How to handle ObservableCollection<> result from a parallelized Task in MVVM?
-
26-09-2019 - |
Question
I am gathering data in a separate Task and I want to data bind the result to a GUI component using an ObservableCollection<>
. So my code goes something like this:
private ObservableCollection<MyItem> _items;
public ObservableCollection<MyItem> Items
{
get { return _items; }
set
{
if (_items.Equals(value))
{
return;
}
_items = value;
RaisePropertyChanged("Items");
}
}
private void LoadData()
{
Task task = Task.Factory.StartNew(() =>
{
ObservableCollection<MyItem> itms = _htmlParser.FetchData(...);
Dispatcher.CurrentDispatcher.Invoke((Action)delegate
{
Items = itms;
});
});
}
The data is fetched from a component doing some HTTP requests. The error I am getting is:
Must create DependencySource on same Thread as the DependencyObject.
I am using the MVVM Light toolkit framework. I also tried to send the result as a message, but that ended up in the same error message. Any ideas or pointers?
EDIT: Here's the issue:
public class MyItem
{
public string Id { get; set; }
public string Name { get; set; }
public BitmapImage Image { get; set; } // <--- A big No No because it inherits from the DependencyObject
public Uri Uri { get; set; }
}
I changed the BitmapImage
to a byte[]
data type.
Solution
The exception you're getting ("Must create DependencySource on same Thread as the DependencyObject") indicates that something's being created on a background thread and used on the UI thread. Are there any UI controls being created and stored in the collection for use by the UI?
I see that the ObservableCollection itself is being created on a background thread, but I don't think that's the issue -- unfortunately I'm not in the office to code and confirm that.
OTHER TIPS
Can you try to replace the Dispatcher.CurrentDispatcher
into Application.Current.Dispatcher
not sure about this though