MVVMを使用してビューモデルのビューを閉じる賢い方法に出会った人はいますか?
バインディングを使用して、ビュー(ウィンドウ)を閉じるように通知する方法があるのでしょうか?
誰もが入力を本当に感謝します。
基本的に、ログインモデルがバインドされているloginViewがあり、viewmodelで(コマンドのバインディングを使用して)ログインが成功するかどうかをテストし、基本的に新しいビュー(mainview)をロードしてそのデータコンテキストを添付します。 ..
しかし、私はまだloginViewが表示されているので、アンロードするように通知する必要があります。
また、他の状況でこの種のことを行う必要があると確信しているため、一般的なソリューションも期待していました
何か案は?
Edit:より詳細な説明については 私のブログ投稿 を参照してください。
それを達成する必要があるときは、作成したIRequestCloseViewModelインターフェイスを使用します。
このインターフェイスには、RequestCloseというイベントが1つだけ含まれています。このイベントは、関連付けられているビューを閉じたいときに、ViewModel(ViewModelBaseクラスを継承し、IRequestCloseViewModelを実装)によって発生します。
私のアプリでは、すべてのWindowは抽象クラスApplicationWindowを継承しています。この抽象クラスは、DataContextが変更されるたびに通知され、ハンドラーでDataContextがIRequestCloseViewModelをサポートするかどうかをチェックします。この場合、イベントが発生したときにウィンドウを閉じるようにイベントハンドラーが設定されます。
あるいは、Kentが言ったように、外部クラスでこのメカニズムを処理するスクリーンコントローラーを使用できます。
使用しているMVVMフレームワークはわかりませんが、ほとんどの場合、送信されるメッセージを簡単に登録できる何らかのメッセージング/通知ソリューションが含まれています。ビューが "CloseWindowsBoundTo"などのメッセージとviewModelを送信者として登録できなかったと想像できる理由はありません。ビューで、そのメッセージに登録するだけで、現在のデータコンテキストを送信者と比較できます。一致する場合は、ウィンドウを閉じます。
シンプルで、ビューモデルからビューを抽象化します。
MVVM-lightツールキットを使用した私のアプローチは次のとおりです。
ViewModelで:
public void notifyWindowToClose()
{
Messenger.Default.Send<NotificationMessage>(
new NotificationMessage(this, "CloseWindowsBoundToMe")
);
}
そしてビューで:
Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
if (nm.Notification == "CloseWindowsBoundToMe")
{
if (nm.Sender == this.DataContext)
this.Close();
}
});
以前はdialogcloserに添付されたビヘイビアを使用していましたが、使用できる場合は以下のソリューションが簡単であることがわかりました。以下のサンプルでは、簡単にするためにウィンドウ上の閉じるボタンの例を取り上げます。
コマンドパラメータとしてウィンドウを渡します。
ビューのxamlボタンで:
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
ビューモデルのコマンドexecuteメソッドで:
if (parameter is System.Windows.Window)
{
(parameter as System.Windows.Window).Close();
}
一般に、何らかの種類のコントローラー/プレゼンター/サービスを使用して、画面のアクティブ化/非アクティブ化を行います。 MVVMは、すべてを支配する1つのパターンであることを意図していません。重要なアプリケーションでは、他のパターンと組み合わせる必要があります。
とはいえ、状況によっては、子ビューモデルのライフサイクルを管理するビューモデルを持つことが理にかなっています。たとえば、子ビューモデルのコレクションを管理するEditorViewModel
があります-編集中のドキュメントごとに1つです。その場合、このコレクションに追加/削除するだけで、ビューがアクティブ化/非アクティブ化される可能性があります。しかし、これはユースケースに合うようには聞こえません。
http://adammills.wordpress.com/2009/07/01/window-close-from-xaml/
<Style.Triggers> <DataTrigger Binding="{Binding CloseSignal}" Value="true"> <Setter Property="Behaviours:WindowCloseBehaviour.Close" Value="true" /> </DataTrigger> </Style>
ウィンドウにアタッチし、実行時にウィンドウを閉じるコマンドを作成できます。次に、そのコマンドをビューモデルのプロパティにバインドし、ウィンドウを閉じるときにコマンドを実行できます。
LoginViewModelをインスタンス化し、LoginViewを表示するApplicationControllerを使用します。ユーザーがログイン画面に進むと、ApplicationControllerはLoginViewを閉じ、MainViewModelでMainViewを表示します。
これを行う方法は、 WPF Application Framework(WAF) プロジェクトのサンプルアプリケーションに示されています。
コードビハインドのEventHandlerを閉じて、コマンドバインディングを使用できるビューモデルの他のすべてを処理します。
この答えは、これを行う別の方法を示しています。
添付プロパティを使用して、DialogResultウィンドウプロパティをViewModelプロパティにバインドします。 DialogResultの値をtrueまたはfalseに設定すると、ビューが閉じられます。
イベントを使用してこれを行うこともできます。ビューコードビハインドには3行のコードが必要ですが(MVVMの純粋主義者の中には、これが気に入らない人もいます)
ビューモデルで、ビューがサブスクライブできるイベントを作成します。
public event CloseEventHandler Closing;
public delegate void CloseEventHandler();
private void RaiseClose()
{
if (Closing != null)
Closing();
}
以下のように、ビューで、initializecomponentメソッドの後にイベントをサブスクライブします。
public View
{
*//The event can be put in an interface to avoid direct dependence of the view on the viewmodel. So below becomes
//ICloseView model = (ICloseView)this.DataContext;*
ProgressWindowViewModel model = (ProgressWindowViewModel)this.DataContext;
model.Closing += Model_Closing;
}
private void Model_Closing()
{
this.Close();
}
ViewModelからビューを閉じる準備ができたら、単にRaiseClose()を呼び出すだけです。
このメソッドを使用して、ビューモデルからビューにメッセージを送信することもできます。
イベントをインターフェイスに配置して、ビューモデルへのビューの直接依存を回避できます。
ビューモデルからビューを閉じるには、ここからダウンロードできるGalasoft MVVM Light Toolkitを使用しました。 http://www.mvvmlight.net/
次のようなクラスを作成します。public class ClosingRequested:MessageBase {}
ビューコンストラクタにこれを追加します:Messenger.Default.Register(this、vm、msg => Close());
これを呼び出してウィンドウを閉じます:Messenger.Default.Send(new ClosingRequested()、this);