Design-Patterns-MVVM-Model-f1d7c05c

M-V-VM Devenez magicien

Depuis l'écriture de cet article en 2012, il à coulé de l'eau sous les ponts les lien vers des exemple de code sont devenus obsolète avec la disparition du CodePlex notamment.

Un article à jour sur ce sujet dans l'univers de Microsoft :

Prism: Patterns For Building Composite Applications With WPF | Microsoft Learn

Vous trouverez également cet exemple dans les All-In-One Code Framework :
Design Patterns - MVVM - Model View ViewModel Pattern-Part 2

Je suis en train de remonter dans l'histoire pour comprendre ce que le modèle M-V-VM est devenu aujourd'hui.

Etude de l'exemple MVVM-Model-f1d7c05c

Voici un des nombreux exemples de tentative de faire quelque chose avec MVVM.

On veux qu'un bouton "Save" ne soit enable que si les deux TextBox du formulaire ne sont pas vides. Pour cela on implemente une pauvre CustomerDelegateCommand qui dérive de ICommand

Pourquoi "Customer" ? Peut-être parce qu'en plus de CanExecute et Execute de l'interface ICommand, on implémente une propriété :

_isAutomaticRequeryDisabled

A quoi sert-elle ? A priori à enabler ou disabler le faite de tester le bouton "Save".

Bon ...

Ce que je voudrais faire

Je voudrais que le comportement du formulaire soit : Si je supprime tous les caractères de l'un des deux champs texte alors le bouton "Save" est désactivé.

26/12/2012
Je remarque que le bouton "Save" ne se disable pas si on vide une des TextBox, il faut également faire un TAB pour disabler ce bouton. Tient c'est curieux.

Je me demande, si en mettant
_isAutomaticRequeryDisabled à true dans l'init de la
saveCustomerCommand dans
\ViewModels\CustomerViewModel.cs
j'obtiens le fonctionnement que je désire :
Je voudrais que le bouton Save se disable si je vide la TextBox comment faire ?
_isAutomaticRequeryDisabled à true le bouton ne se disable plus du tout. En effet la CustomerDelegateCommand ne sert qu'à ça elle ajoute un gestionnaire d’évènement sur CanExecuteChanged pour permettre ou non de disabler le bouton.

Je regarde un autre exemple :
\\AllInOneSamples\Visual Studio 2010\VERY-Easy-MVVM-MVVMExtraLit-9a24e749\C#\MvvmExtraLite\
<Button
CommandParameter="{Binding IsChecked, ElementName=chkButtonCanExecute}" />

Mais il n'y a pas de Property IsEmpty pour une TextBox, je ne peux donc pas Binder le IsEnable de mon bouton "Save" sur cette propriété qui n'existe pas.

Me voilà bien embêté.

Autre idée : Créer un Objet TextBoxIsEmpty dérivée de TextBox et qui implémenterait la propriété IsEmpty cela me parait bien compliqué.

Autre idée : Ajouter une propriété du CustomerModel : IsSaveEnable qui testerait la longeur de mes TextBox pour pouvoir binder mon bouton "Save" sur cette propriété.

Problème : La StackPanel qui contient les deux champs texte et qui est bindée sur le Model ne contient pas le bouton "Save" :

<StackPanel Orientation="Vertical" Margin="4" Height="153"
                    DataContext="{Binding Path=CustomerModelObject, Mode=TwoWay}">

Solution

Dans l'autre exemple :
\\AllInOneSamples\Visual Studio 2010\VERY-Easy-MVVM-MVVMExtraLit-9a24e749\C#\MvvmExtraLite\

Qui met en oeuvre le design-pattern du Mediator pour échanger entre les deux ViewModels, les TextBox se tiennent au courant de changement de leurs contenus respectifs par l'intermédiaire de UpdateSourceTrigger=PropertyChanged

Un des miracles du modèle MVVM et qui se passe dans le Modèle est le RaisePropertyChanged qui lui aussi joue avec le PropertyChanged

D'où mon idée de la solution :

            <TextBox Width="250" Height="20"
                     Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />
            <TextBox Width="250" Height="20"
                     Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}" />

Et ça marche !

N'est-ce pas magique ?

Les sources ici