Ultratrunks
Ultratrunks

Reputation: 2574

Trouble accessing GUI components from another thread. Dispatcher still throwing exception

I have a window that is subscribing to an event that is raised by an object. I'm subscribing to the event as follows:

m_Monitor.NewJob += new Monitor.NewJobEvent(NewJobEventHandler);

The event is being raised successfully and is calling my NewJobEventHandler just fine. The problem occurs when I try to make changes to any UI elements in the window. I get the follow exception:

System.Reflection.TargetInvocationException: {"The calling thread cannot access this object because a different thread owns it."}

I've had this issue before and I've used some "Dispatcher" with some "Action" to get around it. I'll admit that whole thing seem like magic to me and I really didn't understand it, but it did get me past the issue. Coming from a C++ background I'm a bit miffed that I can't access certain things because they are in different threads. But anyways, my NewJobEventHandler() routine is as follows:

private void NewJobEventHandler(JobInfo newJob)
{
    TreeViewItem tvItem = new TreeViewItem();
    tvItem.Header = "Job: " + newJob.ToString();

    //The following call is what causes the exception, yet I've used very
    //similar code to update the .Text property of a TextBox from another
    //thread
    OutputDataTree.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                (Action)(() => { OutputDataTree.Items.Add(tvItem); }));
}

Anyone know why this doesn't work for me?

Upvotes: 0

Views: 517

Answers (1)

Femaref
Femaref

Reputation: 61467

You are creating the TreeViewItem in the worker thread, but use it in the UI thread. You'll have to create it in the Action.

private void NewJobEventHandler(JobInfo newJob)
{
    TreeViewItem tvItem = new TreeViewItem();
    string header = "Job: " + newJob.ToString();

    //The following call is what causes the exception, yet I've used very
    //similar code to update the .Text property of a TextBox from another
    //thread
    OutputDataTree.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                (Action)(() => { 
                                  TreeViewItem tvItem = new TreeViewItem();
                                  tvItem.Header = header;
                                  OutputDataTree.Items.Add(tvItem); 
                               }));
}

This is of concern for any UI element you create, they need to be created in the UI thread to be useable.

Upvotes: 2

Related Questions