Existe-t-il un bon modèle formel pour gérer l'état dans MVVM?

21

J'ai commencé à apprendre sur Redux et React dans le monde Web, et plus j'en apprends plus je me rends compte à quel point la gestion des états est difficile dans le monde du bureau avec l'architecture de style MVVM de WPF (en utilisant Caliburn spécifiquement pour lier des vues à ViewModels).

Redux a quelques principes simples qui dictent la façon dont l'état doit être géré, ce qui rend les mises à jour de l'interface utilisateur, la gestion des événements et les changements d'état beaucoup plus prévisibles. Les principes sont les suivants:

  • Une seule source de vérité (tous les états mutables sont stockés dans un seul objet partagé).
  • L'état est en lecture seule. Il ne peut pas être modifié par des composants tout au long du code, ce qui se produit généralement dans WPF.
  • L'état ne peut être modifié que par des fonctions pures.

L'architecture MVVM de WPF vous permet de créer des vues interactives très rapidement, mais le débogage des problèmes lorsque divers modèles de vue et événements changent tous d'état est un cauchemar. Par exemple: un événement déclenché qui a changé une vue et a essayé de définir un onglet par défaut, mais les données n'ont pas fini de se charger de manière asynchrone à partir d'un service Web de sorte que l'onglet n'existe pas (encore) donc rien ne se passe

J'ai passé des heures à dessiner des diagrammes pour essayer de comprendre les interactions complexes entre les composants viewModels interdépendants qui se mettent à jour les uns les autres.

Je comprends que Redux vise à résoudre une partie de cet imprévisibilité de l'état. Existe-t-il quelque chose de similaire ou un modèle architectural qui conviendrait parfaitement à WPF pour aider à mieux gérer l'état? Je ne sais pas dans quelle mesure les principes Redux fonctionneraient dans .NET car je ne les ai pas encore essayés. Peut-être que quelqu'un a une certaine expérience qui peut donner des conseils?

willem
la source
Nous avons un problème similaire dans le navigateur. Le Javascript simple fonctionnera si tôt et le DOM n'est pas encore construit, donc on ne trouve aucun élément d'interface utilisateur. Heureusement, il existe un certain nombre d'événements, que nous pouvons utiliser pour déclencher l'exécution différée de certains scripts jusqu'à ce que d'autres choses avancent. (Comme DOMContentLoaded.)
Erik Eidt
1
L'état dans redux est réellement mis à jour, jamais modifié.
Andy
1
Je sais que je suis en retard à la fête, mais il y a un projet appelé React.NET qui apporte l'architecture Redux à .NET.
SiberianGuy
Pour ceux qui aiment l'approche de ngrx / store dans les projets angulaires, il existe NetRx.Store - la gestion des états pour les projets .Net, inspirée de ngrx / store. Vous pouvez également le trouver à Nuget . Il existe également un bon exemple d'utilisation de NetRx.Store avec un modèle MVVM dans le projet WPF
Vitalii Ilchenko

Réponses:

8

Je pense que je sais ce que tu veux dire. Fondamentalement, vous résolvez le problème en ajoutant un modèle de vue «contrôleur» ou «maître» (psudocode d'excuse)

c'est à 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;
    }
}

lorsque vous faites cela avec le modèle Mediator, je pense à la classe en tant que contrôleur. c'est à 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;});
    }
}

Ce genre de chose vous permet de placer votre «logique de flux» ou orchestration d'événements dans ces classes persistantes de haut niveau et de garder le code des machines virtuelles léger. Si vous souhaitez modifier "lorsque l'utilisateur clique sur ACHETER, la commande est traitée" le genre de choses que vous savez à regarder dans "OrderFlowController" ou "OrderProcessVM" ou comment vous voulez les nommer. Plutôt qu'une combinaison de BasketVM, PaymentVM, 3dSecureVM, etc., etc.

Donc, dans votre exemple spécifique de l'onglet «pas encore prêt», vous pourriez avoir

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;
    }
}
Ewan
la source