从另一个线程更新标签的最简单方法是什么?
我在thread1上运行了一个Form,然后我开始另一个线程(thread2)。当thread2处理一些文件时,我想用thread2工作的当前状态更新表单上的标签。
我怎么能这样做?
从另一个线程更新标签的最简单方法是什么?
我在thread1上运行了一个Form,然后我开始另一个线程(thread2)。当thread2处理一些文件时,我想用thread2工作的当前状态更新表单上的标签。
我怎么能这样做?
当前回答
例如,访问当前线程以外的控件:
Speed_Threshold = 30;
textOutput.Invoke(new EventHandler(delegate
{
lblThreshold.Text = Speed_Threshold.ToString();
}));
lblThreshold是一个标签,Speed_Threshold则是一个全局变量。
其他回答
还有另一个通用控件扩展。。
首先为Control类型的对象添加扩展方法
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
并从另一个线程调用类似的方法来访问UI线程中名为object1的控件:
object1.InvokeIfRequired(c => { c.Visible = true; });
object1.InvokeIfRequired(c => { c.Text = "ABC"; });
..或类似的
object1.InvokeIfRequired(c =>
{
c.Text = "ABC";
c.Visible = true;
}
);
Label lblText; //initialized elsewhere
void AssignLabel(string text)
{
if (InvokeRequired)
{
BeginInvoke((Action<string>)AssignLabel, text);
return;
}
lblText.Text = text;
}
请注意,BeginInvoke()比Invoke(()更受欢迎,因为它不太可能导致死锁(然而,在这里,将文本分配给标签时,这不是问题):
使用Invoke()时,您正在等待方法返回。现在,可能是您在调用的代码中执行了一些需要等待线程的操作,如果它隐藏在您正在调用的某些函数中,这可能不会立即显现出来,而这本身可能会通过事件处理程序间接发生。因此,您将等待线程,线程将等待您,并且您处于死锁状态。
这实际上导致了我们发布的一些软件挂起。用BeginInvoke()替换Invoke(。除非需要同步操作(如果需要返回值,则可能是这种情况),否则请使用BeginInvoke()。
激发并忘记.NET 3.5的扩展方法+
using System;
using System.Windows.Forms;
public static class ControlExtensions
{
/// <summary>
/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
/// </summary>
/// <param name="control"></param>
/// <param name="code"></param>
public static void UIThread(this Control @this, Action code)
{
if (@this.InvokeRequired)
{
@this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}
这可以使用以下代码行调用:
this.UIThread(() => this.myLabel.Text = "Text Goes Here");
必须使用invoke和delegate
private delegate void MyLabelDelegate();
label1.Invoke( new MyLabelDelegate(){ label1.Text += 1; });
基本上,无论框架版本或GUI底层库类型如何,解决此问题的方法都是保存控件,为工作线程创建线程的同步上下文,从而将控件的相关交互从工作线程编组到GUI的线程消息队列。
例子:
SynchronizationContext ctx = SynchronizationContext.Current; // From control
ctx.Send\Post... // From worker thread