2017-01-21 6 views
2

MVVMパターンを守っている間にダイアログを開くことは、定期的な質問(ここや他の箇所)の1つと考えられます。 MVVMのようなフレームワークがあることは知っていますが、私はその問題の答えを持っていますが、私は現在、学習のために自分で大部分の作業をしようとする非常に小さな個人的なプロジェクトに取り組んでいます。MVVMを強制するビューモデルのプロジェクトを別にする:どのようにダイアログを開くのですか?

私は参照に注意を払うために、UIプロジェクトからビューモデルを抽出し、別のアセンブリに配置することにしました。 UIプロジェクトはUI.ViewModelsを参照しますが、それ以外の方法では参照できません。これは、私にはダイアログウィンドウを開く(モーダル)に問題がありました。

多くの人々はの線に沿って何かをしDialogServiceを使用しているように見える:

internal class DialogService : IDialogService 
{ 
    public bool? OpenDialog(ViewModelBase vm) 
    { 
    Window window = new Window(); 
    window.Content = vm; 
    return window.ShowDialog(); 
    } 
} 

対応するウィンドウの内容がDataTemplateを使用して、ビューモデルタイプから推測することができます。

私のシナリオでは、DialogServiceがUIプロジェクトにある必要があるため、これは機能しませんが、ビューモデルから呼び出す必要があります。もちろん、DI/IoCを悪用してIDialogServiceの実装をビューモデルに挿入することもできますが、それは私がしたいことではありません。

これを動作させる厳密な方法はありますか?代替案として

、私は私のViewModelBaseに次のコードを追加しました:

明らか
public abstract class ViewModelBase : INotifyPropertyChanged 
{ 
    ... 

    public event Action<ViewModelBase, Action<bool?>> Navigate; 

    protected virtual void OnNavigate(ViewModelBase vm, Action<bool?> callback) 
    { 
    Navigate?.Invoke(vm, callback); 
    } 
} 

を、その上でより多くの過負荷、他のパラメータ、EventArgsとがあるかもしれません。私はおそらくインターフェイスにこれを置くべきでしょう。しかし、これまでのところ「思考」に過ぎません。

(たとえば、NavigationServiceで解決するか、下記を参照して)ビューインスタンスを作成するときに、NavigationServiceにそのイベントを登録させてコールバックを呼び出すことができます。 これは問題のある/悪い考えですか?これの短所は何ですか?これまで(あまりテストしなかった)私が気に入らないことの1つは、ダイアログを開いた後に次の行に進むことができず、コールバックコード内で続行する必要があるということです。それはまた、コードを読むことによってプログラムの流れに従うことをより困難にする。

ご迷惑をおかけして申し訳ありません。これは非常に興味深い話題です.SOに関するこれらの質問に対する多くの回答がかなり古いので、現在のベストプラクティスについてもっと学びたいと思っています。

+0

MVVM(https://www.youtube.com/watch?v=OqKaV4d4PXg)のダイアログを使用して、私の最近のビデオを見たい場合があります。これは一般的な問題ですが、比較的簡単に解決できます。サービスロケータパターンやその他の方法を使用することもできるため、サービスの注入方法(または使用方法)を決める必要があります。注射だけではありません。 –

答えて

1

IDialogServiceを実装しているクラスをビューモデルに注入するのはなぜIoCですか?私はこれを行うには良い方法だと思います。

これを考え直してはいけません。ビューとロジックプロジェクトを分離するのは良いアイデアです。あなたの作品は何でも使えます。

私の最後のプロジェクトでは、ReactiveUIフレームワークのInteractionクラスを使用しました。これは、ダイアログとファイルピッカーでうまく動作します。私はそれがあなたの選択に非常に似ていると思う、あなたはcodeexamplesをチェックすることができます。

Reactive Extensionsを使用していますが、あなたはその考えを得るべきです。

+0

参照構造が与えられているので、私のビューモデルではそこに置かれたり、共有/共通のプロジェクトに置かれたりせずに、 'IDialogService'というインターフェースを知ることができません。しかし、このインターフェースを実装するには、ウインドウが表示されるため、* UIプロジェクト内に*存在する必要があります。これはちょうど私にとって「正しい」とは思われませんが、むしろ欠けているプロジェクト参照を回避する方法と似ています。私はあなたが明日提供したリンクを見ていきます、ありがとう! – InvisiblePanda

+0

viewmodelsプロジェクトにIDialogServiceインターフェイスを置くのはなぜですか?あなたのビューモデルは、UIを使用してプログラムを実行するために使用できる必要があります。そのため、そこに置くのは自然です。もちろん、インプリメンテーションはUIプロジェクト内になければなりません。つまり、ビューモデルからのUI依存関係を取り除き、UIとやりとりするためのインターフェースを提供することです。 –

+0

あなたは私を納得させようとしています;)UIプロジェクトの実装をUI.ViewModelsのインターフェイスに登録するのはまだ私にとっては奇妙ですが、それは正しいと思われます...また、最初に取得した最上位VMのIDialogServiceを渡すことによって、VMから新しいビューモデルインスタンスを作成することもできます。 上記のイベント主導のアイデアについてご意見はありますか? – InvisiblePanda

1

私のシナリオでは、DialogServiceはUIプロジェクト内にある必要があるため、これは機能しませんが、ビューモデルから呼び出す必要があります。

IDialogService インターフェイスは、ビューモデルプロジェクトで定義する必要があります。ビューモデルはこのインタフェースについてのみ知っているので、実際にダイアログを作成せずに単にbool?を返す単体テストで模擬実装を簡単に提供できます。

IDialogServiceの具体的な実装、つまりウィンドウを作成するDialogServiceクラスは、UIプロジェクトで実装する必要があります。

もちろん、DI/IoCを使用してIDialogService実装をビューモデルに挿入することもできますが、これは私がしたいことではありません。

これは、従属性の注入パターンの悪用ではありません。むしろ典型的で正しい使い方です。私はそれを自分で使用し、それは不思議に作用します。

何らかの種類のダイアログ機能を提供するためにビューモデルの基本クラスを拡張する代わりのソリューションは、ちょっと面倒で、間違っているようです。私は実際にダイアログサービスを必要とするすべてのビューモデルにIDialogServiceインターフェイスを注入することに固執します。これは他のサービスと一緒に注入するのと同じです。

+1

ありがとう、私はそれを今日考えていたほど、それはより多くクリアされました!そして、はい、私は実際に仕事を嘲笑するのが好きです。私がまだ見ていた唯一の「問題」(上記の2番目のコメントを参照)は、別のVMで新しいVMインスタンスを作成する方法でした。しかし、ビューモデルはすでに 'IDialogService'オブジェクトを持っているので、単にそれらを渡すことができます。 – InvisiblePanda

+0

はい、まさに:) – mm8

関連する問題