namespace InspectionUI { using System; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using System.Windows.Threading; /// /// Base view model with notification features and commands. /// public abstract class VM : INotifyPropertyChanged, IDisposable { private static readonly Dispatcher dispatcher = App.Current.Dispatcher; private String exception; private Visibility exceptionVisible; /// /// Should be implemented in order to use Activate and Deactivate events. /// protected VM() { App.Activate += this.Activated; this.ExceptionVisible = Visibility.Collapsed; this.CloseException = new Command(this.CloseExceptionHanler); } public event PropertyChangedEventHandler PropertyChanged; public String Exception { get => this.exception; protected set => this.Set(() => this.exception = value); } public Visibility ExceptionVisible { get => this.exceptionVisible; protected set => this.Set(() => this.exceptionVisible = value); } public ICommand CloseException { get; } /// /// Should be the last call when overriden /// public virtual void Dispose() { App.Activate -= this.Activated; App.Deactivate -= this.Dispose; } protected void DispatcherInvoke(Action action) { try { dispatcher.Invoke(action); } catch (Exception e) { this.Exception = e.ToString(); } } /// /// Should be the first call when overriden /// protected virtual void Activated() => App.Deactivate += this.Dispose; protected void NotifyPropertyChanged([CallerMemberName] String property = "") => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); protected void Set(Action setExpression, [CallerMemberName] String property = "") { this.DispatcherInvoke(setExpression); this.NotifyPropertyChanged(property); } protected void StartTask(Action action) { Task.Factory .StartNew(action) .ContinueWith(this.Catch); } protected void Catch(Task task) { if (task.Exception != null) { this.Exception = task.Exception.ToString(); this.ExceptionVisible = Visibility.Visible; } } private void CloseExceptionHanler() { this.Exception = null; this.ExceptionVisible = Visibility.Collapsed; } protected class Command : ICommand { private readonly Action executable; public Command(Action executable) => this.executable = executable; public event EventHandler CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } public bool CanExecute(Object _) => this.executable != null; public void Execute(Object _) => this.executable?.Invoke(); } protected class Command : ICommand { private readonly Action executable; public Command(Action executable) => this.executable = executable; public event EventHandler CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } public bool CanExecute(Object _) => this.executable != null; public void Execute(Object parameter) => this.executable?.Invoke(parameter is T t ? t : default(T)); } } }