1 using System; 2 using System.ComponentModel; 3 using System.Threading.Tasks; 4 public sealed class NotifyTaskCompletion<TResult> : INotifyPropertyChanged 5 { 6 public NotifyTaskCompletion(Task<TResult> task) 7 { 8 Task = task; 9 if (!task.IsCompleted) 10 { 11 var _ = WatchTaskAsync(task); 12 } 13 } 14 private async Task WatchTaskAsync(Task task) 15 { 16 try 17 { 18 await task; 19 } 20 catch 21 { 22 } 23 var propertyChanged = PropertyChanged; 24 if (propertyChanged == null) 25 return; 26 propertyChanged(this, new PropertyChangedEventArgs("Status")); 27 propertyChanged(this, new PropertyChangedEventArgs("IsCompleted")); 28 propertyChanged(this, new PropertyChangedEventArgs("IsNotCompleted")); 29 if (task.IsCanceled) 30 { 31 propertyChanged(this, new PropertyChangedEventArgs("IsCanceled")); 32 } 33 else if (task.IsFaulted) 34 { 35 propertyChanged(this, new PropertyChangedEventArgs("IsFaulted")); 36 propertyChanged(this, new PropertyChangedEventArgs("Exception")); 37 propertyChanged(this, 38 new PropertyChangedEventArgs("InnerException")); 39 propertyChanged(this, new PropertyChangedEventArgs("ErrorMessage")); 40 } 41 else 42 { 43 propertyChanged(this, 44 new PropertyChangedEventArgs("IsSuccessfullyCompleted")); 45 propertyChanged(this, new PropertyChangedEventArgs("Result")); 46 } 47 } 48 public Task<TResult> Task { get; private set; } 49 public TResult Result { get { return (Task.Status == TaskStatus.RanToCompletion) ? 50 Task.Result : default(TResult); } } 51 public TaskStatus Status { get { return Task.Status; } } 52 public bool IsCompleted { get { return Task.IsCompleted; } } 53 public bool IsNotCompleted { get { return !Task.IsCompleted; } } 54 public bool IsSuccessfullyCompleted { get { return Task.Status == 55 TaskStatus.RanToCompletion; } } 56 public bool IsCanceled { get { return Task.IsCanceled; } } 57 public bool IsFaulted { get { return Task.IsFaulted; } } 58 public AggregateException Exception { get { return Task.Exception; } } 59 public Exception InnerException { get { return (Exception == null) ? 60 null : Exception.InnerException; } } 61 public string ErrorMessage { get { return (InnerException == null) ? 62 null : InnerException.Message; } } 63 public event PropertyChangedEventHandler PropertyChanged; 64 }
An updated ViewModel using NotifyTaskCompletion<T> would look like this:async
1 public class MainViewModel 2 { 3 public MainViewModel() 4 { 5 UrlByteCount = new NotifyTaskCompletion<int>( 6 MyStaticService.CountBytesInUrlAsync("http://www.example.com")); 7 } 8 public NotifyTaskCompletion<int> UrlByteCount { get; private set; } 9 }
1 <Window x:Class="MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 4 <Window.Resources> 5 <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> 6 </Window.Resources> 7 <Grid> 8 <!-- Busy indicator --> 9 <Label Content="Loading..." Visibility="{Binding UrlByteCount.IsNotCompleted, 10 Converter={StaticResource BooleanToVisibilityConverter}}"/> 11 <!-- Results --> 12 <Label Content="{Binding UrlByteCount.Result}" Visibility="{Binding 13 UrlByteCount.IsSuccessfullyCompleted, 14 Converter={StaticResource BooleanToVisibilityConverter}}"/> 15 <!-- Error details --> 16 <Label Content="{Binding UrlByteCount.ErrorMessage}" Background="Red" 17 Visibility="{Binding UrlByteCount.IsFaulted, 18 Converter={StaticResource BooleanToVisibilityConverter}}"/> 19 </Grid> 20 </Window>
From: https://msdn.microsoft.com/en-us/magazine/dn605875.aspxthis