如何在新线程上打开窗口?

时间:2012-01-22 00:24:56

标签: c# multithreading invoke

我有一个选项窗口和一个基于这些选项和Kinect数据显示颜色的窗口。到目前为止,一切都在一个线程上(据我所知;我没有做任何线程)。

现在,我正在添加一个选项来打开一个需要以尽可能低的延迟进行更新的查看器窗口。所有这一切都需要创建一个窗口并显示它:

viewer = new SkeletalViewer.MainWindow();
viewer.Show();

当此事件触发时,颜色窗口停止显示颜色(即主线程上每秒触发30次的事件停止触发),但查看器显示完美。我希望更新查看器和颜色窗口。

通过阅读其他问题,听起来解决方案是在新线程上创建查看器。不过,我遇到了很多问题。

单击按钮打开查看器时会激活:

private void launchViewerThread_Click(object sender, RoutedEventArgs e)
    {
        Thread viewerThread = new Thread(delegate()
        {
            viewer = new SkeletalViewer.MainWindow();
            viewer.Dispatcher.Invoke(new Action(delegate() 
                {
                    viewer.Show();
                }));
        });

        viewerThread.SetApartmentState(ApartmentState.STA); // needs to be STA or throws exception
        viewerThread.Start();

    }

无论我是否只是如上所述调用viewer.Show()或Invoke(),该行都会抛出异常:不能使用属于与其父Freezable不同的线程的DependencyObject。以下是我理解Invoke()的方法:它访问查看器的调度程序,该调度程序知道运行该对象的线程,然后可以从该线程调用方法。

我应该尝试将此查看器放在新线程上吗?问题甚至是线程问题吗?用户不会与观看者进行交互。

任何人都知道为什么这不起作用?谢谢你的帮助。

3 个答案:

答案 0 :(得分:17)

您需要在创建窗口的同一个线程上调用Show() - 这就是您收到错误的原因。然后,您还需要启动一个新的Dispatcher实例,以使运行时管理窗口。

private void launchViewerThread_Click(object sender, RoutedEventArgs e)
{
    Thread viewerThread = new Thread(delegate()
    {
        viewer = new SkeletalViewer.MainWindow();
        viewer.Show();
        System.Windows.Threading.Dispatcher.Run();
    });

    viewerThread.SetApartmentState(ApartmentState.STA); // needs to be STA or throws exception
    viewerThread.Start();
}

请参阅:http://msdn.microsoft.com/en-us/library/ms741870.aspx

上的多个Windows /多个线程示例

答案 1 :(得分:1)

所以我遇到了一个类似的问题,一个新窗口无法在新线程上打开。例外是“不能使用属于不同线程的dependencyobject”。

问题最终是窗口正在使用全局资源(背景画笔)。一旦我冻结了画笔资源,窗口加载就好了。

答案 2 :(得分:0)

我不确定这是否会解决您的问题,但您是否可以尝试创建一个线程proc(打开一个查看器窗口),该线程在另一个线程上执行,然后有一个dispatcher.beginInvoke来更新主窗口,

这是一些代码 -

    in the constructor register this
    public MainWindow()
    { 
       UpdateColorDelegate += UpdateColorMethod;
    } 

    // delegate and event to update color on mainwindow 
    public delegate void UpdateColorDelegate(string colorname);
    public event UpdateColorDelegate updateMainWindow;

    // launches a thread to show viewer
    private void launchViewerThread_Click(object sender, RoutedEventArgs e)
    {
        Thread t = new Thread(this.ThreadProc);
        t.Start();
    }

    // thread proc
    public void ThreadProc()
    {
       // code for viewer window
       ...
       // if you want to access any main window elements then just call DispatchToMainThread method
       DispatchToUiThread(color);   
    } 

    // 
    private void DispatchToUiThread(string color)
    {
      if (updateMainWindow != null)
      {
        object[] param = new object[1] { color};
        Dispatcher.BeginInvoke(updateMainWindow, param);
      }
    }

    // update the mainwindow control's from this method
    private void UpdateColorMethod(string colorName)
    {
       // change control or do whatever with main window controls
    } 

使用此功能,您可以更新主窗口控件而不冻结它。如果您有任何疑问,请告诉我