¿Existe un buen patrón formal para administrar el estado en MVVM?

16

Empecé a aprender sobre Redux y Reaccionar en el mundo web, y cuanto más aprendo, más me doy cuenta de lo doloroso que es la administración del estado en el mundo del escritorio con la arquitectura de estilo MVVM de WPF (utilizando Caliburn específicamente para enlazar vistas a ViewModels).

Redux tiene algunos principios simples que dictan cómo se debe administrar el estado, lo que hace que las actualizaciones de IU, el manejo de eventos y los cambios de estado sean mucho más predecibles. Los principios son:

  • Una única fuente de verdad (todo el estado mutable se almacena en un solo objeto compartido).
  • El estado es de solo lectura. Los componentes no pueden modificarlo a través del código, que suele ser lo que ocurre en WPF.
  • El estado solo puede modificarse mediante funciones puras.

La arquitectura MVVM de WPF le permite crear vistas interactivas muy rápidamente, pero los problemas de depuración cuando varios modelos de vista y eventos cambian de estado es una pesadilla. Por ejemplo: un evento activado que cambió una vista e intentó establecer una pestaña predeterminada, pero los datos no han terminado de cargarse de forma asíncrona desde un servicio web, por lo que la pestaña no existe (aún), por lo que no pasa nada

Pasé horas dibujando diagramas para tratar de entender las interacciones complejas entre los componentes de viewModels interrelacionados que se actualizan entre sí.

Entiendo que Redux pretende resolver parte de esta imprevisibilidad del estado. ¿Hay algo similar o un patrón arquitectónico que encajaría bien con WPF para ayudar a administrar mejor el estado? No estoy seguro de qué tan bien funcionarán los principios de Redux en .NET, ya que todavía no los he probado. Tal vez alguien tenga alguna experiencia que pueda dar algún consejo?

    
pregunta willem 27.04.2016 - 16:27

1 respuesta

6

Creo que sé lo que quieres decir. Básicamente, resuelve el problema agregando un "controlador" o un modelo de vista "maestro" (excuse psudocode)

es decir

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;
    }
}

cuando haces esto con el patrón de mediador, pienso en la clase como un controlador. es decir.

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;});
    }
}

Este tipo de cosas le permite poner su 'lógica de flujo' o Event Orchestration en estas clases persistentes de alto nivel y mantener la luz del código de las máquinas virtuales. Si desea cambiar 'cuando el usuario haga clic en COMPRAR, el pedido se procesa' tipo de cosas que sabe buscar en 'OrderFlowController' o 'OrderProcessVM' o como quiera llamarlas. En lugar de una combinación de BasketVM, PaymentVM, 3dSecureVM, etc., etc.

Por lo tanto, en su ejemplo específico de la 'pestaña que aún no está lista' podría tener

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;
    }
}
    
respondido por el Ewan 27.04.2016 - 21:05

Lea otras preguntas en las etiquetas