web-dev-qa-db-ja.com

WPF MVVMダイアログの例

誰かがMVVM(プリズム)を使用してウィンドウダイアログを表示する例を持っていますか? -たとえば、コマンドが実行されたときの構成設定ウィンドウ。

私が見たすべての例は、問題のないメディエーターパターンを使用していますが、それらはすべて、理想的ではないビューモデルのビューへの参照も持っています(DataTemplatesを使用しています)。

ありがとう

28
Oll

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

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メソッドと同様に、closeに対してtrue、false、nullを返します。実装は、コンテナからTViewタイプの新しいビューを作成し、それを提供されたViewModelにフックして表示します。

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

コンテンツコントロールを含む標準のダイアログウィンドウがあります。 ShowDialogが呼び出されると、新しい標準ダイアログが作成され、ビューがコンテンツコントロールに追加され、ViewModelが接続されて表示されます。標準ダイアログには、IDialogViewModelから適切なメソッドを呼び出すための適切なロジックを備えた[OK]ボタンと[Cancel]ボタンがすでにあります。

23

これを行う方法は、メディエーターパターンも使用することです。 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();
}

これがあなたにアイデアを与えるのに十分であることを願っています...

13
Grokys

MVVMパターンに従ってダイアログを表示するサービスを使用することが最も単純なソリューションであることに同意します。しかし、私は自分のプロジェクトにも3つのアセンブリがあるかどうかも質問しました。Model、ViewModel、View、およびMVVMパターンによると、アセンブリViewModelはModelへの参照を持ち、ViewはModelとViewModelの両方にDialogServiceクラスを配置する必要がありますか? ViewModelアセンブリに配置する場合-DialogViewインスタンスを作成する機会はありません。一方、DialogServiceをビューアセンブリに配置する場合、ViewModelクラスにどのように注入する必要がありますか?

したがって、私は Prismを使用した高度なMVVMシナリオを検討することをお勧めしますパート:相互作用要求オブジェクトの使用

このアプローチの例として:

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>
3

上記のコメントを理解したように、問題はダイアログを表示することではなく、ダイアログを非表示にすることではありません。この問題を解決するには2つの方法があります。

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

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

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

    このシナリオでは、ViewとオーバーレイのVisibilityは、ViewCommandのIsVisibleプロパティにバインドされます。これは、SaveCommandの実装によって、またはViewModelがViewを表示する必要があるときに設定されます。

最初のアプローチでは、コードビハインドに少しコードを含める必要があり、グローバルイベントを追加する必要があり、(おそらく)MVVM風ではありません。 2番目のアプローチでは、オーバーレイの実装(または他の誰かの実装を使用)が必要になりますが、コードビハインドにコードを含める必要はなく、グローバルイベントを必要とせず、(引数)よりMVVM風です。

2
PL.

これはPrismではありませんが、これ MVVMデモ には、完全にMVVMであるオプションダイアログがあります。

0
Scott Whitlock

次のサンプルアプリケーションに興味があるかもしれません。

http://compositeextensions.codeplex.com

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

0
jbe