从另一个线程更新标签的最简单方法是什么?
我在thread1上运行了一个Form,然后我开始另一个线程(thread2)。当thread2处理一些文件时,我想用thread2工作的当前状态更新表单上的标签。
我怎么能这样做?
从另一个线程更新标签的最简单方法是什么?
我在thread1上运行了一个Form,然后我开始另一个线程(thread2)。当thread2处理一些文件时,我想用thread2工作的当前状态更新表单上的标签。
我怎么能这样做?
当前回答
创建类变量:
SynchronizationContext _context;
在创建UI的构造函数中设置它:
var _context = SynchronizationContext.Current;
要更新标签时:
_context.Send(status =>{
// UPDATE LABEL
}, null);
其他回答
我的版本是插入一行递归的“咒语”:
对于无参数:
void Aaaaaaa()
{
if (InvokeRequired) { Invoke(new Action(Aaaaaaa)); return; } //1 line of mantra
// Your code!
}
对于具有参数的函数:
void Bbb(int x, string text)
{
if (InvokeRequired) { Invoke(new Action<int, string>(Bbb), new[] { x, text }); return; }
// Your code!
}
就是这样。
一些论证:通常在if()语句后一行放置{}对代码可读性不利。但在这种情况下,这是例行的“咒语”。如果此方法在项目中保持一致,则不会破坏代码的可读性。它还可以避免代码乱丢(一行代码而不是五行代码)。
当您看到(InvokeRequired){some long}时,您只知道“从另一个线程调用此函数是安全的”。
您必须确保更新发生在正确的线程上;UI线程。
为了做到这一点,您必须调用事件处理程序,而不是直接调用它。
您可以通过以下方式发起活动:
(代码是在我的脑海中打出来的,所以我没有检查语法等是否正确,但它应该能让你继续。)
if( MyEvent != null )
{
Delegate[] eventHandlers = MyEvent.GetInvocationList();
foreach( Delegate d in eventHandlers )
{
// Check whether the target of the delegate implements
// ISynchronizeInvoke (Winforms controls do), and see
// if a context-switch is required.
ISynchronizeInvoke target = d.Target as ISynchronizeInvoke;
if( target != null && target.InvokeRequired )
{
target.Invoke (d, ... );
}
else
{
d.DynamicInvoke ( ... );
}
}
}
请注意,上面的代码在WPF项目上不起作用,因为WPF控件不实现ISynchronizeInvoke接口。
为了确保上面的代码适用于Windows窗体和WPF以及所有其他平台,您可以查看AsyncOperation、AsyncOperationManager和SynchronizationContext类。
为了以这种方式轻松地引发事件,我创建了一个扩展方法,它允许我通过调用以下命令来简化引发事件:
MyEvent.Raise(this, EventArgs.Empty);
当然,您也可以使用BackGroundWorker类,它将为您抽象这个问题。
只需使用以下内容:
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = e.ProgressPercentage; // runs on UI thread
});
必须使用invoke和delegate
private delegate void MyLabelDelegate();
label1.Invoke( new MyLabelDelegate(){ label1.Text += 1; });
简单的解决方案是使用Control.Invoke。
void DoSomething()
{
if (InvokeRequired) {
Invoke(new MethodInvoker(updateGUI));
} else {
// Do Something
updateGUI();
}
}
void updateGUI() {
// update gui here
}