2014年7月10日木曜日

ボタン用 ViewModel の作成

今回も Livet を使った MVVM ネタです。

ViewModel を書いていると同じことをたくさん書くので疲れます。
で、今回は ViewModelCommand でボタン用の ViewModel を作成してみました。

using System;
using Livet;
using Livet.Commands;

/// <summary>
/// <see cref="System.Windows.Controls.Button"/> の ViewModel の機能を提供します。
/// </summary>
public class ButtonViewModel : ViewModel
{
    #region Private fields

    /// <summary>
    /// コンテンツ。
    /// </summary>
    private object content;

    /// <summary>
    /// コマンド。
    /// </summary>
    private ViewModelCommand command;

    /// <summary>
    /// コマンドが実行可能かどうかの値。
    /// </summary>
    private bool canExecute;

    /// <summary>
    /// コマンドが実行可能かどうかが変化したことを自動通知するかどうかの値。
    /// </summary>
    private bool autoRaiseCanExecuteChanged;

    /// <summary>
    /// コマンドが実行するメソッド。
    /// </summary>
    private Action execute;

    #endregion // Private fields

    #region Constructors

    /// <summary>
    /// <see cref="ButtonViewModel"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="execute">コマンドが実行するメソッド。</param>
    /// <exception cref="ArgumentNullException"><c>execute</c> が null です。</exception>
    public ButtonViewModel(Action execute)
        : this(execute, true, true)
    {
    }

    /// <summary>
    /// <see cref="ButtonViewModel"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="execute">コマンドが実行するメソッド。</param>
    /// <param name="canExecute">コマンドが実行可能かどうかの値。</param>
    /// <exception cref="ArgumentNullException"><c>execute</c> が null です。</exception>
    public ButtonViewModel(Action execute, bool canExecute)
        : this(execute, canExecute, true)
    {
    }

    /// <summary>
    /// <see cref="ButtonViewModel"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="execute">コマンドが実行するメソッド。</param>
    /// <param name="canExecute">コマンドが実行可能かどうかの値。</param>
    /// <param name="autoRaiseCanExecuteChanged">コマンドが実行可能かどうかが変化したことを自動通知するかどうかの値。</param>
    /// <exception cref="ArgumentNullException"><c>execute</c> が null です。</exception>
    public ButtonViewModel(Action execute, bool canExecute, bool autoRaiseCanExecuteChanged)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        this.execute = execute;
        this.canExecute = canExecute;
        this.autoRaiseCanExecuteChanged = autoRaiseCanExecuteChanged;
    }

    #endregion // Constructors

    #region Properties

    /// <summary>
    /// コンテンツを取得または設定します。
    /// </summary>
    public object Content
    {
        get { return this.content; }
        set
        {
            if (value != this.content)
            {
                this.content = value;
                this.RaisePropertyChanged(() => this.Content);
            }
        }
    }

    /// <summary>
    /// コマンドを取得します。
    /// </summary>
    public ViewModelCommand Command
    {
        get
        {
            return this.command = this.command ??
                new ViewModelCommand(this.execute, () => this.CanExecute);
        }
    }

    /// <summary>
    /// コマンドが実行可能かどうかの値を取得または設定します。
    /// </summary>
    public bool CanExecute
    {
        get { return this.canExecute; }
        set
        {
            if (value != this.canExecute)
            {
                this.canExecute = value;
                this.RaisePropertyChanged(() => this.CanExecute);

                if (this.AutoRaiseCanExecuteChanged)
                {
                    this.RaiseCanExecuteChanged();
                }
            }
        }
    }

    /// <summary>
    /// コマンドが実行可能かどうかが変化したことを自動通知するかどうかの値を取得または設定します。
    /// </summary>
    public bool AutoRaiseCanExecuteChanged
    {
        get { return this.autoRaiseCanExecuteChanged; }
        set
        {
            if (value != this.autoRaiseCanExecuteChanged)
            {
                this.autoRaiseCanExecuteChanged= value;
                this.RaisePropertyChanged(() => this.AutoRaiseCanExecuteChanged);
            }
        }
    }

    #endregion // Properties

    #region Public methods

    /// <summary>
    /// コマンドを実行します。
    /// </summary>
    public void Execute()
    {
        if (this.command != null)
        {
            this.Command.Execute();
        }
    }

    /// <summary>
    /// コマンドが実行可能かどうかが変化したことを通知します。
    /// </summary>
    public void RaiseCanExecuteChanged()
    {
        if (this.command != null)
        {
            this.command.RaiseCanExecuteChanged();
        }
    }

    #endregion // Public methods
}

最低限必要なプロパティを実装しました。
おまけで、RaiseCanExecuteChanged メソッドの実行を制御するプロパティを用意。

使う側の MainWindowViewModel.cs はこんな感じで実装します。

public MainWindowViewModel()
{
    this.CopyButton = new ButtonViewModel(this.CopyAction)
    {
        Content = "コピー",
    };
}

public ButtonViewModel CopyButton { get; private set; }

private void CopyAction()
{
}

最後は、xaml です。

<Button Command="{Binding Path=CopyButton.Command}"
        Width="75"
        Height="24"
        Margin="3"
        HorizontalAlignment="Right"
        Content="{Binding Path=CopyButton.Content" />

バインドする名前が長くなってしまうのが難点だけど、ViewModel がスッキリできました。


頑張りすぎず脱力系でいこうと思います。
以上。

0 件のコメント:

コメントを投稿