Esiste un buon modello formale per gestire lo stato in MVVM?


21

Ho iniziato a conoscere Redux e React nel mondo web e più ne apprendo, più sto realizzando quanto sia dolorosa la gestione dello stato nel mondo desktop con l'architettura in stile MVVM di WPF (usando Caliburn appositamente per legare Views a ViewModels).

Redux ha alcuni semplici principi che determinano come gestire lo stato, rendendo gli aggiornamenti dell'interfaccia utente, la gestione degli eventi e i cambiamenti di stato molto più prevedibili. I principi sono:

  • Una singola fonte di verità (tutto lo stato mutabile è archiviato in un singolo oggetto condiviso).
  • Lo stato è di sola lettura. Non può essere modificato dai componenti attraverso il codice, che in genere è ciò che accade in WPF.
  • Lo stato può essere modificato solo da funzioni pure.

L'architettura MVVM di WPF consente di creare viste interattive molto rapidamente, ma il debug dei problemi quando vari modelli di vista ed eventi cambiano tutti stato è un incubo. Ad esempio: è stato generato un evento che ha modificato una vista e ha tentato di impostare una scheda predefinita, ma i dati non sono stati caricati in modo asincrono da un servizio Web, quindi la scheda non esiste (ancora) quindi non accade nulla

Ho passato ore a disegnare diagrammi per cercare di comprendere complesse interazioni tra componenti viewModels interconnessi che si aggiornano l'un l'altro.

Capisco che Redux mira a risolvere un po 'di imprevedibilità di questo stato. C'è qualcosa di simile o un modello architettonico che si adatterebbe bene con WPF per aiutare a gestire meglio lo stato? Non sono sicuro di come i principi Redux funzionerebbero in .NET poiché non li ho ancora provati. Qualcuno ha qualche esperienza che può dare qualche consiglio?


Abbiamo un tipo simile di problemi nel browser. Javascript semplice verrà eseguito così presto e il DOM non è ancora stato creato, quindi non è possibile trovare alcun elemento dell'interfaccia utente. Fortunatamente ci sono un certo numero di Eventi, che possiamo usare per innescare l'esecuzione ritardata di alcuni script fino a quando le altre cose non sono più avanti. (Come DOMContentLoaded.)
Erik Eidt,

1
Lo stato in redux è attualmente aggiornato, mai modificato.
Andy,

1
So che sono in ritardo alla festa, ma c'è un progetto chiamato React.NET che porta l'architettura Redux su .NET.
SiberianGuy

Per coloro a cui piace l'approccio di ngrx / store nei progetti angolari, c'è NetRx.Store - gestione dello stato per i progetti .Net, ispirata a ngrx / store. Puoi trovarlo anche su Nuget . Inoltre c'è un buon esempio di utilizzo di NetRx.Store con pattern MVVM nel progetto WPF
Vitalii Ilchenko

Risposte:


8

Penso di sapere cosa intendi. Fondamentalmente risolvi il problema aggiungendo un "controller" o un "master" viewmodel (scusa psudocode)

vale a dire

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 lo fai con il modello mediatore, penso alla classe come a un controller. vale a dire.

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

Questo genere di cose consente di inserire la "logica di flusso" o l'orchestrazione degli eventi in queste classi persistenti di alto livello e mantenere il codice delle macchine virtuali leggero. Se vuoi cambiare "quando l'utente fa clic su ACQUISTA, l'ordine viene elaborato" tipo di cose che sai cercare in "OrderFlowController" o "OrderProcessVM" o comunque desideri nominarle. Piuttosto che una combinazione di BasketVM, PaymentVM, 3dSecureVM ecc ecc

Quindi nel tuo esempio specifico di "scheda non ancora pronta" potresti avere

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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.