// 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;
}
}