web-dev-qa-db-ja.com

階層ビュー/ ViewModel / MVPVMのプレゼンター

しばらくMVVMを使用していますが、最近MVPVMの使用を開始しました。このパターンを使用して階層的なView/ViewModel/Presenterアプリを作成する方法を知りたいです。

MVVMでは、通常、ビューの階層と対応するViewModelを使用してアプリケーションを構築します。次のように3つのビューを定義します。

View A

これらのビューのビューモデルは次のようになります。

public class AViewModel
{
    public string Text
    {
        get { return "This is A!"; }
    }

    public object Child1 { get; set; }    
    public object Child2 { get; set; }
}

public class BViewModel
{
    public string Text
    {
        get { return "This is B!"; }
    }
}

public class CViewModel
{
    public string Text
    {
        get { return "This is C!"; }
    }
}

次に、ビューBとビューCを使用してBViewModelとCViewModelを表示する必要があることを示すいくつかのデータテンプレートがあります。

<DataTemplate DataType="{StaticResource local:BViewModel}">
    <local:BView/>
</DataTemplate>
<DataTemplate DataType="{StaticResource local:CViewModel}">
    <local:CView/>
</DataTemplate>

最後のステップは、Child1とChild2に値を割り当てるコードをAViewModelに配置することです。

public AViewModel()
{
    this.Child1 = new AViewModel();
    this.Child2 = new BViewModel();
}

これらすべての結果、次のような画面が表示されます。

enter image description here

MVPVMでこれを行うのはかなり簡単です。AViewModelのコンストラクターのコードをAPresenterに移動するだけです。

public class APresenter 
{
    ....
    public void WireUp()
    {
        ViewModel.Child1 = new BViewModel();
        ViewModel.Child2 = new CViewModel();
     } 
}

しかし、BViewModelとCViewModelのビジネスロジックが必要な場合は、BPresenterとCPresenterが必要になります。問題は、これらを配置するのに最適な場所がどこかわからないことです。

AViewModel.Child1およびAViewModel.Child2のプレゼンターへの参照をAPresenterに保存できます。

public class APresenter : IPresenter
{
    private IPresenter child1Presenter;
    private IPresenter child2Presenter;

    public void WireUp()
    {
        child1Presenter = new BPresenter();
        child1Presenter.WireUp();
        child2Presenter = new CPresenter();
        child2Presenter.WireUp();

        ViewModel.Child1 = child1Presenter.ViewModel;
        ViewModel.Child2 = child2Presenter.ViewModel;
    }
}

しかし、このソリューションはMVVMアプローチに比べて洗練されていないようです。プレゼンターとビューモデルの両方を追跡し、それらが常に同期していることを確認する必要があります。たとえば、ビューAにボタンが必要な場合、クリックすると、Child1とChild2のビューが入れ替わり、次のコマンドを実行できます。

var temp = ViewModel.Child1;
ViewModel.Child1 = ViewModel.Child2;
ViewModel.Child2 = temp;

これは、画面のビューを交換する限り機能します(正しいプロパティ変更通知コードが配置されていると想定)。ただし、今度はAPresenter.child1PresenterがAViewModel.Child2のプレゼンターを指し、APresenter.child2PresenterがAViewModel.Child1。何かがAPresenter.child1Presenterにアクセスする場合、変更は実際にはAViewModel.Child2に発生します。これがあらゆる種類のデバッグの楽しみにつながると想像できます。

私はパターンを誤解している可能性があることを知っています。これが事実である場合、イムが間違っていることを明確にしていただければ幸いです。

[〜#〜] edit [〜#〜]-この質問は、WPFとMVPVMの設計パターンに関するものであり、ASP.NETとMVPに関するものではありません。

4
Brian Flynn

MVVMに若干の違反があると思います|ビュー間に作成するリンケージによるMVPVMパターン。どちらのパターンも、子ウィンドウに関してはそれほど冗長ではないので、少しあいまいな領域です。

MVPVMとMVVMの大きな利点は、ビジネスロジックが分離されていることです。 VMはデータコンテナーになり、PはロジックとDALアクセスを処理します。BillKratochvilの MVPVMに関する記事 は、非常に良い読み物でした。

ビルは子ウィンドウについてコメントし、私がふさわしいと思う再利用します:
In cases where a Presenter can be reused across enterprise applications, it’s likely a module would be better suited for the task—that is, you could create a login module (project) that could be reused by all of your enterprise applications.

2つの子コンポーネントを使用して不明瞭な領域にいることを、どの種類が補強しますか。

MVVMまたはMVPVMに関係なく、どちらかが必要になると思います

  • B-VMおよびC-VM MVVMを使用する場合
  • B-PおよびC-PおよびB-VMおよびC-VM MVPVMを使用する場合

aから機能的に分離されているためです。機能的に分離されていない場合、なぜ独自のビューが必要なのでしょうか。

ViewBとViewCを入れ替えることで生じる課題は、オブジェクトの所有権と責任の間にぼやけがあるためだと思います。これは、BとCが機能的にAから分離されているかどうかを確認する別の方法です。それらがそうである場合は、そのようにして、そうでない場合は、それらを独立したものとしてセットアップしないでください。

再利用できるビジネスロジックが多くない軽量なものについては、MVPVMはMVVMを使用するよりも労力が大きいと思います。これは明らかに一般性であり、アプリケーションのビジネスロジックは、MVPVMでよりエレガントに表現できる場合があります。しかし、あなたの質問に基づいて、MVVMは必要なものには十分であるように思えます。

2
user53019

ViewModelを入れ替える場合、プレゼンターも入れ替えるべきではありませんか?

とにかく、私はMVPパターンを研究しています。私は理解からほど遠いです。しかし、私があなたを助けてくれるいくつかのリンクをあなたに与えることができます:

http://lostechies.com/derekgreer/2008/11/23/model-view-presenter-styles/

http://webclientguidance.codeplex.com/wikipage?title=HowToImplementModelViewPresenterPattern&referringTitle=HowToUnitTestPresenter

結局、それを実装する正しい方法はありません。 MVPについて話し合っている部屋に10人のプログラマーを配置すると、11の異なる実装が得られるとどこかで読んだことがあります。自分にとって最善の方法を何でもすべきです。

私が間違っていない場合、このパターンは問題を分離するのに役立ち、コードのテストにも役立ちます。バリエーションを試してみて、あなたにとってより効果的なものを見てください。

0
Luiz Angelo