web-dev-qa-db-ja.com

MVVMで状態を管理するための適切な正式なパターンはありますか?

私はReduxについて学び始め、ReactはWebの世界であり、それについて学ぶほど、WPFのMVVMを使用してデスクトップの世界で状態管理がいかに苦痛であるかを理解します。スタイルアーキテクチャ(特にビューをViewModelにバインドするためにCaliburnを使用)。

Reduxには、状態の管理方法を指示するいくつかの単純な原則があり、UIの更新、イベント処理、および状態の変化をより予測可能にします。原則は次のとおりです。

  • 真実の単一のソース(すべての変更可能な状態は単一の共有オブジェクトに格納されます)。
  • 状態は読み取り専用です。これは、コード全体でコンポーネントによって変更することはできません。これは通常、WPFで発生することです。
  • 状態は、純粋な関数によってのみ変更できます。

WPFのMVVMアーキテクチャを使用すると、インタラクティブなビューをすばやく構築できますが、さまざまなビューモデルとイベントの状態がすべて変化した場合のデバッグの問題は悪夢です。例:ビューを変更してデフォルトのタブを設定しようとしたイベントが発生しましたが、データがWebサービスから非同期に読み込まれていないため、タブが存在しないため(まだ)、何も起こりません

相互に更新する相互に関連するviewModelsコンポーネント間の複雑な相互作用を試し理解するために、何時間も図を描いてきました。

Reduxがこの状態の予測不能性の一部を解決することを目的としていることを理解しています。同様の何か、または状態をよりよく管理するのに役立つWPFにうまく適合するアーキテクチャパターンはありますか? Reduxの原則が.NETでどれほどうまく機能するかは、まだ試していないのでわかりません。多分誰かがいくつかのアドバイスをすることができるいくつかの経験を持っていますか?

22
willem

私はあなたが何を意味するか知っていると思います。基本的には、「コントローラー」または「マスター」ビューモデルのいずれかを追加することで問題を解決します(言い訳の疑似コード)

すなわち

public class MasterVM
{
    public ChildVM View1 {get;set;}
    public ChildVM View2 {get;set;}

    private Data data;
    public MasterVM()
    {
        View1.OnEvent += updateData;
    }

    private Action<int> updateData(int value)
    {
         View2.Value = value;
    }
}

mediatorパターンでこれを行う場合、私はクラスをコントローラーとして考えます。すなわち。

public class Controller
{
    public Controller(MediatorService m)
    {
        m.Subscribe("valueupdated", updateData);
    }

    private Action<int> updateData(int value)
    {
         m.Publish("showvalue", value);
    }
}

public class View2
{
    public View2(MediatorService m)
    {
        m.Subscribe("showvalue", (int v)=> {Value = v;});
    }
}

この種のことにより、これらの高レベルの永続クラスに「制御ロジック」またはイベントオーケストレーションを配置し、VMコードを軽量に保つことができます。 「ユーザーがBUYをクリックすると、注文が処理されます」という種類の変更をしたい場合は、「OrderFlowController」または「OrderProcessVM」で確認するか、名前を付けます。 BasketVM、PaymentVM、3dSecureVMなどの組み合わせではなく

したがって、「タブはまだ準備ができていません」という具体的な例では、

public class Controller
{
    bool dataLoadCompleted;
    public Controller(MediatorService m)
    {
        m.Subscribe("setTabRequest", setTab); //message from view model with set tab button
        m.Subscribe("dataLoadComplete", dataLoadComplete); //message from data loading view model or some other controller?
    }

    private Action<int> setTab(int value)
    {
         if(!dataLoadCompleted)
         {
             m.Publish("error", "Please wait for data to load"); //message for error alert view model
         }
         else
         {
             m.Publish("setDefaultTab", value); //message for tab viewmodel
         }
    }

    private Action dataLoadComplete()
    {
         //persist state;
         dataLoadCompleted = true;
    }
}
8
Ewan