Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I open a window on a new thread?

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.

like image 898
mikey555 Avatar asked Jan 22 '12 00:01

mikey555


2 Answers

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

like image 171
shf301 Avatar answered Oct 14 '22 14:10

shf301


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.

like image 27
bwing Avatar answered Oct 14 '22 16:10

bwing