This post explains how to process data from a task in WPF in a way I’d consider “best-practice”. The main code could or should be in the view-model.
Code-behind (keep it short or better yet use a delegate command)
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
// Get some parameters if necessary
[...]
this.SomeViewModelData.StartSearch([parameters...]);
}
catch (Exception ex)
{
log.Warn("Error handling...", ex);
}
}
And the code in the view-model:
- StartSearch() is a method in the view-model class and sets the properties of the view-model that are bound to the UI
- this.IsWaiting is some bool property to indicate the waiting status in the UI
- this.ResultData is not bound but contains data to be processed
- ProcessResultData() processes the result and sets the output (for example it might fill an ObservableCollection)
public void StartSearch([parameters...])
{
try
{
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
this.IsWaiting = true;
Task.Factory.StartNew(() =>
{
this.ResultData = DatabaseService.GetComplexData([parameters...]);
}).ContinueWith((t) =>
{
// Invoke in UI Thread via scheduler
this.ProcessResultData();
// Cancel waiting indicator
this.IsWaiting = false;
}, uiScheduler // <-- This is the important part: Continue
// the task in the UI thread
{
if (t.Exception != null)
{
log.Warn("Task exception handling...", t.Exception);
}
this.IsWaiting = false;
}, TaskContinuationOptions.OnlyOnFaulted);
}
catch (Exception ex)
{
log.Warn("Do exception handling... ", ex);
this.IsWaiting = false;
}
}