如何用最简单的方式从另一个线程更新Label
?
我有一个在
thread1
上运行的Form
,从那里我启动了另一个线程(thread2
)。当
thread2
处理一些文件时,我想通过Form
将Label
的当前状态更新为thread2
的工作状态。
我该怎么做呢?
如何用最简单的方式从另一个线程更新Label
?
我有一个在thread1
上运行的Form
,从那里我启动了另一个线程(thread2
)。
当thread2
处理一些文件时,我想通过Form
将Label
的当前状态更新为thread2
的工作状态。
我该怎么做呢?
只需要像这样使用:
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = e.ProgressPercentage; // runs on UI thread
});
e.ProgressPercentage
,那么你不是已经在调用此方法的 UI 线程中了吗? - LarsTech我的做法是插入一行递归“口诀”:
对于没有参数的情况:
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 ()
语句后面放置{}会影响代码的可读性,但在这种情况下,这是一个例行公事。如果这种方法在整个项目中都是一致的,它不会破坏代码的可读性。而且这样能够减少代码量(只需要一行代码,而不是五行)。
当你看到if(InvokeRequired) {something long}
时,你知道“这个函数可以安全地从另一个线程中调用”。
您可以使用已经存在的委托 Action
:
private void UpdateMethod()
{
if (InvokeRequired)
{
Invoke(new Action(UpdateMethod));
}
}
又是一个通用的Control扩展方法..
首先,为类型为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);
}
}
在另一个线程中这样调用,以访问名为object1的UI线程控件:
object1.InvokeIfRequired(c => { c.Visible = true; });
object1.InvokeIfRequired(c => { c.Text = "ABC"; });
..or like this
object1.InvokeIfRequired(c =>
{
c.Text = "ABC";
c.Visible = true;
}
);
SynchronizationContext _context;
在创建用户界面的构造函数中设置它:
var _context = SynchronizationContext.Current;
当您想要更新标签时:
_context.Send(status =>{
// UPDATE LABEL
}, null);
尝试使用此方法刷新标签
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
}
你必须使用invoke和delegate。
private delegate void MyLabelDelegate();
label1.Invoke( new MyLabelDelegate(){ label1.Text += 1; });
在WPF应用程序中最简单的方法是:
this.Dispatcher.Invoke((Action)(() =>
{
// This refers to a form in a WPF application
val1 = textBox.Text; // Access the UI
}));
当您在UI线程中时,可以请求其同步上下文任务调度程序。它会给您提供一个TaskScheduler,该调度程序将所有任务都安排在UI线程上。
然后,您可以链式编写您的任务,这样当结果准备好后,另一个任务(在UI线程上安排)会接收它并将其分配给一个标签。
public partial class MyForm : Form
{
private readonly TaskScheduler _uiTaskScheduler;
public MyForm()
{
InitializeComponent();
_uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private void buttonRunAsyncOperation_Click(object sender, EventArgs e)
{
RunAsyncOperation();
}
private void RunAsyncOperation()
{
var task = new Task<string>(LengthyComputation);
task.ContinueWith(antecedent =>
UpdateResultLabel(antecedent.Result), _uiTaskScheduler);
task.Start();
}
private string LengthyComputation()
{
Thread.Sleep(3000);
return "47";
}
private void UpdateResultLabel(string text)
{
labelResult.Text = text;
}
}
这适用于任务(而不是线程),它们现在是编写并发代码的首选方式。
Task.Start
通常不是一个好的实践 http://blogs.msdn.com/b/pfxteam/archive/2012/01/14/10256832.aspx - Ohad Schneider private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(ThreadJob));
t.IsBackground = true;
t.Start();
}
private void ThreadJob()
{
string newValue= "Hi";
Thread.Sleep(2000);
this.Invoke((MethodInvoker)delegate
{
label1.Text = newValue;
});
}