我在下面的应用程序中使用线程有一个问题是两个简单的方法,这两个方法在按钮点击时被调用。
我希望首先运行插入方法并在第二次方法运行5秒后线程休眠5秒,并根据编码显示
但我面对这个错误:
跨线程操作无效:控制'lblDisplay'从其创建的线程以外的线程访问。
以下是代码:
private void button1_Click(object sender, EventArgs e)
{
Thread obj = new Thread(new ThreadStart(inserting));
Thread obj1 = new Thread(new ThreadStart(insert));
obj.Start();
obj1.Start();
}
public void inserting()
{
lblDisplay.Text = "inserting record......";
Thread.Sleep(5000);
}
public void insert()
{
lblDisplay.Text = "Record successfully inserted";
}
答案 0 :(得分:2)
您只能在创建控件的同一个线程上修改控件。使用Control.Invoke修改您的控件:
lblDisplay.Invoke(() =>
{
lblDisplay.Text = "inserting record......";
});
答案 1 :(得分:1)
您收到错误是因为您无法访问主UI线程(或WPF中的Dispatcher线程)以外的线程上的UI元素。如果您希望拥有一些状态更新系统,最好让一个进程在一个单独的线程上运行,然后回调到主UI线程以更新状态文本。例如:
public void button1_Click(object sender, EventArgs e)
{
var thread = new Thread(new ThreadStart(Execute));
thread.Start();
}
private void Execute()
{
UpdateStatus("Starting execution...");
// ... Run some code ...
UpdateStatus("Inserting record...");
// Sleep for 5 seconds
Thread.Sleep(5000);
// ... Run record insertion code ...
UpdateStatus("Record successfully inserted");
}
private void UpdateStatus(string status)
{
// Make sure we're running on the UI thread
if (this.InvokeRequired)
{
BeginInvoke(new Action<string>(UpdateStatus), status);
return;
}
// Update the display text now we are running on the UI thread
lblDisplay.Text = status;
}
注意:这是WinForms特有的答案。对于WPF,您使用CheckAccess()
代替InvokeRequired
和this.Dispatcher.BeginInvoke(...)
代替BeginInvoke(...)
。
答案 2 :(得分:0)
lblDisplay
是在另一个线程上创建的,因此您需要一个委托来更改该值。请查看MSDN,并举例说明该怎么做。
答案 3 :(得分:0)
我也遇到了这个问题。我发布了解决方案here。
这是因为您试图通过未创建Control的线程来修改UI控件。
像这样创建一个扩展
public static class ControlExtensions
{
public static void Invoke(this Control control, Action action)
{
if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null);
else action.Invoke();
}
}
然后执行此操作
lblDisplay.Invoke(() => { lblDisplay.Text = "Record successfully inserted"; });
希望这会对你有所帮助。