質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

1回答

6155閲覧

ViewModelのコマンドでクローズをキャンセルする際のOK/キャンセルの取得

juntaro

総合スコア15

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2018/10/25 07:03

以下の質問をさせてください。
MVVMのWPFアプリケーションにて、ダイアログを表示し、OKボタンが押された時点でチェックを行い、エラー時はメッセージを表示して
ダイアログを終了しないように考えています。

このダイアログの次の作業の為、OKとキャンセルの判別を行いたく、MVVMのコマンドと別にXAMLにClickイベントの処理を追加しましたが、
DialogResultを設定するとViewModelで何もしなくてクローズされてしまいます。
ViewModelのコマンドでクローズする/しないの処理を入れて、OKとキャンセルの判別を行うにはどうすれば良いでしょうか?

初歩的な質問で申し訳ありませんが、よろしくお願いします。

xxxView.xaml

lang

1 <Button Name="OkButton" Content="OK" Command="{Binding OKCommand}" Height="23" Margin="10,0,10,5" Width="80" Click="OkButton_Click"/> 2 <Button Name="CancelButton" Content="キャンセル" Command="{Binding CancelCommand}" Height="23" Margin="0,0,0,5" IsCancel="True" Width="80" Click="CancelButton_Click"/>

xxxView.xaml.cs

lang

1 private void OkButton_Click(object sender, RoutedEventArgs e) 2 { 3 this.DialogResult = true; 4 } 5 6 private void CancelButton_Click(object sender, RoutedEventArgs e) 7 { 8 this.DialogResult = false; 9 } 10

xxxViewMode.cs

lang

1 public void OKCommandDo() 2 { 3 // エラー発生 メッセージ表示後、ウインドウを閉じない 4 return; 5 6 // 保存等の正常処理 7 8 // 終了処理 ウインドウを閉じる 9 Messenger.Raise(new WindowActionMessage(WindowAction.Close, "Close")); 10 } 11

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

MVVM(Commandにバインドする)ならClickイベントハンドラは不要です。
代わりにビヘイビアなどを使ってウィンドウを閉じます。
「MVVM Window close Behavior」で検索すればビヘイビアのサンプルはいくらでも出てきます。

投稿2018/10/25 07:12

編集2018/10/25 07:13
hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

juntaro

2018/10/25 12:14

ご回答ありがとうございます。 その場合、OK/キャンセルの取得って出来ますか? 先日、teratailでOK/キャンセルの取得をしたいと質問した所、Window.DialogResult を使うように回答して頂いたので現状のソースとなっています。 ビヘイビアも調査したつもりですが、OK/キャンセルを取れる操作が発見できませんでした。
hihijiji

2018/10/26 02:17

取得もなにも… あなたがバインドしているOKCommandがOKでCancelCommandがCancelではないのですか?
juntaro

2018/10/26 08:35

説明不足で申し訳ありませんでした。 windowのShowDialogの戻り値でtrue,falseを判別したいということです。
hihijiji

2018/10/26 09:13

MVVMではWindowの参照を持ちませんのでShowDialog出来ません。 ですからShowDialogの戻り値もありません。 Livetを使っているならサンプルも機能も豊富なので先人のやり方に習って下さい。 それとLivetを使っていることは重要な情報ですので必ず質問に書くようにしてください。
juntaro

2018/10/27 06:37

ご回答、ありがとうございました。ShowDialog出来ないというのは、MVVMではShowDialogの戻り値は参照できないということですよね。 申し訳ありませんでした。以後必要な情報は明記するように致します。
hihijiji

2018/10/27 07:16

貴方が提示しているコード内では(他が正しいと仮定して)、イベントハンドラをなくすだけで、質問の最初に書いてある通りの動作をするはずです。 その通りにならないのは、書いてない部分に問題があるのでしょう。
juntaro

2018/10/28 04:20

ありがとうございます。 どういった方法でOK/キャンセルを伝えるのが標準的なプログラミングなのか疑問で質問させて貰いました。 今回はOK、キャンセルのステータスは自分で変数等でセットするって考え方でいこうかと思います。
hihijiji

2018/10/29 01:28

画面の状態を伝えるのではなく、ダイアログでした変更の結果を伝える又は共有します。 根本的なところが違ってます。 繰り返しますが、Livetを使っているならサンプルも機能も豊富なので先人のやり方に習って下さい。
juntaro

2018/10/31 04:28

申し訳ありません。 「画面の状態を伝えるのではなく、ダイアログでした変更の結果を伝える又は共有します。」 が理解できません。 どういう意味でしょうか?
hihijiji

2018/10/31 04:31

繰り返しますが、Livetを使っているならサンプルも機能も豊富なので先人のやり方に習って下さい。
juntaro

2018/10/31 04:45

申し訳ありません。 先人のやり方に習うべく、Liveやビヘイビアも調査し、解決方法が分からなかった為に大変困ってしまい、最初の投稿をさせて頂きました。 「MVVM Window close Behavior」も検索しましたが投稿の解決に至らずです。 根本的な考え方が間違っているのであれば、教えて頂ければと思います。
juntaro

2018/10/31 04:48

追伸: 自分で調べるのが面倒だから誰かに聞いているわけではありません。 調べても解決方法が見つからなかった為にお聞きしています。 お手を煩わせて申し訳ありません。
hihijiji

2018/10/31 04:52

ダイアログの目的は何ですか?
juntaro

2018/10/31 06:23

一連の流れの中で、何らかの処理後、 ダイアログ上で情報を表示し、編集及び確認後に「OK」「キャンセル」をクリックして頂くといった流れです。 「いいえ」は処理を中断。「OK」は編集された情報を回収後(MVVMなので何もしませんが)、処理を続行です。 既に作成している設定関係のダイアログは「OK」「キャンセル」のコマンド時に処理するので、次の処理で何が押されてクローズしたかを確認する必要がありませんが、次工程で「OK」「キャンセル」を取得するにはどうすれば良いのかが分かりません。 勿論、「OK」「キャンセル」のコマンド時に押されたボタンの種類を保持すれば問題なく動作するのでしょうが、 標準的なコーディングや先人のやり方をお聞きしたく質問させて頂きました。
hihijiji

2018/10/31 07:03

「OK」、「キャンセル」、「いいえ」の関係が判りませんが… ダイアログの目的としては、(何かを修正して)続行か中断かの選択ですね? 続行なら何もしなくていいでしょう。 中断を伝えるには変更通知を使うか、Livetだったらメッセンジャーを使うかでしょう?
juntaro

2018/10/31 07:14

申し訳ありません。「いいえ」ではなくキャンセルでした。 ダイアログ関係ではないUIが次の処理で行われる為、ダイアログを閉じる必要があります。 その場合の「OK」「キャンセル」のステータスを取得したいという主旨です。 変更通知、メッセンジャーということはViewに中断を伝えるということですか?
hihijiji

2018/10/31 07:18

>「OK」「キャンセル」のステータスを取得したい 誰が? 変更通知、メッセンジャーはModelでもViewModelでも使ってかまいません。
juntaro

2018/10/31 07:59

本当に言葉足らずで申し訳ありません。 ダイアログを呼び出した側が、「OK」「キャンセル」のどちらを押されたかを取得(確認)したいということです。
hihijiji

2018/10/31 08:05

ダイアログを呼び出した側がModelかViewModelなら「OK」「キャンセル」のどちらを押されたかを取得してはいけません。 「中断」を受け取るようにしてください。
juntaro

2018/10/31 08:19

ダイアログを呼び出した側がModelでもViewModelでもない場合に「OK」「キャンセル」を取得する場合はどうすれば良いでしょうか?
hihijiji

2018/10/31 08:26

ModelでもViewModelでもないのは何なのですか?
Zuishin

2018/10/31 08:31

どうしてそれを取得する必要があるのかっていう話なんじゃないでしょうか。 そのダイアログが編集ダイアログなら、編集するオブジェクトに IEditableObject を実装して OkCommand で EndEdit() を、CancelCommand で CancelEdit() を呼び出せば良いだけのように思いますが、その続きがあるということなんですね? 続きは OkCommand と CancelCommand から呼び出せないものなんですか?
juntaro

2018/10/31 08:33

例えば、フレームワークから呼び出されるコマンドなどですね。
hihijiji

2018/10/31 08:47

コマンドが受け取れるんですか? 普通は誰も引っかからない所で引っかかってるんですよね。 たぶん下手に構築技能があるためにMVVMの基礎の部分を飛ばしていきなり作り始めたのではないでしょうか?
juntaro

2018/10/31 08:50

お時間を取らせて申し訳ありません。 ただ、よく話が見えなくなって来ました。 今ご質問させて頂いているのは、フレームワークのコマンドや、独自のUI等、親にダイアログを持たない状態でダイアログを表示し、「OK」「キャンセル」の取得をしたいだけです。 MessageBoxのYes/Noを取得するのと同じイメージで捉えて頂いて結構です。 MVVMでなければ、ボタンのClickイベントで簡単に取れます。 今質問させて頂いてるのはMVVMの時にどうやってそれを取得するかです。 私、何か根本的な発想がおかしいですか? ダイアログベースのアプリケーションであれば、「OK」「キャンセル」の処理を親ダイアログで確認する必要がないとか、上のModelが処理するとかメッセンジャーを使用とか考えると思います。 本当に初歩的な質問かと思います、よろしくお願いします。
hihijiji

2018/10/31 08:58

上の方でも書きましたが、あなたがバインドしているOKCommandがOKでCancelCommandがCancelではないのですか? 実装しているのはダイアログのVMですね? ダイアログのVMからModelのCancelに対応するものを叩くだけです。
juntaro

2018/10/31 09:05

”コマンドが受け取れるんですか?”とはどういうことですか? WPFアプリケーションが全てダイアログベースとは限らないと思います。 Textエディタアプリケーションやブラウザアプリケーションや、独自UI等、アプリケーションとして呼ばれるものは通常フレームワーク等のダイアログは関係ないUIを持つのではないでしょうか? その中でダイアログを出した際に上記のような初歩的な問題にぶつかりました。 残念ながら有効な文献を発見出来ずに今回の質問をさせて頂きました。 本当に難しくない簡単な事をお聞きしていると思っております。
juntaro

2018/10/31 09:16

例えば、上でも例にあげました、MessageBoxみたいなものを自作した場合などはどうすれば良いでしょうか? MVVMで親がウインドウでない場合、「OK」ボタンを押された事はModelが情報を記憶しておくべきですか?
Zuishin

2018/10/31 09:18

記憶して元の場所に戻るのではなく、そのまま OK の処理をすればいいのではないのですか?
Zuishin

2018/10/31 09:28

例えば終了ダイアログの場合 if (Dialog.ShowDialog()) { Exit(); } else { NextPhase(); } このような処理が頭にあるのではないかと思うのですが、これを OkCommand.Execute() で Exit() CancelCommand.Execute() で NextPhase() このように書き換えるということです。 その場合、コマンド名も OkCommand CancelCommand ではなくもっとふさわしい名前があるでしょう。
juntaro

2018/10/31 10:10

Zuishinさん、ご回答ありがとうございます。 ダイアログベースのアプリケーションではなく、ExcelやWordのようなダイアログベースでないアプリケーションを考えています。 瞬間的に表示したダイアログのコマンド内で、アプリケーションのコマンドを処理するにはダイアログに対する負荷も高くロジックが成立しません。 負荷の高い一連の処理した後、ダイアログを表示し、また負荷の高い一連の処理を行う。 ただ、ダイアログを表示した際のユーザーキャンセル処理もしたい。 その為、ダイアログの「OK」「キャンセル」の判別を行いたいと思っております。 あらためて、お伺いしますが、この疑問ってそんなに難しかったり、誰もひっかからない疑問ですか?
hihijiji

2018/10/31 10:11

Zuishinさんのおかげで、ようやくなんで引っかかっているのか分かったかも 「処理の途中でダイアログを出してダイアログの応答を待っている」 そのためダイアログの参照を保持していたってことですね。 ならば 「処理の途中でダイアログを出して処理は一旦終了」 と 「ダイアログからの応答で処理再開」 に分けて下され
juntaro

2018/10/31 10:22

例えば、検索ボックス(ダイアログ)を出した後、検索する機能を実装した場合に、文字列入れて、『検索』ボタンを押したら検索、『キャンセル』ボタンを押したらユーザーキャンセル。 検索機能をダイアログ内で処理するのも非効率だと思うので、検索ダイアログを表示した側で「OK」「キャンセル」を判別したいというような内容です。 MVVMのダイアログではなければ本当に簡単な内容ですが、MVVMのダイアログを使用した際にどう処理するのが標準的なコーディングなのでしょうか?
hihijiji

2018/10/31 10:35

MVVMを理解したらそんな疑問は湧かないのですよ。 お願いします。 もうちょっと勉強してください。 重ねてお願いします。
Zuishin

2018/10/31 11:09

そのような場合はこう実装したらどうでしょうか? キャンセルダイアログの場合は、ダイアログの View はキャンセルコマンドを送って自らは閉じ、Model はそれを受けて CancellationTokenSource.Cancel() を実行し、処理側の Model はそれで中断します。DialogResult は使いません。 検索の場合は、VM で保持する ObservableCollection をメインウィンドウの DataGrid などにバインドし、検索する時にダイアログを表示します。 検索ダイアログは検索文字列をパラメータとして検索コマンドを VM に送って自らは閉じ、VM は Model に検索指示を送って Model が ObservableCollection を編集します。 ダイアログ内で処理することを心配されていますが、処理するのはダイアログではなく Model で、ダイアログはそれに指示を送るだけにすぎません。 おそらく、Model がしなければならない仕事の多くが ViewModel に割り振られているのではないですか?
juntaro

2018/11/06 08:47

Zuishinさん、ご回答お考え頂き、ありがとうございます。 しつこく聞いて申し訳ありません。時間を使い考えてみましたが、やはりまだ腑に落ちない部分がありまして。 MVVMではない場面からダイアログを表示する際(ダイアログを表示する箇所がModelを持たない)でも同様ですか? 例えば、MVVMではない箇所から、ユーザーに何かを確認する情報を表示し、MessageBoxのように続行するかどうかのメッセージをだして、「はい」「いいえ」のボタンによって処理を進めるかどうかのような場面です。 MVVMでなければシンプルなコーディングで、MVVMでも「はい」「いいえ」のステータスを取得しないのであればかなりシンプルだと思います。 あとはシンプルに「はい」「いいえ」のステータスを取得できればと思っています。
Zuishin

2018/11/06 08:58

それは「MVVM ではない場面」ではなく View だと思います。 詳細がわからないので間違っているかもしれませんが、Model に何の影響も及ぼさないのであれば、多分 View が肥大化しすぎていて設計が悪いと思います。
fsoe

2018/11/07 00:59 編集

一通り読んでみましたがMVVMの基本的なところを勉強なされたほうが早い気がします。回答者の方も仰られていますがClickイベントハンドラは不要だと思います。 「OK/キャンセルを取れる操作が発見できませんでした。」とありますが、ViewでOK、キャンセルを取得しようとしている時点でMVVMから乖離しているのでは。ViewModelであればBindされているコマンドが実行されるのでOK,キャンセルの取得する意味自体ないですよね。
juntaro

2018/11/14 07:19

ご回答、ありがとうございます。 ViewでOK、キャンセルを取得したいわけではありません。 View以外でOK,キャンセルを取得する方法を知りたかったわけです。 勿論、Bindされているコマンドを使用するといった方法は理解しておりますが、その上でダイアログボックスをコールした側にOK,キャンセルが押されたことを返す一般的な方法を質問させて頂いておりました。 そういった質問がMVVMから乖離しているので、一から勉強しなさいということでしたら、この質問は平行線ですね。MVPVMを勉強してみます。
joy1192

2018/12/04 06:41

MVVM=「開発効率を犠牲にしてでも、アプリの具体的な外見・挙動とアプリのコア部分のロジックを分離することによって、保守性や変更容易性を向上させるためのアーキテクチャ」 MVVMにおける一般的な実装方法、というのはほぼ存在しません。 juntaroさんが実際問題としてこのトピックで質問しているのは、「この設計でやったらダメっぽいんですが、どういう設計にしたら良いでしょうか?」という質問と本質的に同じです。 (なので、答えも千差万別です。一般的な設計原則で片付く例でもないので) 何故かというと、MVVMは「アプリのコアロジックと外見の実装を疎結合にするために、データバインディング機構を有効活用した設計をしましょう。こういう概念的な層(M/V/VM)を作るといいね!」という話でしかないので、具体的な方針についてのガイドラインがないからです。 で、具体的な例になるとMVVMの一般的な話がもはや関係なくなり、「MVVMアーキテクチャを採用した上で、どういう設計を行うか?」という話にしかならないため、現場の泥臭い保守性と開発効率バランス、要件、実装のコスト、を考慮した上でのケースバイケースにしかならないのです。 >MVVMではない場面からダイアログを表示する際(ダイアログを表示する箇所がModelを持たない)でも同様ですか? Model層に置く必要が存在しないほど単純なロジックであればView層内だけで完結しても問題ないです。 が、もし検証ロジックが複雑だったり、アプリ状態に依存して動作が変わるなどの要件がある場合には、データ検証や更新、バリデーション、アプリ状態の更新を行う必要があるため、データソースであるModelに処理を依頼して返答を待つ必要があります。 本題の例であれば、[OK][キャンセル]を押した時点でModel層に存在するクラスにまでViewModelを経由して呼び出しを行い、その結果をイベントなり返り値なりでViewModelに認識させ、ViewModelが認識した結果をそのViewに対して有効な手段でNotificationを行ってViewを更新する(=ダイアログの表示更新、入力抑止、ダイアログWindowのClose等)事になります。 Livetはその手段を自分で実装しなくていいように便利クラスを提供しているだけなので、用途に合わない道具であれば使わない判断も必要です。
juntaro

2018/12/10 11:07

joy1192さん、長くご丁寧な回答ありがとうございました。 お返事遅くなり申し訳ありません。 joy1192さんの言われる通り、私はこの質問の手法が分からない訳ではありません。MVVMを理解していない訳でもありません。 ただ一般的な方法はどういう手法かというのを理解したく、質問させて頂きました。 組織で作業を行う際に標準的なコーディングを評定する為の情報を得る為です。 この件に関して、私も色々と考えてみましたが、joy1192さんの言われていることが、まさしくベストアンサーだと思います。 ボタンクリックでModelまで情報を持って行き、バリデーション等を行った結果、有効な手段で伝達する。 手法はケースバイで設計したいと思います。 以前はLivetを使っておりましたが、現在はPrismを使用しております。 今後、MVVMライブラリが何を使うかも不明(Xamarin UWP等の他のフレームワークを使用する為)ということもあり、標準というものに拘っていましたが、どのライブラリを使用しても臨機応変に設計をしていこうと思います。(Prismだとこの辺りの伝達が本当に楽ですが) joy1192さん、本当にありがとうございました。ベストアンサーを上げられず、申し訳ありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問