如何用最简单的方式从另一个线程更新Label
?
我有一个在
thread1
上运行的Form
,从那里我启动了另一个线程(thread2
)。当
thread2
处理一些文件时,我想通过Form
将Label
的当前状态更新为thread2
的工作状态。
我该怎么做呢?
如何用最简单的方式从另一个线程更新Label
?
我有一个在thread1
上运行的Form
,从那里我启动了另一个线程(thread2
)。
当thread2
处理一些文件时,我想通过Form
将Label
的当前状态更新为thread2
的工作状态。
我该怎么做呢?
首先获取您的表单实例(在本例中为 mainForm),然后在另一个线程中使用以下代码。
mainForm.Invoke(new MethodInvoker(delegate ()
{
// Update things in my mainForm here
mainForm.UpdateView();
}));
将一些常用变量放在一个单独的类中来保存它们的值。
例如:
public class data_holder_for_controls
{
// It will hold the value for your label
public string status = string.Empty;
}
class Demo
{
public static data_holder_for_controls d1 = new data_holder_for_controls();
static void Main(string[] args)
{
ThreadStart ts = new ThreadStart(perform_logic);
Thread t1 = new Thread(ts);
t1.Start();
t1.Join();
//your_label.Text=d1.status; --- can access it from any thread
}
public static void perform_logic()
{
// Put some code here in this function
for (int i = 0; i < 10; i++)
{
// Statements here
}
// Set the result in the status variable
d1.status = "Task done";
}
}
一般的做法如下:
using System;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
int clickCount = 0;
public Form1()
{
InitializeComponent();
label1.SetText("0");
}
private void button1_Click(object sender, EventArgs e)
{
new Thread(() => label1.SetText((++clickCount).ToString())).Start();
}
}
public static class ControlExtensions
{
public static void SetText(this Control control, string text)
{
if (control.InvokeRequired)
control.Invoke(setText, control, text);
else
control.Text = text;
}
private static readonly Action<Control, string> setText =
(control, text) => control.Text = text;
}
}
说明:
这个答案与这个非常相似,但使用了更整洁(在我看来)和更新的语法。关键在于control
的InvokeRequired
属性。它获取一个值,指示调用方在对控件进行方法调用时是否必须调用Invoke方法,因为调用方位于与创建控件的线程不同的线程上。所以如果我们在创建control
的相同线程上调用control.SetText("some text")
,只需将Text
设置为control.Text = text
即可。但在任何其他线程上,它都会导致System.InvalidOperationException
,因此必须通过control.Invoke(...)
调用方法,在创建control
的线程上设置Text
。
private void UpdateNowProcessing(string nowProcessing)
{
if (this.InvokeRequired)
{
Action<string> d = UpdateNowProcessing;
Invoke(d, nowProcessing);
}
else
{
this.progressDialog.Next(nowProcessing);
}
}
private void updateUI()
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(updateUI);
return;
}
// Update any number of controls here
}
Application.Current.Dispatcher.Invoke(new Action(() =>
{
try
{
///
}
catch (Exception)
{
//
}
}
));
new Thread(() =>
{
while (...)
{
SomeLabel.Dispatcher.BeginInvoke((Action)(() => SomeLabel.Text = ...));
}
}).Start();