Bhaskar Soni
Bhaskar Soni

Reputation: 11

The calling thread cannot access this object because a different thread owns it when using animation in wpf window

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?

Upvotes: 1

Views: 1627

Answers (2)

J...
J...

Reputation: 31403

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.

Upvotes: 1

Riaan Walters
Riaan Walters

Reputation: 2676

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

Upvotes: -1

Related Questions