任何人都可以请解释这条语句写这篇关于链接
Invoke(Delegate):
在拥有此控件的基础窗口句柄的线程上执行指定的委托。
任何人能解释这是什么意思(尤其是大胆的)我没有能够得到它清楚地
任何人都可以请解释这条语句写这篇关于链接
Invoke(Delegate):
在拥有此控件的基础窗口句柄的线程上执行指定的委托。
任何人能解释这是什么意思(尤其是大胆的)我没有能够得到它清楚地
在这个问题的答案在于如何C#控制工作
在Windows窗体控件绑定到特定线程,而不是线程安全的。 因此,如果从不同的线程调用控件的方法,你必须使用的控件的调用方法之一元帅调用适当的线程。 该属性可用于确定是否必须调用Invoke方法,如果你不知道什么线程拥有控制它可以是有用的。
从Control.InvokeRequired
实际上,调用什么做的是确保你调用的代码中发生的线程上的控制“住在”有效防止交叉螺纹例外。
从历史的角度看,在NET 1.1,这实际上是允许的。 什么意思是,你可以尝试从任何后台线程“GUI”线程中执行代码,这将主要工作。 有时,它会导致您的应用程序退出,因为你得到了有效interupting GUI线程,而这是在做别的事情。 这是十字螺纹例外 -试想一下,而GUI是画别的东西来更新文本框。
实际上,你interupting一个队列,这可以有很多不可预见的后果。 调用是有效地得到自己想要做成队列什么的“客气”的方式,而这种规则是从NET 2.0通过抛出起执行InvalidOperationException异常 。
要了解什么是真正回事幕后,什么是“GUI线程”的意思,它是有用的了解消息泵或消息循环。
这实际上已经回答的问题:“ 什么是消息泵 ”,并推荐阅读理解与控制交互时,你是绑到实际的机制。
其他阅读你可能会发现有用包括:
这是怎么回事首先调用
一个Windows图形用户界面编程的基本规则是,只有创建一个控制线程可以访问和/或修改其内容(除了少数例外记录)。 尝试从其他线程做它,你会得到不可预知的行为,从僵局,以例外半更新UI。 然后更新从另一个线程的控制以正确的方式是张贴适当的消息发送到应用消息队列。 当消息泵都绕来执行该消息时,控制将得到更新,创建它的同一线程(记住,在主线程消息泵运行)上。
并且,对于具有代表性的样品更重的代码概述:
无效的跨线程操作
// 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升值,你不妨考虑使用扩展方法用于包装这些呼叫起来。 这是巧妙地覆盖在堆栈溢出问题清理代码调用所需散落 。
也有进一步的历史了什么事写起来可能会感兴趣。
在Windows窗体控件或窗口对象仅仅是围绕由句柄标识一个Win32窗口的包装(有时称为HWND)。 你与控制办最多的事,最终会导致使用该手柄上的Win32 API调用。 手柄是由创建它的线程(通常是主线程)所拥有,并且不应该被另一个线程操作。 如果由于某种原因,你需要做的事情从另一个线程控制,您可以使用Invoke
来要求主线程做您的名义。
举例来说,如果你想要一个标签的文本从一个工作线程改变,你可以这样做:
theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));
如果你想修改的控制,必须在其控制的创建线程来完成。 这个Invoke
方法允许你在执行相关线程(拥有控件的基础窗口句柄的线程)的方法。
在下面的示例线程1抛出一个异常,因为SetText1试图从另一个线程修改textBox1.Text。 但在线程2,在SetText2行动在该文本框被创建的线程中执行
private void btn_Click(object sender, EvenetArgs e)
{
var thread1 = new Thread(SetText1);
var thread2 = new Thread(SetText2);
thread1.Start();
thread2.Start();
}
private void SetText1()
{
textBox1.Text = "Test";
}
private void SetText2()
{
textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });
实际上这意味着委托保证在主线程上被调用。 因为在窗口控制的情况下,如果你不主线程上更新它们的属性,则说明您没有看到改变这一点很重要,或者控制将引发异常。
该模式是:
void OnEvent(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(() => this.OnEvent(sender, e);
return;
}
// do stuff (now you know you are on the main thread)
}
this.Invoke(delegate)
请确保您呼叫的委托参数this.Invoke()
在主线程/创建的线程。
我可以说一个经验法则,不要访问,除了从主线程你的表单控件。
可能是以下行有意义使用的invoke()
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
还有虽然你创建一个线程池线程(即工作线程),它会在主线程上运行的情况。 怎么把主线程可以处理更多的指令它不会创建一个新线程。 因此,首先调查是否当前正在运行的线程主线程使用this.InvokeRequired
如果返回true当前的代码是在工作线程运行,所以调用this.Invoke(d,新的对象[] {文本});
否则直接更新UI控件(这里你保证你正在运行在主线程的代码。)
这意味着代表将在UI线程上运行,即使你调用从后台工作或线程池线程的方法。 UI元素有线程关联 -他们只喜欢直接交流,以一个线程:UI线程。 UI线程被定义为所创建的控制实例的线程,并因此与窗口句柄相关联。 但所有这一切是一个实现细节。
关键的一点是:你会从一个工作线程调用此方法,这样就可以访问UI(更改标签值等) -因为你不能做任何其他线程比UI线程。
代表基本上是内联Action
的或Func<T>
可以声明所运行或使用的方法的范围以外的代表lambda
表达式( =>
); 因为你的方法中运行的委托,就其正在运行当前窗口/应用程序,它是位大胆的线程上运行它。
例如LAMBDA
int AddFiveToNumber(int number)
{
var d = (int i => i + 5);
d.Invoke(number);
}
这意味着你通过委托创建该控制对象(其是UI线程)在线程上执行。
您需要在您的应用程序是多线程调用这个方法,你想从非UI线程的线程上做一些UI操作,因为如果你只是尝试从不同的线程调用一个控制的方法,你会得到一个System.InvalidOperationException。