1
votes

As per our requirement we have to open a WPF window in a new UI thread.

We are opening the window in a new UI thread from the main UI Thread using following code:

Thread winthread = new Thread(new ThreadStart(() =>
{
    SynchronizationContext.SetSynchronizationContext(
        new DispatcherSynchronizationContext(
            Dispatcher.CurrentDispatcher));
    Window windowObj = new Window();
    Grid gridObj = new Grid();
    MyUserControl ctrl = new MyUserControl();
    gridObj.Children.Add(ctrl);
    windowObj.Content = gridObj;

    windowObj.Show();
    System.Windows.Threading.Dispatcher.Run();
}));

winthread.IsBackground = true;
winthread.SetApartmentState(ApartmentState.STA);
winthread.Start();

The window will show with MyUserControl as content when the above code executes. I am doing some animation like flipping my usercontrol on the mouse double click event.

When I double clicked on it the application starts throwing following exception:

The calling thread cannot access this object because a different thread owns it.

on line System.Windows.Threading.Dispatcher.Run().

Can anyone suggest the solution for this problem?

2
Sorry to be pedantic, but it's because the thread can't access the object, because a different thread owns it. Which bit don't you understand fully and maybe we can help? - Kieren Johnstone
@ Kieren Johnstone :- To make it more clear, my animation should work perfectly logically because it is running on the same thread on which the window is created, it should not throw any exception. - Bhaskar Soni
Your code looks ok - this runs fine for me (replacing MyUserControl with just a Button). Can you show the code for MyUserControl? Can you show how you are calling this code? From an existing WPF application? Console application? - J...
@J... Sorry, I cant share my full code for MyUserControl because its really huge and spread across multiple classes, but i can give u a brief about its functionality. It contains one label which is updating continusly by real time data. When we flipped our user control I am creating the graph cooresponding to the that specific usercontrol,then it will starts plotting the real time data on the graph - Bhaskar Soni

2 Answers

1
votes

Your code above is fine. Whatever the issue is, it is something inside MyUserControl - there must be shared elements in those classes or references to objects owned by the main thread. You must make certain that nothing inside MyUserControl has been created on or is owned by the main thread, including objects passed as arguments, etc.

Alternatively, you may be trying to use the main thread to interact with (or with components inside) MyUserControl. If you want to perform any actions on ctrl from an outside thread (ie: the main thread, etc) you have to keep a reference to ctrl and use invoke - something like this:

public partial class MainWindow : Window
{
    UserControl1 ctrl;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        Thread winthread = new Thread(new ThreadStart(() =>
        {
            SynchronizationContext.SetSynchronizationContext(
                new DispatcherSynchronizationContext(
                    Dispatcher.CurrentDispatcher));
            Window windowObj = new Window();
            Grid gridObj = new Grid();
            ctrl = new UserControl1();
            gridObj.Children.Add(ctrl);
            windowObj.Content = gridObj;

            windowObj.Show();
            System.Windows.Threading.Dispatcher.Run();
        }));

        winthread.IsBackground = true;
        winthread.SetApartmentState(ApartmentState.STA);
        winthread.Start();
    }

    private void button2_Click(object sender, RoutedEventArgs e)
    {
        ctrl.Dispatcher.Invoke(new Action(() => ctrl.AddStuff()));
    }
}

Here I've made UserControl1 a simple window with a listbox:

public partial class UserControl1 : UserControl
{
    private int i;

    public UserControl1()
    {
        InitializeComponent();
    }

    public void AddStuff()
    {
        listBox1.Items.Add("This is line : " + i.ToString());
        i += 1;
    }
}

In the above case you have to make sure that the main thread uses invoke - specifically that it looks to ctrl's Dispatcher to handle the invoke. Rather than use its own dispatcher (which causes the cross-thread error) the main thread marshalls the call to ctrl's dispatcher.

It would help if you could at least show the line of code inside MyUserControl where you are getting the exception.

-1
votes

Sounds like an Invoke issue :

Fairly easy to solve, as your attempting to change the Grid/window in a different thread.

Change the Thread to Invoke a change

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/360540eb-d756-4434-86f9-a3449f05eb55