0

I'm getting an error when running this code:

tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { tabControl1.Items.Add(tbItem); }));   

the tabcontrol1 is hard coded into the xaml and the tab item/s are built at runtime. I'm getting an error:

TargetInvocationException was unhandled Exception has been thrown by the target of an invocation.

I'd love to hear any thoughts on this. Thanks

UPDATE

the inner exception:

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

the full method code:

TabItem tbItem = new TabItem();
                tbItem.Header = worker;       

                Grid grid = new Grid();

                ListBox listBox = new ListBox();
                listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
                listBox.VerticalAlignment = VerticalAlignment.Stretch;
                listBox.ItemsSource = datasource.Where(i => i.Category == worker);

                grid.Children.Add(listBox);
                tbItem.Content = grid;

                tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { tabControl1.Items.Add(tbItem); })); 

The method is called with this:

Thread newThread = new Thread(myMethod);
            newThread.SetApartmentState(ApartmentState.STA);
            newThread.Start(); 

ANOTHER UPDATE

This works:

tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, 
                    (Action)(() => 
                    {
                        TabItem tbItem = new TabItem();
                        tbItem.Header = worker;


                        //Grid & ListBox(within tab item)
                        Grid grid = new Grid();

                        ListBox listBox = new ListBox();
                        listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
                        listBox.VerticalAlignment = VerticalAlignment.Stretch;
                        listBox.ItemsSource = datasource.Where(i => i.Category == worker);

                        grid.Children.Add(listBox);
                        tbItem.Content = grid;

                        tabControl1.Items.Add(tbItem); 
                    }));                            
2
  • where r u running this from? can u provide context. and also how did you create tbItem? Commented Apr 8, 2011 at 15:53
  • I've added some more details. What do you think? Commented Apr 8, 2011 at 16:00

3 Answers 3

1

as you can see your tbItem is created on different thread, even through it tries to dispatch it back to the TAbControl's main gui thread.

why not extract out the part that takes longer (which you are usign thread for) and once you got result back, continue with creating tbItem and adding it to TabControl in the GUI thread

Example:

tabControl.Dispatcher.Invoke calls below function with dataSoruce result it gets 
List<string> result = null;
tabControl.Dispatcher.Invoke((Action<IEnumerable<string>>)ProcessResult, result);

public  void ProcessResult(IEnumerable<string> datasource)
{
   //this is where you do creating TabItem and assigning data source to it and adding to TabControl. 

}

Haven't compiled, pls check syntax

Sign up to request clarification or add additional context in comments.

1 Comment

I'm not sure what you mean. Could you post an example?
0

Check the InnerException property to find out the reason. TargetInvocationException is just a wrapper by the wpf runtime. Your lambda probably throws, but without the actual exception you can't tell.

edit

You are creating your TabItem in a different thread, thus the GUI thread can't access it, even though you use the dispatcher for the actual adding. As you already posted with your last snippet, you have to create the TabItem in the GUI thread. Only do the calculation in a different thread, and once the result returns, do the actual creation of the TabItem in the GUI thread (if necessary via the Dispatcher).

2 Comments

You do need to cast or create a delegate of a specific type, though, since Dispatcher.Invoke takes a Delegate, not an Action. See: msdn.microsoft.com/en-us/library/ms591596.aspx
@Reed: you are right. The method I had in mind was in fact an extension method to make calling the Invoke methods easier.
0

The problem is that you're creating your UIElements on a separate thread. This is not allowed.

You can do your processing on a background thread (the call to datasource.Where(i => i.Category == worker);), but unfortunately, every UI element needs to be constructed and used entirely on the main user interface thread.

In your case, this means constructing your ListBox and Grid on the UI thread, inside the Dispatcher call.

I would suggest rewriting this as:

// Load the data on the background...
var data = datasource.Where(i => i.Category == worker);

// Do all work on the UI thread
tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, 
                (Action)(() => 
                {
                    TabItem tbItem = new TabItem();
                    tbItem.Header = worker;

                    //Grid & ListBox(within tab item)
                    Grid grid = new Grid();

                    ListBox listBox = new ListBox();
                    listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
                    listBox.VerticalAlignment = VerticalAlignment.Stretch;
                    listBox.ItemsSource = data;

                    grid.Children.Add(listBox);
                    tbItem.Content = grid;

                    tabControl1.Items.Add(tbItem); 
                }));    

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.