C# 如何打开新线程的窗口?

C# 如何打开新线程的窗口?,c#,multithreading,invoke,C#,Multithreading,Invoke,我有一个选项窗口和一个基于这些选项和Kinect数据显示颜色的窗口。到目前为止,所有的东西都在一个线程上(据我所知,我没有做任何线程) 现在,我添加了一个选项来打开需要以尽可能低的延迟更新的查看器窗口。所有这些都需要创建一个窗口并显示它: viewer = new SkeletalViewer.MainWindow(); viewer.Show(); 当触发此事件时,颜色窗口将停止显示颜色(即,每秒在主线程上触发30次的事件将停止触发),但查看器将完美显示。我希望查看器和颜色窗口都被更新 从阅

我有一个选项窗口和一个基于这些选项和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(),该行都会抛出一个异常:不能使用一个DependencyObject,它属于与其父Freezable不同的线程。以下是我对Invoke()的理解:它访问viewer的dispatcher,后者知道对象在哪个线程上运行,然后可以从该线程调用方法

我应该尝试将此查看器放到新线程上吗?这个问题甚至是线程的问题吗?用户将不会与查看器交互


有人知道为什么这样不行吗?谢谢您的帮助。

我不确定这是否能解决您的问题,但您能否尝试创建一个线程进程(打开查看器窗口),该进程在不同的线程上执行,然后让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
    } 

使用此功能,您可以更新主窗口控件而无需冻结它,如果您有任何问题,请告诉我您需要在创建窗口的同一线程上调用
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();
}

请参阅位于的多窗口/多线程示例:

因此,我遇到了一个类似的问题,即在新线程上无法打开新窗口。例外情况是“无法使用属于其他线程的dependencyobject”


问题是窗口使用了全局资源(背景笔刷)。一旦我冻结了画笔资源,窗口就可以正常加载。

谢谢。为什么要将颜色分配到UI线程?UI线程(默认线程)上没有调用任何被调用的方法吗?因为从主UI线程派生的后台线程无法更新在UI线程上创建的任何控件的内容。为了让后台线程访问主窗口上的控件,后台线程必须将工作委托给与UI线程关联的调度程序。这是通过使用Invoke或BeginInvoke来实现的。Invoke是同步的,BeginInvoke是异步的。该操作以指定的DispatcherPriority添加到Dispatcher的事件队列中。请参阅此链接-我将调用视为保证在查看器的线程上调用Show()。即使在viewer.Show()周围没有Invoke(),我仍然会得到Freezable异常。@michael.greenwald然后在
SkeletalViewer.MainWindow()
中有一些东西导致了异常。我构建了一个空的WPF项目,它完全按照我上面展示的那样运行,并且毫无例外。可能您的问题与此问题中的问题类似:
System.Windows.Threading
存在于
WindowsBase.dll
中,您必须添加到引用中。