In my MVVM application my view model calls 3 different service methods, converts the data from each into a common format and then updates the UI using property notification/observable collections etc.
Each method in the service layer starts a new Task
and returns the Task
to the view model. Here's an example of one of my service methods.
public class ResourceService
{
internal static Task LoadResources(Action<IEnumerable<Resource>> completedCallback, Action<Exception> errorCallback)
{
var t = Task.Factory.StartNew(() =>
{
//... get resources from somewhere
return resources;
});
t.ContinueWith(task =>
{
if (task.IsFaulted)
{
errorCallback(task.Exception);
return;
}
completedCallback(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
return t;
}
}
Here's the calling code and other relevant parts of the view model...
private ObservableCollection<DataItem> Data = new ObservableCollection<DataItem>();
public ICollectionView DataView
{
get { return _dataView; }
set
{
if (_dataView != value)
{
_dataView = value;
RaisePropertyChange(() => DataView);
}
}
}
private void LoadData()
{
SetBusy("Loading...");
Data.Clear();
Task[] tasks = new Task[3]
{
LoadTools(),
LoadResources(),
LoadPersonel()
};
Task.WaitAll(tasks);
DataView = CollectionViewSource.GetDefaultView(Data);
DataView.Filter = FilterTimelineData;
IsBusy = false;
}
private Task LoadResources()
{
return ResourceService.LoadResources(resources =>
{
foreach(var r in resources)
{
var d = convertResource(r);
Data.Add(d);
}
},
error =>
{
// do some error handling
});
}
This almost works but there are a couple of small issues.
Number 1: In the call to SetBusy
at the very beginning, before I start any tasks and before I call WaitAll
, I set the IsBusy
property to true. This should update the UI and show the BusyIndicator control but it's not working. I've also tried adding simple string properties and binding those and they're not being updated either. The IsBusy functionality is part of a base class and works in other view models where I don't have more than one Task running so I don't believe there is an issue with the property notification or data binding in the XAML.
All the data bindings seem to be updated after the whole method has completed. I'm not seeing any "first time exceptions" or binding errors in the output Window which is leading me to believe the UI thread is somehow being blocked before the call to WaitAll.
Number 2: I seem to be returning the wrong Tasks from the service methods. I want everything after WaitAll
to run after the view model has converted all the results from all the service methods in the callbacks. However if I return the continuation task from the service method the continuation never gets called and WaitAll
waits forever. The strange thing is the UI control bound to the ICollectionView actually displays everything correctly, I assumed this is because Data is an observable collection and the CollectionViewSource is aware of the collection changed events.