// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.ComponentModel; using System.Threading.Tasks; namespace Microsoft.Toolkit.Helpers { /// /// Helper class to wrap around a Task to provide more information usable for UI databinding scenarios. As discussed in MSDN Magazine: https://msdn.microsoft.com/magazine/dn605875. /// /// Type of result returned by task. public sealed class NotifyTaskCompletion : INotifyPropertyChanged { /// /// Initializes a new instance of the class. /// /// Task to wait on. public NotifyTaskCompletion(Task task) { Task = task; if (!task.IsCompleted) { TaskCompletion = WatchTaskAsync(task); } } private async Task WatchTaskAsync(Task task) { try { await task; } catch { } if (PropertyChanged == null) { return; } PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(Status))); PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(IsCompleted))); PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(IsNotCompleted))); if (task.IsCanceled) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(IsCanceled))); } else if (task.IsFaulted) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(IsFaulted))); PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(Exception))); PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(InnerException))); PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(ErrorMessage))); } else { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(IsSuccessfullyCompleted))); PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(Result))); } } /// /// Gets the task that is being waited on. /// public Task Task { get; private set; } /// /// Gets the task wrapper task. /// public Task TaskCompletion { get; private set; } /// /// Gets the result of the given task. /// public TResult Result { get { return (Task.Status == TaskStatus.RanToCompletion) ? Task.Result : default(TResult); } } /// /// Gets the status of the task. /// public TaskStatus Status => Task.Status; /// /// Gets a value indicating whether the task is completed. /// public bool IsCompleted => Task.IsCompleted; /// /// Gets a value indicating whether the task is not completed. /// public bool IsNotCompleted => !Task.IsCompleted; /// /// Gets a value indicating whether the task was successfully completed. /// public bool IsSuccessfullyCompleted => Task.Status == TaskStatus.RanToCompletion; /// /// Gets a value indicating whether the task was cancelled. /// public bool IsCanceled => Task.IsCanceled; /// /// Gets a value indicating whether there was an error with the task. /// public bool IsFaulted => Task.IsFaulted; /// /// Gets the exception which occured on the task (if one occurred). /// public AggregateException Exception => Task.Exception; /// /// Gets the inner exception of the task. /// public Exception InnerException => Exception?.InnerException; /// /// Gets the error message of the task. /// public string ErrorMessage => InnerException?.Message ?? Exception.Message; /// /// PropertyChanged event. /// public event PropertyChangedEventHandler PropertyChanged; } }