c# - 调用(委托(delegate))

标签 c# winforms delegates invoke

任何人都可以解释写在这个 link 上的声明吗?

Invoke(Delegate):

在拥有控件的底层窗口句柄的线程上执行指定的委托(delegate)。

任何人都可以解释这是什么意思(尤其是粗体)我无法清楚地理解

最佳答案

这个问题的答案在于 C# 控件的工作原理

Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread. This property can be used to determine if you must call an invoke method, which can be useful if you do not know what thread owns a control.

来自 Control.InvokeRequired

实际上,Invoke 所做的是确保您正在调用的代码发生在控件“存在”的线程上,从而有效防止跨线程异常。

从历史的角度来看,在 .Net 1.1 中,这实际上是允许的。这意味着您可以尝试从任何后台线程在“GUI”线程上执行代码,这通常会起作用。有时它只会导致您的应用程序退出,因为您在 GUI 线程执行其他操作时有效地中断了它。这是跨线程异常 - 想象一下在 GUI 正在绘制其他内容时尝试更新 TextBox。

  • 哪个行动优先?
  • 两者是否有可能同时发生?
  • GUI 需要运行的所有其他命令会怎样?

实际上,您正在打断队列,这可能会产生许多无法预料的后果。 Invoke 实际上是将您想要执行的操作放入该队列的“礼貌”方式,并且此规则从 .Net 2.0 开始通过抛出的 InvalidOperationException 强制执行。 .

要了解幕后实际发生的事情,以及“GUI 线程”的含义,了解什么是消息泵或消息循环是很有用的。

这实际上已经在问题“What is a Message Pump”中得到了回答,建议阅读以了解您在与控件交互时所绑定(bind)的实际机制。

您可能会发现有用的其他读物包括:

What's up with Begin Invoke

One of the cardinal rules of Windows GUI programming is that only the thread that created a control can access and/or modify its contents (except for a few documented exceptions). Try doing it from any other thread and you'll get unpredictable behavior ranging from deadlock, to exceptions to a half updated UI. The right way then to update a control from another thread is to post an appropriate message to the application message queue. When the message pump gets around to executing that message, the control will get updated, on the same thread that created it (remember, the message pump runs on the main thread).

并且,对于具有委托(delegate)性示例的更多代码重度概述:

Invalid Cross-thread Operations

// the canonical form (C# consumer)

public delegate void ControlStringConsumer(Control control, string text);  // defines a delegate type

public void SetText(Control control, string text) {
    if (control.InvokeRequired) {
        control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});  // invoking itself
    } else {
        control.Text=text;      // the "functional part", executing only on the main thread
    }
}

一旦您对 InvokeRequired 有所了解,您可能希望考虑使用扩展方法来包装这些调用。 Stack Overflow 问题 Cleaning Up Code Littered with Invoke Required 巧妙地涵盖了这一点.

还有一个write up of what happened historically这可能很有趣。

关于c# - 调用(委托(delegate)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14703698/

相关文章:

方法参数的 c# 自定义属性 - 它是如何工作的?

c# - 在 winform 应用程序的数据 GridView 中添加上下文菜单

c# - 如何在 Application.Run(form1) 执行时隐藏 form1?

ios - 在不相关的 ViewController 之间传递数据

objective-c - 内存管理和异步操作: when does an object become nil?

c# - LINQ没有给出我期望的输出

c# - 如何在 LibGit2Sharp 中执行 git diff --name-status origin/master...HEAD ?

c# winforms - DataGridView 重新加载后保存位置

c# - 全局变量和局部变量澄清

iphone - 如何关闭多个存在的 Modal ViewController 并返回到根 Tab Bar Controller ?