从单独的线程创建WPF控件

时间:2012-05-25 05:24:13

标签: c# wpf multithreading

我有一个异步运行的Task,当事件像这样完成时会触发事件:

task.ContinueWith(() => {
    if (MyEvent != null)
        MyEvent(this, EventArgs.Empty);
}

然后,事件处理程序应该创建WPF控件的实例。但是当我尝试这样做时,它会导致异常:The calling thread must be STA, because many UI components require this。调用方法InitializeComponent()时,类构造函数中会发生异常。

据我所知,通常使用Dispatcher.Invoke来处理来自不同线程的WPF控件,它总是对我有用,所以我试了一下:

Dispatcher.Invoke(new Action(() =>
{
    InitializeComponent();
}));

但在这种情况下,异常不断发生。如何从单独的线程创建WPF控件的实例?

或许这可能是将完成事件编组到主UI线程的更好方法。如果是,我该怎么做?

3 个答案:

答案 0 :(得分:3)

您必须使用与UI线程关联的Dispatcher实例。如果你写的是这样的话:

Dispatcher.Invoke(new Action(() =>
{
    InitializeComponent();
}));

在任务正文中,您正在使用调用线程的调度程序,该调度程序可以是池中的后台线程。

无论如何,对于任务,您不应直接使用Dispatcher。使用适当的任务计划程序:

var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.ContinueWhenAll(tasks.ToArray(),
    result =>
    {
        // Put you UI calls here

    }, CancellationToken.None, TaskContinuationOptions.None, ui);

其中tasks是使用默认调度程序执行的一系列任务。

答案 1 :(得分:1)

我过去做过这个:

 Dispatcher.Invoke(DispatcherPriority.Normal,
                   new Action(
                        delegate()
                        {
                            // Access control created by main thread
                            textBlock.Text = msg;
                        }
                   ));

答案 2 :(得分:1)

从另一个线程上的构造函数调用InitializeComponent似乎在寻找麻烦。那个对象还没有(我们在构造函数中)

将它编组回UI线程通常可以解决问题,但在构造函数中看起来对我来说是一个坏主意。

如果要异步初始化控件,只需订阅已加载的事件,因此您知道对象在那里,生成一个执行某些计算/数据检索的线程,并将数据编组回UI线程以显示它。 / p>