139 lines
4.1 KiB
C#
139 lines
4.1 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Base view model with notification features and commands.
|
|
/// </summary>
|
|
public abstract class VM : INotifyPropertyChanged, IDisposable
|
|
{
|
|
private static readonly Dispatcher dispatcher = App.Current.Dispatcher;
|
|
|
|
private String exception;
|
|
private Visibility exceptionVisible;
|
|
|
|
/// <summary>
|
|
/// Should be implemented in order to use Activate and Deactivate events.
|
|
/// </summary>
|
|
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; }
|
|
|
|
/// <summary>
|
|
/// Should be the last call when overriden
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Should be the first call when overriden
|
|
/// </summary>
|
|
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<T> : ICommand
|
|
{
|
|
private readonly Action<T> executable;
|
|
|
|
public Command(Action<T> 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));
|
|
}
|
|
}
|
|
}
|