WPF Threading Problem

The calling thread cannot access this object because...

Page 1 of 1

11 Replies - 8381 Views - Last Post: 10 September 2010 - 10:12 AM Rate Topic: -----

#1 Guest_Jason*


Reputation:

WPF Threading Problem

Posted 05 September 2010 - 10:36 AM

Hello everybody,

I was working one my recent WPF project today. I used multithreading in the project and recieved this error: The calling thread cannot access this object because a different thread owns it." This was happening because I was trying to change the properties of various UI elements from one of these threads I had created.

So, I researched the issue and read about the STAThread attribute and the consequences of derivation from DispatcherObject and how WPF application have two default threads; one dealing with UI elements and one with rendering. However, although it is apparently advisable to find other ways (other than multithreading) of implementing solutions in WPF, I wanted to find out how to work around this issue and avoid the above error.

I found a few things about delegates and using the Invoke() method and such, but nothing made any real sense. Therefore, I have made a basic mock up of the situation and I was hoping that someone could just outline,explain and help me to understand exactly how to eliminate the above error from the code, in addition to why the solution actually works. Here is the simple mock up:

Window1 Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private Class1 c;

        public Window1()
        {
            InitializeComponent();
            c = new Class1(this);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            c.func1();
        }

    }
}




Class in which new thread is created

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace WpfApplication1
{
    class Class1
    {
        private Window1 window;
        private Thread thread;

        public Class1(Window1 window)
        {
            this.window = window;
        }

        public void func1()
        {

            
            try
            {
                thread = new Thread(new ThreadStart(func2));
                thread.Start(); //I obviously get the error here as I start the func2 method in the new thread and try to change the button content from the new thread
            }
            catch (Exception e)
            {

                System.Windows.MessageBox.Show(e.Message); 

            }

        }

        public void func2()
        {


            window.button1.Content = "Hello"; //this is a button on the Window WPF Application


        }
    }
}





Any help and guidance with this issue would be greatly appreciated.

Thanks you very much for you time.

Is This A Good Question/Topic? 0

Replies To: WPF Threading Problem

#2 Guest_Jason*


Reputation:

Re: WPF Threading Problem

Posted 05 September 2010 - 10:59 AM

SI apologise for posting in the wrong section...I forgot about the WPF section :oops:
Was This Post Helpful? 0

#3 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6107
  • View blog
  • Posts: 23,661
  • Joined: 23-August 08

Re: WPF Threading Problem

Posted 05 September 2010 - 11:01 AM

Don't sweat it :)
Was This Post Helpful? 0
  • +
  • -

#4 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1526
  • View blog
  • Posts: 5,961
  • Joined: 21-March 08

Re: WPF Threading Problem

Posted 07 September 2010 - 04:40 AM

We have a number of snippets and tutorials on writing to the UI from a different thread.
Was This Post Helpful? 0
  • +
  • -

#5 Guest_Jason*


Reputation:

Re: WPF Threading Problem

Posted 08 September 2010 - 01:02 PM

Thanks for the reply. Isn't the threading model for windows forms different than it is for WPF. Is it basically the same concept though? Although, I am still finding it hard to get my head around. I would really appreciate it if somebody could perhaps add to the code above to show me the idea working in my precise situation.

This won't be doing the work for me as the above code isn't from my project. It's just something to demonstrate roughly what is happening in my project in order to simplify, for you guys (in the sense of, so you don't have to to trawl through hundreds of lines of novice code finding the appropriate lines.), what I require.

I would really appreciate if someone could just add a few lines, or tell me what to add to get it working. I can then review the situation in the context of an extremely basic example, that I have made, to custom fit my circumstances. This, I believe, will help me pull all the ideas I have read about in tutorials together and finally make sense of the concept, and consequently incorperate it into my actual project correctly. (Note...the project isn't homework or any equivalent; it's just my personal project for fun/independant learning)...
Was This Post Helpful? 0

#6 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1526
  • View blog
  • Posts: 5,961
  • Joined: 21-March 08

Re: WPF Threading Problem

Posted 08 September 2010 - 01:37 PM

The concept is still the same. Also, you can use the BackgroundWorker in both WinForms and WPF. It's probably the easiest way of doing threading.

We have a tutorial on using the BackgroundWorker.
Was This Post Helpful? 0
  • +
  • -

#7 Guest_Jason*


Reputation:

Re: WPF Threading Problem

Posted 08 September 2010 - 02:00 PM

Thank you again. I shall look at the tutorial in more detail tomorrow when I am a bit more awake! I'll then post back with the updated situation. Hopefully the background worker class will finally drill home this concept. Thanks!
Was This Post Helpful? 0

#8 ragingben  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 175
  • View blog
  • Posts: 641
  • Joined: 07-October 08

Re: WPF Threading Problem

Posted 09 September 2010 - 03:21 AM

Also just a quick note, as all UI elements (TextBoxes, Buttons, Labels etc) are owned by the thread that they were created on, you cannot edit them from another thread.

So the background worker can do the work, but it will not be able to update any UI values.

However you can use the .Dispatcher property on your window or control to update a value safely from a background thread. I find using this with lambda expressions is for me the quickest and simplist way of updating a value.

For example, you need to create a public delegate that you will use to update the values, I've done it just outside my main window class...
namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    }

    /// <summary>
    /// Deletage used for updating values
    /// </summary>
    public delegate void UpdaterDelegate();
}


...and then you can simply use the objects dispatcher to call a delegate that will update the object, using a parameterless lambda expression containing the update code. That sentance sounds more complicated than it actually is :)
// call this from wherever you want to update the values from on a non UI thread. In this example "this" is Window1...

// to update one line of code, for example change the background of the window
this.Dispatcher.BeginInvoke(new UpdaterDelegate(() => this.Background = Brushes.Red));

// or you can update multiple lines in a block of code
this.Dispatcher.BeginInvoke(new UpdaterDelegate(() =>
{
    // update background
    this.Background = Brushes.Red;

    // change title
    this.Title = "Hello";
}));


To see what I mean just create a new WPF app, and paste this over the Window1 code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        // the worker for this example
        BackgroundWorker worker;

        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // create worker
            this.worker = new BackgroundWorker();

            // subscribe to do work event - this is called when the worker runs...
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);

            // now run
            worker.RunWorkerAsync();
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            // wait a sec so we can see change... notice that we can call this and the UI remains responsive, only the worker is sleeping not the UI thread
            Thread.Sleep(1000);

            // to update one line of code, for example change the background of the window
            this.Dispatcher.BeginInvoke(new UpdaterDelegate(() => this.Background = Brushes.Red));

            // wait again
            Thread.Sleep(1000);

            // or you can update multiple lines in a block of code
            this.Dispatcher.BeginInvoke(new UpdaterDelegate(() =>
            {
                // update background
                this.Background = Brushes.Yellow;

                // change title
                this.Title = "Updating on UI...";
            }));

            // wait again
            Thread.Sleep(1000);

            // or you can update multiple lines in a block of code
            this.Dispatcher.BeginInvoke(new UpdaterDelegate(() =>
            {
                // update background
                this.Background = Brushes.Blue;

                // change title
                this.Title = "Hope that helped :)/>";
            }));
        }
    }

    /// <summary>
    /// Deletage used for updating values
    /// </summary>
    public delegate void UpdaterDelegate();
}


Hope that helps :)

This post has been edited by ragingben: 09 September 2010 - 03:23 AM

Was This Post Helpful? 0
  • +
  • -

#9 Guest_Jason*


Reputation:

Re: WPF Threading Problem

Posted 09 September 2010 - 11:03 AM

Thank you so much! I now understand the issue much better. It works brilliantly in my project too. Why exactly does using a delegate (like in your first example in particular) work?
Was This Post Helpful? 0

#10 Guest_Jason*


Reputation:

Re: WPF Threading Problem

Posted 09 September 2010 - 11:17 AM

Also, am I correct in saying that you have to use a delegate to call a method in the main window class from a separate thread? Thanks again.
Was This Post Helpful? 0

#11 ragingben  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 175
  • View blog
  • Posts: 641
  • Joined: 07-October 08

Re: WPF Threading Problem

Posted 10 September 2010 - 03:53 AM

Well, Im no expert, but this is basically whats going on as far as I understand:

All WPF FrameworkElements, which all visual controls etc are derieved from inherit directly from DispatcherObject. DispatcherObject has a Dispatcher property which is the pump for all viusal updates and rendering of UI elements, and also controls which order certain tasks are carried out in, which can be specified by a DispatcherPriority.

Just google any of these classes and there are loads of descriptions of whats going on with them, and how they work. Because all controls and all windows derieve from DispatcherObject in WPF, they all have a Dispatcher property.

What is actually happening when you call Dispatcher.BeginInvoke() on your window, is you are passing the Dispatcher a task to do (the delegate), which it inserts into it's pending queue, and carries out when it's turn comes around (determined by the tasks DispatcherPriority, which you can explicitly specify as a parameter to the Dispatcher.BeginInvoke() method). So by using a delegate, you are saying "Carry out all these operations", the same as when you subscribe to events like MouseDown, Click etc. Because the dispatcher is now carrying out the operations, and the dispatcher is owned by the window, they are carried out on the UI thread. Remember that the UI thread controls all the rendering and user interaction, so the more code you pass the dispatcher to do, the less responsive the window will become. Go ahead and try it - in one of lambda blocks in the sample I posted put a...
for(Int32 index = 0; index < 10000000; index++)
{
    // just keeping the processor busy...
}


...and watch your UI grind to a halt. Always be a bit careful of this. By using the lambda approach that I posted you are basically just using a delegate to contain a block of code for the dispatcher to carry out. But this could be also method, and you could just use a delegate to call that method, which is useful if the code you want to execute is used elsewhere in the program.

Threading is C#/WPF takes a bit of time to get your head around - it is a complicated topic, but once you do it will all swing into focus and be pretty clear why things are the way they are. It would get pretty messy if different threads could update the same UI element...

I hope this helps, don't take any of it as gospel because it is just my understanding of how it works and it may not be 100% correct, but it's how I think of it :) There's a heap of info on google about threading in C#, most of it much clearer than what I've just tapped out!
Was This Post Helpful? 0
  • +
  • -

#12 Guest_Jason*


Reputation:

Re: WPF Threading Problem

Posted 10 September 2010 - 10:12 AM

Thanks you very much. I really appreciate the detailed replies you've given. They have helped hugely! Thanks for taking so much of your time to help me.
Was This Post Helpful? 0

Page 1 of 1