So I want to load my data collections in a background thread and then bind my treeview to the new collection (rather than having the background thread queue things up on the dispatcher every time it wants to add an item to the list [sounds inefficient]).
Is this possible? I create the new data structure and it is output as pd.result on a background thread. When the UI thread checks that the dialog box has closed, it should then set
ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;
after this the event OnLoadVCD is called. I have an event handler that then tries to set a treeview's itemsource to the new collection.
this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;
This crashes with the error: "The calling thread cannot access this object because a different thread owns it."
Not even sure how to debug it, the call stack doesn't give any real details.
However, if I just set the Itemsource to a blank new empty collection like so:
this.AvailableModulesTreeView.ItemsSource = (IEnumerable<object>)new List<object>();
it doesn't crash (but then it's not displaying my data either). Any ideas what could be causing the crash?
I thought it might be that I was updating the UI from the wrong thread, so I tried both calling the dispatcher with begininvoke, and checking that I am indeed the UI thread with dispatcher.checkaccess(). so that does not seem to be the issue. However, I really don't know what is going on.
Another way I could implement this is to just make my parsing routine just update the original data structure that is bound to the treeview by caling dispatcher on each item as it is added to the observable collection. However, even if that is the only solution, I really dislike not knowing why something doesn't work. In my mind, it seems reasonable to just create an entirely new data structure on a different thread, and then rebind the new datastructure to the treeview, discarding the old one. It also seems cleaner to me than dozens of 1 line ObservableCollectionInstance.Add calls being placed on the dispatcher while parsing through a file on the background thread.
Full Code:
method called by UI thread
public bool LoadPortInterface(string VCDFileName)
{
ProgressDialog pd = new ProgressDialog("Loading File: ", VCDFileName);
pd.Owner = Application.Current.MainWindow;
pd.WindowStartupLocation = WindowStartupLocation.CenterOwner;
ModuleHierarchyVM.TopLevelModules.Clear();
VCDData TempVCDOutput = null;
Func<object> handler = delegate
{
return VCDParser.ParseVCDFileForAllPorts(VCDFileName, this, pd.Worker, out TempVCDOutput);
};
pd.RunWorkerThread(handler);
pd.ShowDialog();
if (pd.DialogResult == true)
{
ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;
VCDOutput = TempVCDOutput;
}
OnLoadVcd();
}
Response to OnLoadVCD event handler in graphviewer:
void gvvm_LoadVCDEvent(object sender, EventArgs e)
{
this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;
}