私はWPF MVVMアプリケーションに取り組んでいます。データグリッドにいくつかのデータを表示しています。選択したレコードを追加および編集するための 2 つのボタンがあります。ViewModel にデータがあり、別のウィンドウ (ビュー) を表示して、ViewModel にビューに関する情報がないようにする必要があります。ビューとビューモデルはどこに作成すればよいですか? データを取り戻してデータグリッドを更新する方法は? MVVMでこれを達成するにはどうすればよいですか? フレームワークを使用することはまだ決定していないため、独自のインターフェイスを作成する必要があります。
2 に答える
注:これは非常に長い回答になりました-不明な点があれば質問してください
ダイアログ ウィンドウの実装は、MVVM の設計において論争の的となっている問題であり、さまざまな人がさまざまなアプローチを使用しています。
あなたと同じように、私はフレームワークを使用せず、ほとんどのものを手作業で実装することにしました。ダイアログ ウィンドウに関しては、ViewModel 内からダイアログ ウィンドウを起動することで、MVVM の実装について実用的にすることを選択します。また、各 Dialog ViewModel が表示されている Window への参照を持つことを許可しているため、必要に応じて閉じることができます (詳細は以下を参照)。これは、厳密な MVVM の「ルール」の一部を破りますが、仕事は完了します。
これの主な欠点は、ダイアログを通過するものをテストしている場合、単体テストが壊れる可能性があることです。ただし、その問題に遭遇することなく長い道のりを歩むことができ、まだ私を悩ませていません.
簡単に拡張できるダイアログ ViewModel のライブラリを少し作成しました。ここに投稿するにはコードが多すぎますが、ハイライトを示します。
ダイアログのベース ViewModel
私の各ダイアログ ウィンドウには、 から継承する ViewModel があります。これは、などをサポートするという点でDialogViewModelBase
私の通常のウィンドウに似ています。興味深い部分は、このパブリック メソッドであり、ダイアログを起動するためにどこからでも呼び出すことができます。ViewModelBase
INotifyPropertyChanged
/// <summary>
/// Creates window instance for this dialog viewmodel and displays it, getting the dialog result.
/// </summary>
public void ShowDialogWindow()
{
// This is a property of the DialogViewModelBase class - thus, each DialogViewModel holds a reference to its own DialogWindow:
this.DialogWindow = new Dialogs.Views.DialogWindow();
// Tell the DialogWindow to display this ViewModel:
this.DialogWindow.DataContext = this;
// Launch the Window, using a method of the Window baseclass, that only returns when the window is closed:
this.DialogWindow.ShowDialog();
}
Window.DialogResult
上記のメソッドで起動されたウィンドウは、そのプロパティが設定されると閉じます。DialogWindow
これがクラスのプロパティである理由ですDialogViewModelBase
。サブクラス化ダイアログViewModel
がダイアログ ウィンドウを閉じたい場合、単純に結果を設定します。
protected void CloseDialogWithResult(bool dialogWindowResult)
{
// Setting this property automatically closes the dialog window:
this.DialogWindow.DialogResult = dialogWindowResult;
}
ダイアログ ビューのホスト ウィンドウ
メソッドがインスタンス化するDialogs.Views.DialogWindow
クラスShowDialogWindow
は XAML で定義され、 のサブクラスですWindow
。これには 2 つの重要な機能があります。1 つ目は、その主要なコンテンツ要素が単にContentControl
現在のコンテキストにバインドされる であるということです。これにより、Views
の異なるサブクラスに対して異なる定義を行うことができ、 はコンテキストのタイプに基づいて対応するものをホストします。DialogViewModelBase
DialogWindow
View
<ContentControl Content="{Binding}" /> <!-- In reality this is inside a border etc but its simplified here for demonstration -->
DialogWindow
XAMLの 2 番目の重要な機能は、どのダイアログViews
がどのダイアログと連動するかを定義することViewModels
です。以下にサンプルを示します。
<Window.Resources>
<!-- DEFAULT ViewModel-View TEMPLATES -->
<DataTemplate DataType="{x:Type dialogs:YesNoMessageBoxDialogViewModel}">
<views:MessageBoxView />
</DataTemplate>
<DataTemplate DataType="{x:Type dialogs:ErrorDialogViewModel}">
<views:ErrorDialogView/>
</DataTemplate>
</Window.Resources>
これがすべて行うことは、ダイアログをサブクラスとして定義してfor eachDialogViewModelBase
を実装し、どのダイアログに対してどのダイアログを表示する必要があるかを伝えることができるということです。View
DialogWindow
View
ContentControl
ViewModel
ダイアログを起動して結果を取得する
ViewModels
以下は、作成するアセット タイプをユーザーが選択できるダイアログ ウィンドウを起動するアプリケーションの 1 つのサンプルです。
public void CreateNewAsset()
{
// Instantiate desired Dialog ViewModel:
Dialogs.NewAssetTypeSelectionDialogViewModel dialog = new Dialogs.NewAssetTypeSelectionDialogViewModel();
// Launch Dialog by calling method on Dialog base class:
dialog.ShowDialogWindow();
// Execution will halt here until the Dialog window closes...
// The user's selection is stored in a property on the dialog ViewModel, and can now be retrieved:
CalculatorBase.AssetTypeEnum newAssetType = dialog.AssetType;
switch (newAssetType)
{
// Do stuff based on user's selection...
}
}
PS: これについてブログ エントリを書く必要があります。ブログ エントリにはおそらくより完全なコード サンプルがあるため、ここにリンクを投稿します。
データをどのように扱っているかによって異なります。ポップアップウィンドウで行われた変更は、ユーザーが保存などをクリックした場合にのみ受け入れることができ、それ以外の場合は破棄する必要があると想定します。まず、コントローラーはそのようなタスクに最適であるため、MVC アプローチを使用することをお勧めします。その中にビューモデルを構築し、それらをビューに割り当てて、ビューを表示します。VM は単にデータとコマンドを保持し、コマンド実行メソッドはコントローラーに保持されます。つまり、VM とビューを管理するシングルトン クラスがあります。Prismフレームワークをチェックアウトする必要があります。ランタイムにさまざまなユーザー コントロールを挿入できるビュー リポジトリ、IOC および DI パターンと一緒にすぐに使用できるコマンドと MVC レイヤリングなどの優れた機能を提供します。