在后台线程WPF中创建UI?

时间:2011-12-29 11:53:44

标签: c# .net wpf multithreading

我试过以下:

var task = new Task(() =>
    {
       for (int i=0; i<10; i++) {
          //Create new Grid HERE
          // Add Table with some dynamic data here..
          // print the above Grid here.
        }

    });

task.ContinueWith((previousTask) =>
    {
        label.Content = printerStatus(); // will return "Out of Paper", "printing", "Paper jam", etc.
    },
    TaskScheduler.FromCurrentSynchronizationContext());

label.Content = "Sending to printer";

它返回以下错误:调用线程必须是STA,因为许多UI组件都需要这个..

尝试创建新的UI对象Grid时发生错误。

我该如何解决这个问题?如果还有其他任何方式让我知道!

3 个答案:

答案 0 :(得分:2)

任务使用MTA中的线程池线程。

如果你想要一个后台STA线程,你必须自己创建一个并明确设置ApartmentState

Thread t = new Thread( ... );
t.SetApartmentState( ApartmentState.STA );
t.Start();

答案 1 :(得分:1)

使用Dispatcher作为标签和Invoke可能有所帮助:

label.Dispatcher.Invoke(
      System.Windows.Threading.DispatcherPriority.Normal,
      new Action(
        delegate()
        {
          label.Content = printerStatus();
        }
    ));

答案 2 :(得分:1)

您不能在与主UI线程不同的线程上创建UI对象,因为只要将它们添加到UI,它就会尝试设置Parent属性,并且WPF中的线程无法修改已创建的对象在另一个线程上。

相反,我建议在第二个线程上创建Grid的数据列表或集合,并使用像ItemsControl之类的东西将它绑定到UI。这将使所有UI对象保留在主UI线程上,而后台处理可以在后台线程上完成。

要从后台线程(例如您的状态标签)更新UI对象,我建议您使用Dispatcher之类的lawrencealan's answer建议。 Dispatcher是WPF的主UI线程的内部消息队列