是否有很好的形式化模式来管理MVVM中的状态?


21

我已经开始了解网络世界中的Redux和React,并且对它的了解越多,我越意识到WPF的MVVM风格的架构在桌面世界中的状态管理是多么痛苦(使用Caliburn专门绑定视图)。到ViewModels)。

Redux有一些简单的原则,指示如何管理状态,从而使UI更新,事件处理和状态更改更加可预测。原则是:

  • 单一事实来源(所有可变状态都存储在单个共享库中)。
  • 状态为只读。组件无法在整个代码中对其进行修改,这通常是WPF中发生的情况。
  • 状态只能通过纯函数进行修改。

WPF的MVVM体系结构允许您非常快速地构建交互式视图,但是当各种视图模型和事件都改变状态时调试问题是一场噩梦。例如:触发了一个事件,该事件更改了视图并尝试设置默认选项卡,但是数据尚未从Web服务异步加载完成,因此该选项卡不存在(尚未),因此没有任何反应

我花了数小时来绘制图表,以尝试理解相互更新的相互关联的viewModels组件之间的复杂交互。

我了解Redux旨在解决这种状态不可预测的问题。是否有类似的东西,或与WPF很好地配合以更好地管理状态的体系结构模式?我不确定Redux原则在.NET中的运行情况如何,因为我还没有尝试过。也许有人有经验可以提供一些建议?


浏览器中存在类似的问题。简单的Javascript将会运行得如此之早,并且尚未构建DOM,因此无法找到任何UI元素。幸运的是,有许多事件,我们可以使用它来触发某些脚本的延迟执行,直到其他事情发生为止。(例如DOMContentLoaded。)
Erik Eidt's

1
redux中的状态实际上已更新,从未修改。
安迪

1
我知道我参加聚会很晚,但是有一个名为React.NET的项目将Redux架构引入.NET。
SiberianGuy

对于那些谁喜欢的方式NGRX /存储在角项目中,有NetRx.Store -对于.NET项目,由NGRX /存储激发状态管理。您也可以在Nuget找到它。还有一个很好的使用NetRx.WPF项目中的MVVM模式
存储示例

Answers:


8

我想我明白你的意思。基本上,您可以通过添加“控制器”或“主”视图模型(例如psudocode)来解决问题

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 Pattern进行此操作时,我将该类视为Controller。即。

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代码保持清淡。如果您想更改“当用户单击“购买时,订单已处理””,则可以在“ 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;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.