我正在使用.NET C#并尝试加载包含三个选项卡的UserControl。我想要做的是,加载第一个Tab使其可见并响应,然后在后台线程(或工作人员或任务)中加载其他两个选项卡。
我尝试使用线程,任务,后台工作者但是总是有相同的异常“调用线程无法访问此对象,因为不同的线程拥有它。”
这里我使用了一些代码示例:
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync();
在bw_DoWork中我把我需要做的所有工作都涉及到UI更新
Task t1 = new Task(DoWork);
t1.Start();
在DoWork中我也这样做(一些代码使用UI更新)
感谢您的帮助。
Oussema
答案 0 :(得分:2)
这不是不可能的,但这是一个坏主意 - 要做到正确是非常棘手的。
相反,您希望将业务逻辑与UI分离,以便您可以在后台执行逻辑,而UI仍在UI线程上。关键是你不能从后台线程修改UI控件 - 而是首先加载你需要的任何数据,然后使用Invoke
或ReportProgress
将它封送回UI线程,您可以在哪里更新UI。
如果创建控件本身花费的时间太长,您可能需要查看一些选项以提高其性能。例如,使用BeginUpdate
和朋友避免不必要的重绘和布局,同时您仍然填写数据,或按需创建控件(因为它们即将可见),而不是全部预先。
使用await
的一个简单示例(使用Windows窗体,但基本思想无处不在):
tabSlow.Enabled = false;
try
{
var data = await Database.LoadDataAsync();
dataGrid.DataSource = data;
}
finally
{
tabSlow.Enabled = true;
}
数据库操作在后台完成,完成后,UI更新将在UI线程上执行。如果您需要进行一些昂贵的计算,而不是I / O,那么您只需使用await Task.Run(...)
- 只需确保任务本身不会更新任何UI;它应该只返回更新UI所需的数据。
答案 1 :(得分:0)
WPF不允许您从后台线程更改UI。只有ONE SINGLE线程可以处理UI线程。相反,您应该在后台线程中计算数据,然后调用Application.Current.Dispatcher.Invoke(...)
方法来更新UI。例如:
Application.Current.Dispatcher.Invoke(() => textBoxTab2.Text = "changing UI from the background thread");