从单独的线程创建 WPF 控件
本文关键字:WPF 控件 创建 线程 单独 | 更新日期: 2023-09-27 18:35:28
我有一个异步运行的Task
,当它像这样完成时会触发一个事件:
task.ContinueWith(() => {
if (MyEvent != null)
MyEvent(this, EventArgs.Empty);
}
然后,事件处理程序应创建 WPF 控件的实例。但是当我尝试这样做时,它会导致异常:The calling thread must be STA, because many UI components require this
.调用方法 InitializeComponent()
时,类构造函数中发生异常。
据我所知,通常从单独的线程访问 WPF 控件是使用 Dispatcher.Invoke
来处理的,它总是对我有用,所以我尝试了一下:
Dispatcher.Invoke(new Action(() =>
{
InitializeComponent();
}));
但在这种情况下,异常不断发生。如何从单独的线程创建 WPF 控件的实例?
或者,也许将完成事件封送到主 UI 线程会是更好的方法。如果是,我该怎么做?
您必须使用与 UI 线程关联的调度程序实例。如果你正在写这样的东西:
Dispatcher.Invoke(new Action(() =>
{
InitializeComponent();
}));
在任务正文中,你使用的是调用线程的调度程序,该调度程序可以是池中的后台线程。
无论如何,对于任务,您不应该直接使用调度程序。使用适当的任务计划程序:
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
// Put you UI calls here
}, CancellationToken.None, TaskContinuationOptions.None, ui);
其中tasks
是使用默认调度程序执行的一系列任务。
从另一个线程上的构造函数调用 InitializeComponent似乎在找麻烦。对象还不存在(我们在构造函数中)
将其封送回 UI 线程通常会解决问题,但在构造函数期间对我来说似乎是一个坏主意。
如果要异步初始化控件,只需订阅加载的事件,以便知道对象在那里,请生成一个线程,该线程执行一些计算/数据检索,并将数据封送回 UI 线程以显示它。
我过去做过这个:
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(
delegate()
{
// Access control created by main thread
textBlock.Text = msg;
}
));