从另一个线程更新标签的最简单方法是什么?
我在thread1上运行了一个Form,然后我开始另一个线程(thread2)。当thread2处理一些文件时,我想用thread2工作的当前状态更新表单上的标签。
我怎么能这样做?
从另一个线程更新标签的最简单方法是什么?
我在thread1上运行了一个Form,然后我开始另一个线程(thread2)。当thread2处理一些文件时,我想用thread2工作的当前状态更新表单上的标签。
我怎么能这样做?
当前回答
即使操作很耗时(在我的示例中为thread.sleep)-此代码不会锁定您的UI:
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;
});
}
其他回答
将一些公共变量放在一个单独的类中以保存值。
例子:
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";
}
}
最简单的方法是将匿名方法传递给Label。Invoke:
// Running on the worker thread
string newText = "abc";
form.Label.Invoke((MethodInvoker)delegate {
// Running on the UI thread
form.Label.Text = newText;
});
// Back on the worker thread
请注意,Invoke会阻止执行直到它完成——这是同步代码。这个问题不涉及异步代码,但在StackOverflow上有很多关于在您想了解异步代码时编写异步代码的内容。
例如,访问当前线程以外的控件:
Speed_Threshold = 30;
textOutput.Invoke(new EventHandler(delegate
{
lblThreshold.Text = Speed_Threshold.ToString();
}));
lblThreshold是一个标签,Speed_Threshold则是一个全局变量。
您需要在GUI线程上调用该方法。您可以通过调用Control.Invoke来实现这一点。
例如:
delegate void UpdateLabelDelegate (string message);
void UpdateLabel (string message)
{
if (InvokeRequired)
{
Invoke (new UpdateLabelDelegate (UpdateLabel), message);
return;
}
MyLabelControl.Text = message;
}
这是一个古老问题的新视角,使用了更实用的风格。如果您在所有项目中都保留TaskXM类,那么只有一行代码不再担心跨线程更新。
public class Example
{
/// <summary>
/// No more delegates, background workers, etc. Just one line of code as shown below.
/// Note it is dependent on the Task Extension method shown next.
/// </summary>
public async void Method1()
{
// Still on the GUI thread here if the method was called from the GUI thread
// This code below calls the extension method which spins up a new task and calls back.
await TaskXM.RunCodeAsync(() =>
{
// Running an asynchronous task here
// Cannot update the GUI thread here, but can do lots of work
});
// Can update GUI on this line
}
}
/// <summary>
/// A class containing extension methods for the Task class
/// </summary>
public static class TaskXM
{
/// <summary>
/// RunCodeAsyc is an extension method that encapsulates the Task.run using a callback
/// </summary>
/// <param name="Code">The caller is called back on the new Task (on a different thread)</param>
/// <returns></returns>
public async static Task RunCodeAsync(Action Code)
{
await Task.Run(() =>
{
Code();
});
return;
}
}