2009-11-03 20 views
25

MVVM(Prism)を使用してウィンドウダイアログを表示する例はありますか?たとえば、コマンドが実行されるときの構成設定ウィンドウ。WPF MVVMダイアログ例

私は結構ですMediatorパターンを使用して見てきた例のすべてが、彼らはまた、すべての(私たちはDataTemplatesを使用している)は理想的ではないビューモデルのビューへの参照を持っている

感謝

答えて

12

私がこれを行う方法は、メディエーターパターンも使用しています。 ViewModelがダイアログを表示したい場合、ViewModelはアプリケーションのメインウィンドウで選択されたメッセージを送信します。メッセージには、ダイアログで使用されるViewModelのインスタンスが含まれています。

メインウィンドウは、ダイアログウィンドウのインスタンスを構築し、ビューモデルを渡してダイアログを表示します。ダイアログの結果は元のメッセージの呼び出し元に戻されます。あなたのビューモデルで

:メインウィンドウの分離コードで

DialogViewModel viewModel = new DialogViewModel(...); 
ShowDialogMessage message = new ShowDialogMessage(viewModel); 

_messenger.Broadcast(message); 

if (message.Result == true) 
{ 
    ... 
} 

:私はこれがあなたのアイデアを与えるのに十分であると思います

void RecieveShowDialogMessage(ShowDialogMessage message) 
{ 
    DialogWindow w = new DialogWindow(); 
    w.DataContext = message.ViewModel; 
    message.Result = w.ShowDialog(); 
} 

それは次のようになります。 ..

+0

答えをありがとう。以下のシナリオを明確にしてください。 DialogWindowで、保存およびキャンセルコマンドを使用してビューモデルを表示するとします。ユーザーがビュー(SaveCommandにバインドされている)で「保存」をクリックすると、検証がいくつか実行され、構成が保存されることになります。 私は、VMがビューのDialogResultをどのように設定するか(つまり、ダイアログを閉じる)の周りに頭を浮かべることはできません。 もう一度ありがとうございます。 – Oll

+0

抽象化を破ることなく、ビューとやりとりするVMを取得する方法はたくさんあります。たとえば、ダイアログビューモデルの基本クラスには、通常、ダイアログを少し簡単に表示するための基本プロパティとメソッドがあります(通常、ビューロードで実行するメソッドのようなものも含むダイアログビューモデルのインターフェイスがあります)ダイアログの結果として、コミット/アボートコマンドなど)。ビューを閉じて閉じるようにビューモデルを取得する簡単な方法は、プロパティを公開することです(CanCloseなど)。 – Egor

+0

次に、ダイアログに対応する依存関係プロパティを作成し、datacontextの変更によって2つのバインディングが設定されると、バインドされたプロパティの変更されたイベントハンドラのロジックを処理できます。また、ダイアログのviewmodelに "close"イベントを単に公開する方が簡単で、ダイアログ・ウィンドウのデータ・コンテキスト変更ハンドラでこのイベントをサブスクライブすると、適切なダイアログ結果を割り当ててウィンドウを閉じることができます。 – Egor

0

あなたは次のサンプルアプリケーションに興味があります:

http://compositeextensions.codeplex.com

はPresentationModel(別名MVVM)パターンでPrism2を使用します。サンプルアプリケーションにはモーダルダイアログが含まれています。

2

私は上記のあなたのコメントを理解していたので、ダイアログはそれらを非表示として表示するほどの問題ではありません。この問題を解決する方法は2つあります。

  1. 標準のダイアログウィンドウを使用してビューを実装します。これには、ViewModelがViewへの参照を持たずに閉じることがViewに通知できるように、ViewModelとの間の疎結合の通信方法が必要です。

    これには複数のフレームワークが存在します.Prismのイベントアグリゲーターはその1つになります。このシナリオでは、Viewはイベント(MyDialogResultValidatedなど)をサブスクライブし、イベントを受け取るとDialogResultを肯定的に設定します。検証が成功した場合、ViewModel(そのSaveCommand内)はイベントを発生させます。

  2. 標準のダイアログウィンドウを使用してビューを実装しないでください。これには、モダリティを効果的にエミュレートするオーバーレイが必要です。

    このシナリオでは、ビューおよびオーバーレイの可視性は、SaveCommand実装に応じて設定されるViewModelのIsVisibleプロパティにバインドされます。または、ViewModelがビューを表示する必要があるときはいつでも。

最初のアプローチは、コードビハインドのコードのビットを持つ必要とする、グローバルイベント(単数または複数)を追加する必要があり、(おそらく)以下MVVMっぽいあります。2番目のアプローチでは、オーバーレイの実装(または他の誰かの実装の使用)が必要ですが、コードビハインドでコードを持つ必要はなく、グローバルイベントを必要とせず、さらに議論の余地がありますMVVM-ish 。

21

サービスを使用してダイアログを表示します。このサービスはビューをビューモデルとリンクすることもできます。

public interface IDialogService { 
    void RegisterView<TView, TViewModel>() where TViewModel:IDialogViewModel; 
    bool? ShowDialog(IDialogViewModel viewModel); 
} 

public interface IDialogViewModel { 
    bool CanClose(); 
    void Close(); 
} 


RegisterViewだけのViewModelタイプとビュータイプをリンクします。これらのリンクは、モジュールの初期化で設定できます。これは、アプリケーションの最上位層にデータ・テンプレートを登録するモジュールを取得しようとするより簡単です。

ShowDialog表示するViewModelを表示します。 Window.ShowDialogメソッドのように、true、false、nullを返します。実装はコンテナからタイプTViewの新しいビューを作成し、それを提供されたViewModelにフックして表示します。

IDialogViewModelは、検証を行いダイアログの終了をキャンセルするためのViewModelのメカニズムを提供します。

標準のダイアログウィンドウがあり、その中にコンテンツコントロールがあります。 ShowDialogが呼び出されると、新しい標準ダイアログが作成され、コンテンツコントロールにビューが追加され、ViewModelがフックアップされて表示されます。標準ダイアログには適切なロジックを持つ[OK]と[キャンセル]ボタンが既にあり、IDialogViewModelから正しいメソッドを呼び出すことができます。

+0

こんにちはキャメロン! OKまたはCancelが押されたかどうかは、ビューからどのように通知されますか? –

+0

標準的な方法です。 'ShowDialog'のコード実装は、表示する必要があるViewを見つけて、そのViewで' ShowDialog'を呼び出し、結果を戻します。 –

+0

IDIalogViewModel内のプロパティの変更は、標準ダイアログの[OK]および[キャンセル]ボタンにバインドされたコマンドのCanExecuteの評価をどのようにトリガしますか? InvalidateRequerySuggested? – jan

0

これはプリズムではありませんが、このMVVM demoには完全にMVVMのオプションダイアログがあります。

2

MVVMパターンに従ってダイアログを表示するサービスを使用することが最も簡単な解決策であると私は同意しました。しかし、私のプロジェクトModel、ViewModel、Viewに3つのアセンブリがあり、MVVMパターンアセンブリに従ってViewModelにModelへの参照があり、ModelとViewModelの両方への表示でDialogServiceクラスを配置する必要がありますか? ViewModelアセンブリに配置する場合は、DialogViewインスタンスを作成する機会はありません。一方、ViewアセンブリにDialogServiceを配置する場合、ViewModelクラスにDialogServiceを挿入する方法はありますか?

だから、私はAdvanced MVVM scenarios with Prismパートを見てrecomentう:対話要求を使用すると、このアプローチの例として

オブジェクト:

DialogViewModelBase

public abstract class DialogViewModelBase : ViewModelBase 
{ 
    private ICommand _ok; 

    public ICommand Ok 
    { 
     get { return _ok ?? (_ok = new DelegateCommand(OkExecute, CanOkExecute)); } 
    } 

    protected virtual bool CanOkExecute() 
    { 
     return true; 
    } 

    protected virtual void OkExecute() 
    { 
     _isSaved = true; 
     Close = true; 
    } 

    private ICommand _cancel; 

    public ICommand Cancel 
    { 
     get 
     { 
      return _cancel ?? (_cancel = new DelegateCommand(CancelExecute, CanCancelExecute)); 
     } 
    } 

    protected virtual bool CanCancelExecute() 
    { 
     return true; 
    } 

    protected virtual void CancelExecute() 
    { 
     Close = true; 
    } 

    private bool _isSaved = false; 
    public bool IsSaved 
    { 
     get { return _isSaved; } 
    } 

    private bool _close = false; 

    public bool Close 
    { 
     get { return _close; } 
     set 
     { 
      _close = value; 
      RaisePropertyChanged(() => Close); 
     } 
    } 
} 

CreateUserStoryViewModel:

public class CreateUserStoryViewModel : DialogViewModelBase 
{ 
    private string _name = String.Empty; 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      _name = value; 
      RaisePropertyChanged(() => Name); 
     } 
    } 
} 

CreateUserStoryRequest

private InteractionRequest<Notification> _createUserStoryRequest; 
public InteractionRequest<Notification> CreateUserStoryRequest 
{ 
    get 
    { 
     return _createUserStoryRequest ?? (_createUserStoryRequest = new InteractionRequest<Notification>()); 
    } 
} 

CreateUserStoryコマンド

private void CreateUserStoryExecute() 
{ 
    CreateUserStoryRequest.Raise(new Notification() 
    { 
     Content = new CreateUserStoryViewModel(), 
     Title = "Create User Story" 
    }, 
    notification => 
       { 
         CreateUserStoryViewModel createUserStoryViewModel = 
           (CreateUserStoryViewModel)notification.Content; 
         if (createUserStoryViewModel.IsSaved) 
         { 
         _domainContext.CreateUserStory(
new UserStory(){ Name = createUserStoryViewModel.Name, }); 
         } 
       }); 
} 

XAML:

<!--where xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
      xmlns:ir="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"--> 

<i:Interaction.Triggers> 
    <ir:InteractionRequestTrigger SourceObject="{Binding CreateUserStoryRequest}"> 
    <ir:PopupChildWindowAction> 
     <ir:PopupChildWindowAction.ChildWindow> 
     <view:CreateUserStory /> 
     </ir:PopupChildWindowAction.ChildWindow> 
    </ir:PopupChildWindowAction> 
    </ir:InteractionRequestTrigger> 
</i:Interaction.Triggers> 
+0

Vladimir:私はアプローチを試みましたが、それは私のために働いていません。何が_domainContextであるかを精緻化できますか?私のシナリオは、テキストボックス、ラベル、pdfviewerを持つモーダルダイアログを開いています。私はModalDialogのdatacontext [ieを変更する必要があります。これらの値をボタン(トリガー)のクリックに応じてビューモデルとして渡します。任意のアイデアや参照が役立つだろう...ありがとう –

+0

私のサンプルの_domainContextはリポジトリの並べ替えです。これは単なる例であり、WCFサービスコールで置き換えるか、ディスクに保存することができます。このサンプルはあなたのシナリオで動作します。 CreateUserStoryViewModelをTitle、Textなどのプロパティを持つ独自のModalDialogViewModelに置き換える必要があります。これらのプロパティをModalDialogViewのLabelおよびPdfViewerにバインドします(CreateUserStoryビューの代わりにModalDialogViewを使用する必要があります)。 –

+0

これはWPFでは動作しません。 要素は存在しません。しかし、それはSilverlightで行います。 –