C# / WPF Databinding and backgroundworkers
Update2
I've rewritten the entire question, because some things became a lot clearer, the issue now seems to be that I created a list of DependencyProperties on a different thread than where the DependencyProperties will be used :(.
When I do some work on a BackgroundWorker
the XAML
bindings cause an ArgumentException
Must create DependencySource on same Thread as the DependencyObject.
I've got the following setup:
I've got a simple class that implements INotifyPropertyChanged
which contains a few ints, list's and Dictionaries.
public class Calculator : INotifyPropertyChanged
{
//Note that InstanceGroup is a dependency object
private List<InstanceGroup> instanceGroups = new List<InstanceGroup>();
public List<InstanceGroup> InstanceGroups
{
get { return instanceGroups; }
set { instanceGroups = value; }
}
// snip //
public void Calculate()
{
InstanceGroups = MyNewFilledInstanceGroup;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("instanceGroups"));
}
}
}
In a UserControl
I use a BackgroundWorker
to run the Calculate
method, because it can take a lot of time:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object o, DoWorkEventArgs args)
{
lock (Calculator)
{
Calculator.Calculate();
}
};
worke开发者_运维问答r.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
In the XAML
file of the UserControl
I have multiple bindings to the Calculator
, like {Binding Path=Calculator.InstanceGroups, Path=userControlName}
.
(The overall goal is to be able to do all the work in the Calculate method on a separate thread so I can show a progress bar or something like that)
I am not convinced that you need to use DP for this Observable collection. Best to store it in ViewModel.
ObservableCollections are not thread-safe, and you need to use Dispatcher to update the collection.
Google there were some posts with Extension to ObservableCollection which used Dispatcher.
This link might help
Any DependencyObject
includes a Dispatcher
property that can help you push work to the correct thread for that object.
You can use Dispatcher.Invoke
or Dispatcher.BeginInvoke
to run code on the correct thread.
The only solution seems to be to not create DependencyProperties ( How to handle ObservableCollection<> result from a parallelized Task in MVVM? ) in a background task, this weird behavior costed me the better part of the day. But at least now I know what the problem was.
For the sake of completeness I'd mention two solutions of WPF guru Dean Chalk:
- Create a thread-safe observable collection. It's an old school solution that just works. To get the source code check a short article in his blog. This one was mentioned by anvarbek raupov in this thread earlier. Similar solution is in Sasha Barber's blog.
- Use Reactive Extensions library. See this article for an example. It's a bit bulky for one task, but meanwhile it brings a bunch of modern tools what come in handy.
精彩评论