WPF MVVM Buttonのupとdownイベント発生時に各コマンドをICommandに送る方法


手順

  1. 通常どおりにボタンとコマンドを作成する。
  2. ボタンにイベントにPreviewMouseDown,PreviewMouseUpにイベントハンドラを追加する。
  3. イベントハンドラで接続されいるコマンドのExecuteに引数をつけて呼び出す。
  4. ICommandのExecute関数ではパラメータで場合分けする。
MainWindow.xaml
<Window  x:Class= ...>
    <StackPanel>
        <Button x:Name="button1" Content="Button1" 
            Command="{Binding ButtonCommand}" 
            PreviewMouseDown = "button1_PreviewMouseDown"
            PreviewMouseUp = button1_PreviewMouseUp/>
    </StackPanel>
</MainWindow>
MainWindow.xaml.cs
public partial class MainWindow
{
    private void button1_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        Button button =(Button)sender;
        if(button != null)
            button.Command.Execute("Down");
    }
    private void button1_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        Button button =(Button)sender;
        if(button != null)
            button.Command.Execute("Up");
    }
}
MainWindowViewModel.cs
using Prism.Commands;      // prism6

class MainWindowViewModel
{

    prtvate DelgateCommand<object> buttonCommand;
    public ICommand Button {
        get
        {
            return this.buttonCommand ?? 
                       (this.buttonCommand = new DelgateCommand<object>(executeButton, canExecuteButton) )
        }
    }
    void executeButton(object paramater)
    {
        string str = (string)paramater;
        if(str == "Down"){
            // ToDo: Downの処理
        }else if(str == "Up"){
            // ToDo: Upの処理
        }
    }
    bool canExecuteButton(object paramater)
    {
        return true;
    }
}

メモ

イベントはここで定義
namespace System.Windows ... partial class UIElement : IAnimatable
コマンドは
ButtonBase

MouseDown,MouseUpのイベントはButtonBaseで使用のため単純にはとれない。

注意:Downのコマンド実行でCanExecute()の戻り値をfalseにするとUpは実行されません。

改良版

ViewModelで Click 、PreviewMouseDown、 PreviewMouseUp を得る。
ハンドラーは複数ボタンに共通で使用できる。
ButtonのCommandParameterの設定はしない。

X.Xaml

  <Button Content="+X" Command="{Binding AltXPCommand}"  PreviewMouseDown="btn_PreviewMouseDown" PreviewMouseUp="btn_PreviewMouseUp"/>
  <Button Content="-X" Command="{Binding AltXNCommand}"   PreviewMouseDown="btn_PreviewMouseDown" PreviewMouseUp="btn_PreviewMouseUp"/>

X.Xaml.cs
    public partial class PaCommand : UserControl
    {
        public PaCommand()
        {
            InitializeComponent();
        }
        /// <summary>
        // WPF MVVM Buttonのupとdownイベント発生時に各コマンドをICommandに送る
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            (sender as Button)?.Command?.Execute(true);
        }

        private void btn_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            (sender as Button)?.Command?.Execute(false);
        }
    }
XViewModel.cs
     // Prismの場合。
        /// <summary>
        /// </summary>
        public DelegateCommand<object> LatXPCommand
        {
            get { return _latXPCommand = _latXPCommand ?? 
                    new DelegateCommand<object>(LatXPExecute, LatXPCanExecute); }
        }
        private DelegateCommand<object> _latXPCommand;
        void LatXPExecute(object parameter)
        {
            bool? para = parameter as bool?;
            // nullは、Click
            // trueは PreviewMouseDown
            // falseは PreviewMouseUp
            if(! para.HasValue)
            {
                 /* Click */
            }else if(pata==true)
            {
                 /* PreviewMouseDown  */
            }else{
                 /* PreviewMouseUp  */
            }
        }
        bool LatXPCanExecute(object parameter)
        {
            return true;
        }