2013年1月28日月曜日

メニューのコマンドをViewModelに実装

1つ前の記事に記載したメニューの書き方から、実際にプログラム側で処理を行う部分を実験してみました。

MVVMモデルですとViewModelに相当する部分ですので、ファイル名は"MainWindowViewModel.cs"としています。

コマンドの記述としては、CanExecuteとExecuteが肝なのですが、こちらの書き方が諸説あるようで、まずは(調べると)ポピュラーと思われるパターンで実装してみました

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;     // IComand用
using System.Windows;            // Dialog表示用(表示しなければ不要)

namespace _130126Project
{
    public class MainWindowViewModel
    {
        class OkCommandImpl : ICommand
        {
          public bool CanExecute(object parameter) { return true; }
          public event EventHandler CanExecuteChanged;

          public void Execute(object parameter)
          {
            MessageBox.Show("コマンドが実行されました。");
          }
        }

        public ICommand OkCommand { get; private set; }



        // ViewModelのコンストラクタ
        public MainWindowViewModel()
        {
            // public ICommand型の公開プロパティに
      // OkCommandImplクラスのオブジェクトを設定
            this.OkCommand = new OkCommandImpl();
        }

    }
}

そして、コードビハインドと言われるコード(MainWindow.xaml.cs)のコンストラクタに
 DataContext = new MainWindowViewModel();
を記述します

    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainWindowViewModel();   // ここだけ追加
        }
    }

 とりあえずこれで
- メニューの"ファイル -  実行"を選択すると
- MainWindowViewModel.csのICommand型の"OkCommandの
動きます(これならprismを使わなくても動きますね)

もうちょっといい書き方があるかなぁと調べていると、
- DelegateCommandを使うと簡潔に記載できる
との記事が出てきます
さらに
- 以前はDelegateCommandを自作してたけど、prismに入っているから便利
という記事も出てきたりしました

いろいろ調べた末に↑のコードを以下のように変更して動作する事が出来ました
以下ではPrismを使っているのでコメントにある通りに、dllの参照設定を追加する必要があります
(面倒なので、2つ前の記事で解凍したprism関連のdllを全て選択してしまっていますが、使うのは以下のusingで記載したdllだけだと思います)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.ComponentModel;    // INotifyPropertyChange用
using Microsoft.Practices.Prism.Commands;    // prism用(予めdllを参照設定しておく)
using Microsoft.Practices.Prism.ViewModel;  // NotificationObject用

namespace _130126Project{
    public class MainWindowViewmodel : NotificationObject
    {
        private DelegateCommand<object> _okCommand;

        public DelegateCommand<object> OkCommand
        {
            get
            {
                return _okCommand ?? (_okCommand = new DelegateCommand<object>(
                    (param) =>
                    {   // Execute
                        MessageBox.Show("コマンドが実行されました");
                    },
                    (param) =>
                    {    // CanExecute
                         return true;    // 実行しない場合はfalseを返す。動的に変更可                    }
                ));
            }
        }
    }
}

動作としては以下のような感じのようです(デバッガでbreakさせた時の挙動)
0. View(xaml)の
     Command="{Binding OkCommand}"
  と
  DelegateCommand<object> OkCommand が紐づけ
1. オブジェクト作成時(プログラム起動時)にOkCommandのgetterにWPFがアクセス
  _okCommandはnullなのでDelegateCommandでnewします
2. menu表示時("ファイル"を押下してペロッと表示される瞬間)にWPFがCanExecuteを聞きに来る
  今回はtrueが返るのでメニューの"実行"も黒文字で表示される
3. "実行"を選択するともう一度"CanExecute"を聞きに来て、すぐにExecuteを実行
  結果、MessageBoxが表示される

"1"の部分が以前は自作されていたようでうすが、prismでサポートされたのでこちらの"DelegateCommand"を使うようになったようです

View-ViewModelのコマンドはこれで開通したので、次はModelとViewModelの接続について試していこうと思います





0 件のコメント:

コメントを投稿