How do I open a window on a new thread?

ぐ巨炮叔叔 提交于 2019-12-20 21:47:12

问题


I have a options window and a window that displays color based on these options and Kinect data. So far everything's on one thread (as far as I know; I haven't done any threading).

Now, I'm adding an option to open a viewer window that will need to be updated with lowest possible latency. All this entails is creating a window and showing it:

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

When this event fires, the color window stops displaying colors (i.e. the event that fires 30 times a second on the main thread stops firing), but the viewer is displayed perfectly. I want the viewer and the color window to both be updated.

From reading other questions, it sounds like the solution is to create the viewer on a new thread. I'm encountering a lot of problems with this, though.

This fires when I click the button to open the viewer:

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();

    }

Regardless of if I just call viewer.Show() or Invoke() it as above, the line throws an exception: Cannot use a DependencyObject that belongs to a different thread than its parent Freezable. Here's how I understand Invoke(): it accesses viewer's dispatcher, which knows what thread the object is running on, and can then call methods from that thread.

Should I be trying to put this viewer on a new thread? Is the problem even a question of threads? The user will not be interacting with the viewer.

Anyone know why this doesn't work? Thanks for the help.


回答1:


You need to call Show() on the same thread that the window is created on - that's why you are getting the error. Then you also need to start a new Dispatcher instance to get the runtime to manage the window.

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();
}

See the Multiple Windows/Multiple Threads example at: http://msdn.microsoft.com/en-us/library/ms741870.aspx




回答2:


So I was running into a similar issue where a new window failed to open on a new thread. The exception was "cannot use a dependencyobject that belongs to a different thread".

The issue ended up being that the window was using a global resource (Background brush). Once I froze the brush resource, the window loaded just fine.




回答3:


I am not sure if this will solve your problem but can you try creating a thread proc (to open a viewer window) which is executed on a different thread and then have a dispatcher.beginInvoke to update the main window ,

Here is some code-

    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
    } 

With this you can update the main window controls without freezing it, Let me know if you have any questions



来源:https://stackoverflow.com/questions/8957969/how-do-i-open-a-window-on-a-new-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!