かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

いつも書いてるViewModelBaseとDelegateCommandクラス

WPFHello world書いたり、ちょっと実験したりというときに毎回書いてるのも馬鹿らしいので、ここにメモ。
Visual Studioのテンプレートに登録してしまうのが楽そうだ。

ViewModelBase

public abstract class ViewModelBase : INotifyPropertyChanged
{
    protected ViewModelBase()
    {
    }

    public event PropertyChangedEventHandler PropertyChanged;
    /// <summary>
    /// Raise PropertyChanged Event.
    /// </summary>
    /// <param name="names"></param>
    protected virtual void OnPropertyChanged(params string[] names)
    {
        var h = PropertyChanged;
        if (h == null) return;

        CheckPropertyName(names);

        foreach (var name in names)
        {
            h(this, new PropertyChangedEventArgs(name));
        }
    }
    [Conditional("DEBUG")]
    private void CheckPropertyName(params string[] names)
    {
        var props = GetType().GetProperties();
        foreach (var name in names)
        {
            var prop = props.Where(p => p.Name == name).SingleOrDefault();
            if (prop == null) throw new ArgumentException(name);
        }
    }
    protected void OnPropertyChanged<T>(params Expression<Func<T>>[] propertyExpression)
    {
        OnPropertyChanged(
            propertyExpression.Select(ex => ((MemberExpression)ex.Body).Member.Name).ToArray());
    }
}

DelegateCommand

#region No parameter DelegateCommand
public sealed class DelegateCommand : ICommand
{
    private Action _execute;
    private Func<bool> _canExecute;

    public DelegateCommand(Action execute) : this(execute, () => true)
    {
    }
    public DelegateCommand(Action execute, Func<bool> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute()
    {
        return _canExecute();
    }

    public void Execute()
    {
        _execute();
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    #region ICommand
    bool ICommand.CanExecute(object parameter)
    {
        return CanExecute();
    }
    void ICommand.Execute(object parameter)
    {
        Execute();
    }
    #endregion
}
#endregion

#region Parameter DelegateCommand
public sealed class DelegateCommand<T> : ICommand
{
    private Action<T> _execute;
    private Func<T, bool> _canExecute;

    private static readonly bool IS_VALUE_TYPE;

    static DelegateCommand()
    {
        IS_VALUE_TYPE = typeof(T).IsValueType;
    }


    public DelegateCommand(Action<T> execute) : this(execute, o => true)
    {
    }

    public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(T parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(T parameter)
    {
        _execute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    #region ICommand
    bool ICommand.CanExecute(object parameter)
    {
        return CanExecute(Cast(parameter));
    }

    void ICommand.Execute(object parameter)
    {
        Execute(Cast(parameter));
    }
    #endregion

    /// <summary>
    /// convert parameter value
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    private T Cast(object parameter)
    {
        if (parameter == null && IS_VALUE_TYPE)
        {
            return default(T);
        }
        return (T)parameter;
    }
}

#endregion

多分・・・間違ってないはず。
Visual Studio 2008の時のコードテンプレートへの追加の仕方は、前に書いたけど、Visual Studio 2010ではどうやるんだろう??同じところにメニュー項目がないorz