Existe um bom padrão formal para gerenciar o estado no MVVM?


21

Comecei a aprender sobre o Redux e o React no mundo da web e, quanto mais aprendo sobre ele, mais percebo o quão doloroso o gerenciamento de estado é no mundo do desktop com a arquitetura no estilo MVVM do WPF (usando o Caliburn especificamente para vincular o Views para ViewModels).

O Redux possui alguns princípios simples que determinam como o estado deve ser gerenciado, tornando as atualizações da interface do usuário, a manipulação de eventos e as mudanças de estado muito mais previsíveis. Os princípios são:

  • Uma única fonte de verdade (todo estado mutável é armazenado em um único objeto compartilhado).
  • O estado é somente leitura. Ele não pode ser modificado pelos componentes em todo o código, o que normalmente ocorre no WPF.
  • Estado só pode ser modificado por funções puras.

A arquitetura MVVM do WPF permite criar visualizações interativas muito rapidamente, mas problemas de depuração quando vários modelos e eventos de visualização mudam de estado são um pesadelo. Por exemplo: um evento disparado que mudou uma visualização e tentou definir uma guia padrão, mas os dados não terminaram de carregar assincronamente a partir de um serviço da Web, para que a guia ainda não exista, para que nada aconteça

Passei horas desenhando diagramas para tentar entender as interações complexas entre os componentes viewModels inter-relacionados que se atualizam.

Entendo que o Redux tem como objetivo resolver parte dessa imprevisibilidade do estado. Existe algo semelhante ou um padrão arquitetural que se encaixaria perfeitamente no WPF para ajudar a gerenciar melhor o estado? Não tenho certeza de como os princípios do Redux funcionariam no .NET, pois ainda não os tentei. Talvez alguém tenha alguma experiência que possa dar alguns conselhos?


Temos um tipo semelhante de problemas no navegador. O Javascript simples será executado tão cedo e o DOM ainda não foi criado; portanto, não é possível encontrar nenhum elemento da interface do usuário. Felizmente, existem vários eventos que podemos usar para disparar a execução atrasada de algum script até que outras coisas avancem. (Tal como DOMContentLoaded.)
Erik Eidt

1
O estado no redux é realmente atualizado, nunca modificado.
21416 Andy

1
Sei que estou atrasado para a festa, mas há um projeto chamado React.NET que traz a arquitetura Redux para o .NET.
SiberianGuy

Para quem gosta da abordagem do ngrx / store em projetos Angular, existe o NetRx.Store - gerenciamento de estado para projetos .Net, inspirado no ngrx / store. Você pode encontrá-lo em Nuget também. Também há uma boa amostra do uso NetRx.Store com padrão MVVM no projeto WPF
Vitalii Ilchenko

Respostas:


8

Eu acho que sei o que você quer dizer. Basicamente, você resolve o problema adicionando um modelo de exibição 'controller' ou 'master' (desculpe psudocode)

ie

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

quando você faz isso com o Padrão do Mediador, penso na classe como Controladora. ie

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

Esse tipo de coisa permite que você coloque sua 'lógica de fluxo' ou orquestração de eventos nessas classes persistentes de alto nível e mantenha o código das VMs leve. Se você deseja alterar 'quando o usuário clica em COMPRAR, o pedido é processado', como você deve procurar no 'OrderFlowController' ou 'OrderProcessVM' ou, no entanto, deseja nomeá-los. Em vez de uma combinação do BasketVM, PaymentVM, 3dSecureVM etc etc

Portanto, no seu exemplo específico de 'guia ainda não está pronto', você pode ter

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;
    }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.