1
votes

I'm quite new to threads in c# (WPF) and since I've implemented some label and progressbar update successfully, I do not understand Why when I try to add items to the treeView of my GUI from another class called in a separate thread I get an exception:

An unhandled exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll

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

My update treeview code is this:

private void updateTreeView(TreeView tree, List<TreeViewItem> items, Boolean clear) {
            tree.Dispatcher.Invoke(new Action(() => {
                if (clear) {
                    tree.Items.Clear();
                }
                ItemCollection treeitems = tree.Items;
                foreach (TreeViewItem item in items) {
                    treeitems.Dispatcher.Invoke(new Action(() => {
                        treeitems.Add(item);
                    }));
                }
                tree.ItemsSource = treeitems;
            }));
        }

And the exception points at the line:

treeitems.Add(item);

Thanks in advance.

2
I misread your question initially. Where are you creating these TreeView items(List<TreeViewItem> items) that you pass to the updateTreeView function? have you made sure to create them in the Main thread as well. seems like your TreeView items are created on the worker thread and your trying to then add them from the main thread.Viv

2 Answers

1
votes

you can use the following :

 delegate void DUpdateTreeView(TreeView tree, List<TreeViewItem> items, Boolean clear);
 private void UpdataTreeView(TreeView tree, List<TreeViewItem> items, Boolean clear)
    {
        if (tree.InvokeRequired)
        {
            DUpdateTreeView d = new DUpdateTreeView(UpdataTreeView);
            // replace this by the main form object if the function doesn't in the main form class 
            this.Invoke(d, new object[] { tree, items, clear }); 
        }
        else
        {
            if (clear)
            {
                tree.Items.Clear();
            }
            else
            {
                // Here you can add the items to the treeView
                /***
                ItemCollection treeitems = tree.Items;
                foreach (TreeViewItem item in items)
                {
                    treeitems.Dispatcher.Invoke(new Action(() =>
                    {
                        treeitems.Add(item);
                    }));
                }
                tree.ItemsSource = treeitems;
                ***/
            }
        }
    }
0
votes

This is a really old question but I figured I would answer it. You have two dispatchers in your sample. You have a treeview that you are getting its thread and a list that seems to be created in a different thread.

But the code should look more like this. Sorry about the VB in this case I'm using a delegate inside the invoke.

 tree.Dispatcher.BeginInvoke(Sub()
          Dim node = new TreeViewItem() With {.Header = "Header"}
          tree.items.add(node)
                             End Sub)

I am not jumping out of the UI thread to add the node like in the original question.