WPF_ICommandインターフェース

ICommandインターフェース

ICommandインターフェースとは

ICommandインターフェースを実装すれば独自のコマンドクラスを作成することができます。

コマンドとは、Viewに公開する(XAMLで発生した何らかの操作に基づいて処理を実行する)操作のことです。

コマンドは、ViewModelのプロパティとして公開され、データ・バインディング経由でViewから操作されます。


MVVMでコマンドを使用する理由

コマンドはビューと処理の分離を行います。

  • コードビハインド(*.xaml.cs)には一切書く必要がないこと。
  • コマンドの単体テストで、ビューやビューモデルが不要となります。

コマンドとメソッドの違い

  • コマンド(ICommand)ならばバインド機能が利用できるため、別クラス(主にViewModel)の処理を簡単に呼び出すことができます。
    • XAMLからのメソッド呼び出しがXAMLと同一クラス内のメソッド(コードビハインド)である必要が無いことを意味します。
  • コマンドは、処理の実行可否を状態として持つ事ができ、さらには状態の変更を通知できます。

ICommand.cs


 namespace System.Windows.Input
 {
     public interface ICommand
     {
         // コマンドを実行するかどうかに影響するような変更があった場合に発生します。
         event EventHandler CanExecuteChanged;

         // 現在の状態でコマンドが実行可能かどうかを決定するメソッドを定義します。
         bool CanExecute(object parameter);

         // コマンドが起動される際に呼び出すメソッドを定義します。
         void Execute(object parameter);
     }
 }

ICommand実装例

コマンドの実装

ICommandを継承したコマンドクラスを作成します。

パラメータから受け取った文字列をMessageBoxで表示するコマンド例です。


namespace WpfDevelop
{
    using System;
    using System.Windows;
    using System.Windows.Input;

    class MainCommand : ICommand
    {
        /// <summary>
        /// 現在の状態でコマンドを実行できるか判定するメソッド.
        /// </summary>
        /// <param name="parameter">XAML上で'CommandParameter'に指定した値. default=null.</param>
        /// <returns>このコマンドを実行できる場合は true. それ以外は false .</returns>
        public bool CanExecute(object parameter)
        {
            string text = parameter as string;
            return !string.IsNullOrEmpty(text);
        }

        /// <summary>
        /// 実行されるコマンドの実処理.
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            MessageBox.Show(parameter as string);
        }

        /// <summary>
        /// CanExecute()の返す値が変わった際に発火するイベントハンドラ.
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

コマンドをViewModelのプロパティとして公開する。

ViewModel


namespace WpfDevelop
{
    using System.Windows.Input;

    public class MainWindowViewModel : ViewModelBase
    {
        private string _bindText = string.Empty;

        public string BindText
        {
            get
            {
                return this._bindText;
            }
            set
            {
                this._bindText = value;
                OnPropertyChanged(nameof(BindText));
                return;
            }
        }

        public ICommand MainCommand { get; private set; }

        public MainWindowViewModel()
        {
            this.MainCommand = new MainCommand();
        }
    }
}

(備考)INotifyPropertyChanged用のViewModelBaseクラス


namespace WpfDevelop
{
    using System.ComponentModel;
    using System.Runtime.CompilerServices;

    /// <summary>
    /// ViewModel 基底クラス を表現します。
    /// </summary>
    public class ViewModelBase : INotifyPropertyChanged
    {
        /// <summary>
        /// プロパティ値が変更されたことをクライアントに通知します。
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// PropertyChanged イベント を発生させます。
        /// </summary>
        /// <param name="propertyName">変更されたプロパティの名前</param>
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

コマンドをView操作へ対応(データ・バインディング)する

xaml


<Window x:Class="WpfDevelop.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vm="clr-namespace:WpfDevelop"
        mc:Ignorable="d"
        Title="MainWindow" Height="480" Width="640">
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <TextBox x:Name="EditBox" Margin="10" Background="White" Grid.Row="0" AcceptsTab="True" AcceptsReturn="True"
                 Text="{Binding BindText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <Button                             
            Width="120" Grid.Row="1"
            HorizontalAlignment="Center" VerticalAlignment="Center"
            Command="{Binding MainCommand}"
            CommandParameter="{Binding ElementName=EditBox, Path=Text}"
            Content="Execute" />
    </Grid>
</Window>

xaml.cs


namespace WpfDevelop
{
    using System.Windows;
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            MainWindowViewModel vm = new MainWindowViewModel();
            this.DataContext = vm;
        }
    }
}

関連ページ