MVVM パターンでのダイアログの扱いに悩む
MVVM パターンを使った開発だと、私の場合、ViewModel にデータの保持やサービス呼び出しを実装していきます。サービス呼び出しはエラーが発生する場合があるので、そのときはエラーダイアログ*1を出すんですが、処理をどこに記述しようかいつも頭を悩ませます。いまだ手探りの状態です。
私の周りでは下に挙げる方法を使っているみたい
(1)コマンド至上主義!派
ViewModelがもつコマンドをボタンにバインドする。エラーが発生したときはViewModel内で処理してダイアログを出す。単体テストのことを考えて、ダイアログを表示する部分は差し替え可能にする。
// ViewModel 内でダイアログを表示するときに使う public static class ViewModelErrorDialog { // 単体テストではこいつを差し替える internal static Func<string,bool?> _showErrorDialogFunc; static ViewModelErrorDialog() { _showErrorDialogFunc = s => { return new ErrorDialog(s).ShowDialog(); }; } public static bool? ShowErrorDialog(string message) { return _showErrorDialogFunc(message); } } public class FooViewModel : ViewModelBase { // ViewModel はコマンドを提供 public ICommand LoadCommand { get;set; } public FooViewModel() { LoadCommand = new DelegateCommand(LoadData); } private void LoadData(object param) { var client = new FooServiceClient(); var data = client.GetData(); if (null == data) { // ViewModel の中にダイアログを表示する処理を書いてしまう ViewModelErrorDialog.ShowErrorDialog("取得失敗"); } else { this.Data = data; } } }
(2)メソッドでもいいんじゃない?派
エラー処理でダイアログを出したいときは、コマンドではなくメソッドを ViewModel に用意。ボタンがクリックされたら、View のイベントハンドラ内で ViewModel のメソッドを呼び出す。ダイアログは View が表示。
public class FooViewModel : ViewModelBase { // ...省略... // ViewModel はメソッドを提供 public bool LoadData() { var client = new FooServiceClient(); var data = client.GetData(); if (null == data) { return false; } else { this.Data = data; return true; } } } public class FooView : UserControl { // ...省略... // View は ViewModel のメソッドを呼び出す private void OnLoadButtonClick(object sender, RoutedEventArgs e) { var viewModel = (FooViewModel)DataContext; if (viewModel.LoadData() == false) { new ErrorDialog("取得失敗").ShowDialog(); } } }
(3)その他
(1)(2)以外のステキな方法。例えば、
とか、
を応用したようなもの。
みなさんどうしています?
もしかしたら「今どきダイアログなんて出さないよ」という人もいるかも。
自分は今のところ(2)の方法でやっていますね。シンプルなので。
*1:MessageBox のときもある