Wilfried Woivré & .Net

Live Meeting : MVVM de A a Z

DÉCE7

Avec Thomas Lebrun, nous avons réalisé un Live Meeting autour du pattern MVVM, celui ci avait pour but de refaire un tour d’horizon de ce dernier.

Donc comme promis voici les sources et le powerpoint de la session.

N’oubliez pas que nous organisons d’autres live meeting à peu près tout les deux mois le mardi soir de 19h à 20h, vous pouvez retrouver la liste ici

 

La ressource MVVM In the Box dont on a parlait pendant les questions/réponses se trouve ici.

EDIT Il ne sera pas possible de rejouer le WebCasts, cependant, je vais vous représenter la technologie, ainsi que la démonstration de façon plus complète prochainement.

 

Vous pouvez télécharger la vidéo sur mon Skydrive, vu la taille, elle est contenu dans un fichier 7zip splitté en deux : ici et

Dîtes moi en commentaire, si vous savez où je pourrais Upload la vidéo en 1 seul morceau (Youtube à échoué vu la taille de la vidéo). Et d’ailleurs si vous voulez d’autres vidéos, sur d’autres sujets proposez aussi via le formulaire de contact, je verrais si je peux les faire.

Remonter

WPF : Utiliser des commandes dans un DataTemplate

NOVE21

Après une très longue période sans réutiliser de technologies tel que WPF ou Silverlight, on s’aperçoit que l’on perd très vite la main. C’est donc durant un projet éclair que je me suis décidé de refaire un petit projet en utilisant le MVVM.

C’est donc confiant que je commence mon code, que je me décide à le lancer au bout d’une heure, histoire de voir ce que ça donne en dehors du Designer WPF. Mon interface ressemble donc à ce que je veux, cependant je m’aperçois que certaines de mes commandes ne marchaient pas, je passe donc 10 bonnes minutes pour trouver ce qu’il se passe et enfin corriger.

On va donc voir dans cet article un moyen de contourner la déclaration des commandes dans un DataTemplate, sans pour autant perdre en fonctionnalité.

 

Pour cette démonstration je vais utiliser comme base le template de MVVM qui vient de codeplex (WPF Model-View-ViewModel Toolkit 0.1) que je vais modifier de tel sorte que ViewModelBase dérive de DependencyObject, et implémente deux méthodes abstraites qui sont OnViewReady(), et OnViewDispose(). On obtient donc ceci :

/// <summary>
/// Provides common functionality for ViewModel classes
/// </summary>
public abstract class ViewModelBase : DependencyObject, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public abstract void OnViewReady();
    public abstract void OnViewDispose();

}

Note les modifications apportées ici ne sont pas nécessaire pour la démonstration, mais grâce à cela vous pouvez utiliser les DependencyProperty dans votre ViewModel, et propager les évènements Loaded et Unloaded de vos vues, vers vos ViewModel. Voilà pour l’astuce du jour !

Voici donc  la commande que nous allons utiliser :

#region GestionCommandes
private DelegateCommand<Models.Person> editPersonCommand;

public ICommand EditPersonCommand
{
    get
    {
        if (editPersonCommand == null)
            editPersonCommand = new DelegateCommand<Models.Person>(EditPerson);
        return editPersonCommand;
    }
}

private void EditPerson(Models.Person person)
{
    MessageBox.Show("Ici on éditera la personne", "", MessageBoxButton.OK);
}
#endregion 

Bon maintenant, affichons nos données dans la vue au pas à pas. Après un binding initial on obtient quelque chose du style

<Window x:Class="WpfModelViewApplication3.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:c="clr-namespace:WpfModelViewApplication3.Commands"
    Title="Main Window" Height="400" Width="800">

    <Grid>
        <ListBox ItemsSource="{Binding People}" />
    </Grid>
</Window>

Avec pour interface générée :

image

Bon ceci, n’étant pas très lisible pour un client, on va donc créer un DataTemplate. Or pour des raisons de lecture, nous allons ajouter ce DataTemplate en ressources de la fenêtre.

Donc confiant, j’écris ceci :

<Window.Resources>
    <DataTemplate DataType="{x:Type localModel:Person}">
        <StackPanel Orientation="Horizontal">
            <Label Content="{Binding FirstName}" />
            <Button Content="Modifier" Margin="5 0" Command="{Binding EditPersonCommand}" CommandParameter="{Binding}" />
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<Grid>
    <ListBox ItemsSource="{Binding People}" />
</Grid>

J’ai donc mon interface qui change en conséquence :

image

Le problème se situe en fait lorsque je clique sur le bouton Modifier, en effet rien ne se produit. J’ai donc regardé si lors de la construction de la fenêtre il allait bien me chercher ma commande, mais il ignora mon point d’arrêt dans Visual Studio.

Alors l’astuce facile à réaliser avec ce template est d’utiliser leur CommandReference, de tel sorte :

<Window.Resources>
    <c:CommandReference x:Key="EditPerson" Command="{Binding EditPersonCommand}" />


    <DataTemplate DataType="{x:Type localModel:Person}">
        <StackPanel Orientation="Horizontal">
            <Label Content="{Binding FirstName}" />
            <Button Content="Modifier" Margin="5 0" Command="{StaticResource EditPerson}" CommandParameter="{Binding}" />
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<Grid>
    <ListBox ItemsSource="{Binding People}" />
</Grid>

Là, notre code fonctionne comme on le souhaitait, et l’on récupère bien entendu le bon membre lors du déclenchement de la commande. En fait, ce qui a changé, nous avons déclaré la command, dans l’objet CommandReference. Notre bouton peut donc appeler la commande via le nom qu’on lui a donné. En effet, il passe par une ressource statique qui existe, et non une donnée dynamique comme il était question dans le DataTemplate.

Vous pouvez retrouvez la CommandReference dans le MVVM Toolkit, ce qui nous prouve encore une fois qu’avec des Toolkit bien pensé on optimise fortement notre temps de développement.

En espérant que cet article vous aide dans de futurs développement !

Remonter

MVVM Template en WPF et Silverlight

JUIL31

Bonjour à tous,

Alors je publie cet article vu le nombre de personne qui visitent mon blog pour les données sur le MVVM, j’espère avant tout qu’elles vous sont précieuses !

En fait durant mes différentes recherches sur le MVVM, principalement sur des projets de template pour réaliser des démonstrations, ou pour créer des projets plus rapidement avant de décider à implémenter mon propre projet de Template qui sera peut être publié un jour (si vous êtes sages !)

 

Vous pouvez donc retrouver un très bon Template sur le MVVM sur le site de codeplex à l’adresse : http://wpf.codeplex.com

 

Maintenant pour Silverlight et WPF, vous avez celui sur le site de Galasoft : http://www.galasoft.ch/mvvm/install/publish.html 

Alors rapidement avant que je ne vois des gens choqués sur mon blog, ces deux templates référence une dll de Galasoft, qui gère le MVVM, néanmoins si vous n’avez pas besoin de changer le comportement de son Toolkit, il suffit amplement pour des projets d’entreprise et de démonstration entre autre. Cependant voici un aperçu de sa dll : http://www.galasoft.ch/mvvm/getstarted/

 

Et voilà, en espérant que cela vous sera utile pour des développements futurs !

Remonter

Migrer une application WPF en Silverlight grâce au MVVM

JUIN7

Si vous êtes comme moi développeur WPF et Silverlight, on a souvent du vous dire: “mais c’est facile si tu sais faire l’un, l’autre c’est la même chose”. Or nous savons tous que c’est faux, il y a certes certains points similaires, mais ça ne fait pas tout puisque Silverlight c’est pour le Web et donc beaucoup plus limité que WPF tant au niveau des ressources disponibles que des composants, de la possibilité de Binding … Enfin tant de choses qui les différencient que toutes les énumérer serait un peu trop long.

Enfin, clairement on ne peut pas vraiment migrer une application WPF en Silverlight totalement, cependant il serait tout de même bien qu’en parti on puisse migrer une partie. Clairement le Model et son accès, ce n’est pas possible vu que Silverlight s’exécute dans une “Sandbox” on n’a pas accès au model. Vous pouvez tout de même y accéder via plusieurs méthodes que j’ai présenté précédemment. Maintenant la vue, vu ce que j’ai dis précédemment entre les différences entre Silverlight et WPF il est difficilement envisageable de migrer en 2 clics la vue entre ces types d’application. Il nous reste donc le ViewModel que l’on peut réutiliser en WPF ou en Silverlight, vu que comme je vous l’ai présenté dans un ancien poste, il contient des données, des DependencyProperty pour les injecter dans la vue, et bien entendu diverses actions appelées par la vue. Nous allons donc essayer de les migrer … A première vue, on ne peut pas vraiment référencer le projet contenant les ViewModel depuis Silverlight, donc on a une autre solution qui serait de copier le contenu de chacun des ViewModel dans un projet Silverlight ou alors même d’ajouter notre fichier “.cs” à notre application tel quel. Mais cela voudrait dire que pour chaque modification de notre ViewModel pour notre application WPF, nous serions obligé de faire la même en Silverlight, ce qui n’est certes pas pratique.

Cependant les concepteurs de Visual Studio ont pensé à nous, lorsque l’on ajoute un élément existant à notre application il est possible de l’ajouter comme lien vers le fichier en question, comme on peut le voir ci-dessous.

image

Cela nous permet donc de modifier les 2 ViewModel sélectionnés dans n’importe laquelle des deux applications.

Bien entendu, si vous avez déjà utilisé ce genre d’ajout, vous savez qu’il y a aussi beaucoup de contraintes, entre autre le fait que les deux projets doivent référencer les mêmes assembly afin de pouvoir fonctionner dans les deux cas.

De plus, en Silverlight ayant accès à beaucoup moins de choses qu’en WPF, si vous créez un projet avec ce principe, il faut que votre application WPF d’origine n’utilise pas des accès direct à la base de données, il vaut mieux passer par un Web Service commun pour vos deux applications afin que votre application WPF soit isolée par rapport à votre base de données.

Bon après tout cette littérature, je vais vous montrer succinctement un projet WPF que j’ai migré en Silverlight pour votre plus grand plaisir. Donc voici avant tous les différents projets :

image Le projet Helix et un projet Silverlight qui aide entre autre pour la navigation au sein d’un projet Silverlight, il n’a pas été créé par moi mais vous pouvez voir plus d’infos sur ce projet sur ce lien.

Bon comme vous pouvez le voir pour les autres projets, on va parler un peu Flux RSS là ! L’application a pour rôle d’afficher diverses personnes en base de données, puis après sélection on va récupérer les derniers posts de leurs blogs pour les afficher, je n’ai pas mis de lien lors d’un clic sur le titre d’un post, mais je vous laisse le faire par la suite …

Donc nous avons nos deux projets en Silverlight et WPF qui sont respectivement “MVVM.RSS.SL” et “MVVM.RSS”, les autres projets sont le service WCF, le modèle de base de données, et un projet de dépôt avec une Factory pour les différents types de données.

Dans cet article je ne vais pas rentrer dans l’implémentation du code puisque j’ai déjà abordé cette partie dans un autre post. Mais juste pour vous montrer le projet Silverlight contient les différents “ViewModel” du projet WPF en étant ajouté comme lien.

image image

 

La démonstration :image Vous pouvez voir que la partie Silverlight pour les flux RSS ne marche pas avec les liens fournis, puisqu’ils n’ont pas les fichiers XML pour autoriser l’accès aux flux RSS via Silverlight …

 

Pour une fois je vais conclure sur cet article, j’ai en réalité créé cet article sur un coup de tête puisque le projet initial en MVVM/WPF était pour mon premier post sur le MVVM, mais certaines circonstances furent telles que je ne pus le poster.

J’ai donc décidé de réaliser ce post puisque je savais qu’il était possible d’effectuer ce genre de manipulation. Néanmoins la réalisation de la migration en utilisant des fichiers “.cs” d’un projet WPF est assez ardue, du moins avec ma façon de concevoir le MVVM. Cela est dû entre autre à l’architecture de l’application qui est légèrement différente, mes contrôles ne passent pas directement par un ControlBase, mais via une classe intermédiaire puisque le XAML en Silverlight ne prends pas les arguments en compte dans le constructeur.De plus, les DependencyProperty en Silverlight et WPF sont légèrement différentes, je ne pouvais donc pas les utiliser pour les deux applications en mêmes temps. Je n’ai pas regardé si ces diverses différences sont moins importantes en Silverlight 3, ça sera peut être l’intitulé d’un autre post.

Enfin bref, divers problèmes, je pense donc que la migration d’un projet WPF en Silverlight peut s’avérer longue et ardue et il peut être plus rapide de reprendre entièrement un nouveau projet en Silverlight surtout si ce n’est pas vous qui avez réalisé celui en WPF. Je ne vous donne néanmoins pas de chiffres, puisque j’avais beaucoup de morceaux de code déjà fait, donc c’est toujours plus rapide. A près, il faudrait voir si cela serait rentable de réaliser les deux applications en parallèle afin de permettre une plus grande visibilité de votre application finale.

Remonter

Le design pattern : MVVM

MAI18

Bon avant de commencer, désolé de vous avoir fait attendre pour cet article. Promis, je vais essayer de me rattraper d'ici les prochaines semaines ... Enfin il faudra venir voir pour savoir ! Alors le deisgn pattern MVVM signifie pour commencer Model View ViewModel, alors j'espère que cet acronyme vous rappelle celui pour le MVC (Model View Controller). Celui ci a été crée principalement pour les applications en WPF ou en Silverlight, voir plus généralement les applications supportant un moteur de "binding" avancé. A quand le MVVM dans une application en JavaFX (Patrick si tu passes par là) Donc, à mon habitude je vais vous présenter une application implémentant ce design pattern. Donc contrairement à ce que j'avais prévu, cette application contient une liste de personne ou l'on peut afficher leurs détails. Et oui, l'application gérant les FluxRSS n'a pas été faite, puisque sans Internet la gestion de ces flux était légèrement moins pratique. Donc voici l'application au final : On ne pourra s'empêcher le voir le côté design très avancée de celle ci. Quand à la solution, voici à quoi elle ressemble, ce qui est d'ailleurs la partie intéressante de la démonstration. Donc ici, on peut voir le "Model" situé dans le projet "MVVM.Data", la "View" dans le "MVVM.Client", et le "ViewModel" dans le projet "MVVM.ViewModel" Bon alors, vu que j'ai décidé de parler des projets les plus intéressants, on va juste décrire les projets "MVVM.Client" et "MVVM.ViewModel" puisque l'utilisation du moteur de Binding se fait entièrement entre ces deux projets. Donc la partie "ViewModel", regardons de plus près la classe ViewModelBase public abstract class ViewModelBase : DependencyObject { public abstract void OnViewReady(); public abstract void OnViewClosed(); } On peut donc voir notre classe ViewModelBase dérivant de la classe DependencyObject, voyons donc maintenant notre classe LstPersonsViewModel public class LstPersonsViewModel : ViewModelBase {

public override void OnViewReady()

{

Personnes = PersonRepository.LoadPerson();

}

public override void OnViewClosed()

{

}

public IEnumerable<Personne> Personnes

{

get { return (IEnumerable<Personne>)GetValue(PersonnesProperty); } set { SetValue(PersonnesProperty, value); }

}

public static readonly DependencyProperty PersonnesProperty = DependencyProperty.Register("Personnes", typeof(IEnumerable<Personne>), typeof(LstPersonsViewModel), new UIPropertyMetadata(null));

public Personne SelectedPersonne

{

get { return (Personne)GetValue(SelectedPersonneProperty); }

set { SetValue(SelectedPersonneProperty, value); }

}

public static readonly DependencyProperty SelectedPersonneProperty =

DependencyProperty.Register("SelectedPersonne", typeof(Personne), typeof(LstPersonsViewModel), new UIPropertyMetadata(null)); } Cette classe implémente comme il se doit notre classe abstraite, on peut donc voir nos deux méthodes, celle pour le OnViewReady() permet d'initialiser nos données, de les charger depuis la base, ou comme ici en dur depuis notre projet "MVVM.Repository" On déclare ici, de plus deux DependencyProperty afin de pouvoir les injecter dans notre vue par la suite. Passons maintenant à la vue. Notre vue est basé sur un ControlBase générique contenant un objet dérivant de notre ViewModelBase, et on lie les méthodes OnViewReady() et OnViewClose() à ce control : public abstract class ControlBase<TViewModel> : UserControl where TViewModel : ViewModelBase {

public TViewModel ViewModel { get; protected set; }

public ControlBase()

{

Loaded += delegate { if (ViewModel != null) ViewModel.OnViewReady(); };

Unloaded += delegate { if (ViewModel != null) ViewModel.OnViewClosed(); };

} } Les deux classes DelegateCommand et DelegateCommandWithParam permettent d'appeler différentes command depuis la vue grâce au Controller. Je vous laisse donc regarder ces deux classes, qui implémentent l'interface ICommand. Notre classe Controller maintenant : public static ICommand NavigateUri {

get { return new DelegateCommandWithParam<Uri>(OnNavigateUri); } } private static void OnNavigateUri(Uri uri) {

Process.Start(new ProcessStartInfo(uri.AbsoluteUri)); } public static ICommand StartApplication {

get { return new DelegateCommand(OnStartApplication); } } private static void OnStartApplication() {

Window window = Application.Current.MainWindow; if (window == null)

window = new Window1();

if (window.Visibility != Visibility.Visible)

{

window.Dispatcher.BeginInvoke(

DispatcherPriority.Send, new Action(() => window.Show()));

}

Application.Current.MainWindow = window;

} } On peut voir ici la déclaration de deux commandes, la première sert pour naviguer vers les différents sites des personnes présentes dans l'application. et la deuxième permet de gérer le démarrage de l'application. Maintenant voici la partie Xaml de notre application : <local:ControlBase

x:Class="MVVM.Client.LstPersons"

x:TypeArguments="viewModel:LstPersonsViewModel"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:MVVM.Client"

xmlns:viewModel="clr-namespace:MVVM.ViewModel;assembly=MVVM.ViewModel"> <Grid>

<Grid.RowDefinitions>

<RowDefinition Height="250" />

<RowDefinition Height="Auto" />

</Grid.RowDefinitions>

<ListView x:Name="lst_Personnes" ItemsSource="{Binding Personnes}"

IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedPersonne}" >

<ListView.ItemTemplate>

<DataTemplate>

<StackPanel Orientation="Horizontal">

<TextBlock Text="{Binding Prenom}" />

<TextBlock Text="{Binding Nom}" Margin="5,0,0,0" />

</StackPanel>

</DataTemplate>

</ListView.ItemTemplate>

</ListView>

<Grid Grid.Row="1">

<Grid.RowDefinitions>

<RowDefinition Height="Auto" />

<RowDefinition Height="Auto" />

<RowDefinition Height="Auto" />

</Grid.RowDefinitions>

<StackPanel Orientation="Horizontal">

<TextBlock Text="{Binding SelectedPersonne.Prenom}" />

<TextBlock Text="{Binding SelectedPersonne.Nom}" Margin="5,0,5,0" />

</StackPanel>

<TextBlock Grid.Row="1">

<Hyperlink Command="local:Controller.NavigateUri" CommandParameter="{Binding SelectedPersonne.SiteInternet}" >

<TextBlock Text="Site Internet" />

</Hyperlink>

</TextBlock>

<TextBlock Grid.Row="2" Text="{Binding SelectedPersonne.NomEntreprise}" />

</Grid> </Grid> </local:ControlBase> Donc maintenant regardons uniquement les parties intéressantes de ce fichier Xaml, on intègre les deux namespaces "MVVM.Client" et "MVVM.ViewModel", et on ajoute bien entendu le ControlBase et son argument pour la création de ce fichier Xaml, afin qu'on puisse profiter de notre classe précédemment créer. Maintenant passons aux commandes, celle de démarrage je vous l'épargne pour le moment, mais elle intervient lors du démarrage de l'application "OnStartupApplication" dans App.xaml.cs. Donc on voit l'appelle d'une commande avec paramètre dans le composant Hyperlink. Command="local:Controller.NavigateUri" Ici, on voit l'appel de notre commande, puis on passe notre paramètre avec cet attribut : CommandParameter="{Binding SelectedPersonne.SiteInternet}" Pour le reste, en fait la classe DelegateCommandWithParam s'occupe de relayer et d'exécuter cette action. Edit : Alors depuis que j'ai installé Visual Studio 2010, autant profiter de ces fonctionnalités. Voici un schéma des différentes liaisons entre mes Namespaces, j'ai seulement laissé ceux en liaison avec le MVVM bien entendu. Schéma liaison Namespace Alors une fois n'est pas coutume, voici les sources de la solution:

Toutefois, je souhaite remercier Fabrice Marguerie (MVP) pour ces différents liens sur le MVVM qu'il m'a fourni, ainsi qu'une application fortement détaillé implémentant ce design pattern.
Remonter