Quoi de neuf dans le Microsoft Framework .NET ?

Un peu d'histoire, qu'elles sont les étapes importantes, les modifications apportées au .NET Framework de Microsoft. On me pose souvent cette question lorsque l'on me demande si j'ai déjà travaillé avec telle ou telle version du Framework.

Voici donc pour ceux qui aiment l'histoire du développement logiciel de Microsoft .NET, les dates des releases des différentes versions du framework :
Overview of .NET Framework release history
GenerationVersion numberRelease dateDevelopment toolDistributed with
1.01.0.3705.02002-02-13Visual Studio .NETN/A
1.11.1.4322.5732003-04-24Visual Studio .NET 2003Windows Server 2003
2.02.0.50727.422005-11-07Visual Studio 2005Windows Server 2003 R2
3.03.0.4506.302006-11-06Expression BlendWindows VistaWindows Server 2008
3.53.5.21022.82007-11-19Visual Studio 2008Windows 7Windows Server 2008 R2
4.04.0.30319.12010-04-12Visual Studio 2010N/A
4.54.5.50709.179292012-08-15Visual Studio 2012Windows 8Windows Server 2012

Source : WikipediA on y trouvera les grands principes du CLR.

Ne parlons pas de la version 1.0 qui ne fonctionnait pas. D'ailleurs je ne connais personne qui ait démarré en 2002 avec cette version 1.0. On commencera à parler de développement possible avec le .NET Framework que bien plus tard.

DotNET Framework 1.1

ASP.NET Mobile Controls

Les contrôles mobiles sont maintenant intégrés au framework. Le nom Mobile Internet Toolkit est remplacé par ASP.NET Mobile Controls. 

Les contrôles mobiles sont : AdRotator Calendar Command CompareValidator CustomValidator Form Image Label Link List MobilePage ObjectList Panel PhoneCall RangeValidator RegularExpressionValidator RequiredFieldValidator SelectionList StyleSheet TextBox TextView ValidationSummary

Les contrôles mobiles sont extensibles, vous pouvez utiliser la composition et l'héritage pour créer de nouveaux contrôles.

ADO.NET

L'objet DataReader expose maintenant une propriété HasRow pour savoir si l'objet retourne des Lignes sans avoir besoin de faire appel à la fonction Read.

L'objet Connection possède maintenant une méthode EnlistDistributedTransaction pour établir manuellement des transactions distribuées.

Exécution côte à côte

Différentes versions d'une application peuvent s'exécuter en même temps sur un même ordinateur. Une application peut choisir les composants avec lesquels elle va s'exécuter.

IPv6

Le framework .NET support maintenant IPv6 ...

DotNET Framework 2.0

La version 2.0 est importante, on va enfin pouvoir travailler.
Support des plateformes 64-bits
ACL : Access Control List utilisé pour accorder (grant) ou supprimer (revoke) la persmission d'accès au ressources d'un ordinateur.

Apparition des Generics et des Collection Generics.

Globalisation : GetCultureInfo et CultureInfo

ADO.NET 

Support de UDT User-define Types, types définis par l'utilisateur. Apparition des types de données XML.

ASP.NET

Grandement amélioré, les contrôles sont améliorés, on peut éditer modifier des données sans écrire de code. On peut écrire une table de dépendance de cache dans SQL Server.
Apparition des Web Parts. Menu de navigation. Master Page. 
Prise en compte des différents navigateurs, le rendu des contrôles est compatible des standards XHTML 1.1.

Débogueur

Il supporte le mode édit et continuer, vous pouvez modifier le code source et reprendre l'exécution du programme ...

Support de SMTP

Amélioré, on peut maintenant envoyer à plusieurs destinataires, des pièces attachés mettre en copie et en carbon copie ... Et avant c'était comment ? 
Espaces de noms System.Net.Mail et System.Net.Mime

Filtrage des données de Trace

Le système de Trace et Log des données permet maintenant de les filtrer ...

Web Services

Support de SOAP 1.2 et de WS-I Basic Profile 1.0

XML Améliorations

Améliorations du Processeur : XSL Transformation (XSLT)
XmlReader
XmlWriter
XPathNavigator

Langage Visual Basic

Certaines améliorations du Langage Visual Basic sont apportée pour lui donner à peu prêt le même niveau qu'en C# ...

Conclusion

Il y a plein d'autres améliorations du .NET Framework que je ne détaille pas ici, j'ai tenté de résumer mais c'est à se demander comment pouvait-on faire avant ...

DotNET Framework 3.0

La version 3.0 du Framework est sortie pour regrouper les technologies suivantes dans le SDK (Software Development Kit) :
  • Windows Communication Foundation
  • Windows Presentation Foundation
  • Windows Workflow Foundation
  • Windows CardSpace

DotNET Framework 3.5

C'est WCF (Windows Communication Foundation) la partie importante dans cette release. WCF est maintenant intégré dans le .NET Compact Framework pour les applications mobiles.

ASP.NET

Ajax Enable Web Site, les contrôles ScriptManager et UpdatePanel ont été ajouté ainsi on peut rafirachir une page sans la recharger entièrement.
Support IntelliSense pour JavaScripts.
Les fonctions d'authentification, de gestion des rôles et des profile sont maintenant exposées à travers un service-web qui peut être hébergé dans une application WCF, ainsi plusieurs ASP.NET applications peuvent partager ces même services.
Nouveau Data Contrôle ListView
Nouvelle source de données LinqDataSource
De nouveaux outils permettent une meilleur intégration avec IIS 7.0

Add-Ins et extensibilité

Namespace System.AddIn.dll
Fonctionnalités :
Discovery
Activation
Isolation
Sandboxing
UI Composition
Versioning

On se croirait dans MEF (Managable Extensible Framework) ... curieux je n'avais pas vu cet aspect des choses.On va voir que MEF sera intégré au Framework 4.0

Common Language Runtime

Une nouvelle collection : HashSet<T>, modélisation d'un ensemble mathématique de valeurs toutes différentes et non ordonnées.

Diagnostic : nouvelle class EventSchemaTraceListener pour des composants hétérogènes qui traversent des thread des AppDomain.

Linq

Étendu par le .NET 3.5 donne la possibilité de faire des requêtes sur des Tables SQL Server, des ADO.NET DataSet, des XML Documents, et des collections du type IEnumerable et IEnumerable<T>.

Expression Trees

Namespace : System.Linq.Expressions
Permet de représenter des expressions du code sous forme de données.
Mais à quoi cela peut-il bien servir ? Ici.

DotNET Framework 4.0

.NET Framework 4 Client Profile : sous ensemble du .NET Framework 4 optimisé pour les applications clientes.
Améliorations de l'énumération de système de fichiers ??? Et oui on améliore encore c'est trucs là !

Managed Extensibility Framework

Managed Extensibility Framework (MEF) est une nouvelle bibliothèque dans le .NET Framework 4 
qui vous aide à générer des applications extensibles et composables. MEF 
vous permet de spécifier des points où une application peut être étendue, 
d'exposer des services à offrir à d'autres applications extensibles et 
de créer des parties en vue de leur utilisation par des applications extensibles. 
Il facilite également la détectabilité des parties disponibles en fonction des métadonnées, 
sans que les assemblys pour les parties aient besoin d'être chargés.

Dynamic Language Runtime (DLR)

Dynamic Objects, Python est un exemple de langage dynimaque

TBC (To Be Continued)

Objets MVVM

Quels sont les objets MVVM nécessaires à l'exécution des applications C# .NET basées sur le Modèle M-V-VM ?

Objets dérivés de l'interface ICommand
RelayCommand
DelagateCommand
DelegateCommandWithParam

Objets dérivés de INotifyPropertyChanged
ObservableObject

PropertyObserver

Autres objets
EventToCommand
Mediator
Messenger

ViewModelBase : INotifyPropertyChanged

View modèles de base
ViewModelBase : peut dériver de DependencyObject
Tous les ViewModel vont dériver de ViewModelBase

Controler de base

WPF Drag & Drop in Grid Sample

Drag and Drop, ce n'est peut être pas si facile. Bien souvent il manque quelques astuces de bases comme par exemple quand on Drop dans une Grid on aimerait bien savoir dans quelle cellule on a dropé l'objet.

Alors on part de l'exemple MSDN :

Drag and Drop on a user control

MSDN Drag and Drop Sample

On écrit une couleur dans le TextBox et en la dropant  dans un des cercles on change la couleur du cercle, on peut copier un cercle en le dropant en maintenant la touche contrôle appuyée.

C'est intéressant mais il nous manque tout un tas de choses. Ce que j'aimerais faire c'est dropper des objets dans une Grid savoir où il sont dans la Grid et pouvoir commencer réellement à jouer avec mes objets.

Il est par exemple intéressant de jouer avec les propriétés de ma Grid et d'y déplacer les objets :

Grid.SetRow(object,x), Grid.SetColumn, Grid.SetColumnSpan,Grid.SetRowSpan

Je sais maintenant déplacer mes objets dans la Grid mais où sont -ils ?

Grid.GetRow(object,x),  object.GetValue(Grid.RowProperty)

Et voilà que je peux commencer à jouer.

Mais je voudrais aller plus loin et pouvoir dropper mes objects mais qu'ils ne se chevauchent pas. Pouvoir leur donner la taille que je veux en la changeant dans un menu contextuel et toujours en évitant qu'ils ne se chevauchent.

Voilà l'exemple que je vous propose :

WPF Drag&Drop Sample CanDrop and CanResize

Vous trouverez dans le code source suivant, la création dynamique d'objets dans la grille pour détecter où les objets sont droppés. Et tout un tas d'autres astuces vous permettant de réellement bien commencer avec le Drap&Drop en WPF.

Requirements :
WPF .NET 4.0
Visual Studio 2010
Microsoft.Practices.Prism
Microsoft.Practices.Prism.Interactivity
Microsoft.Practices.Prism.UnityExtension
Microsoft.Practices.Prims.Unity

Download and Setup Prism Library 5.0 for WPF

Inutile de préciser que les packages nugets sont difficiles à installer en ce qui concerne Prism et ses différentes version, en constante modification de version de namespace... bref la résolution de vos problèmes passera peut être par l'exécution de la commande : 

PM> Install-Package CommonServiceLocator dans la "Console du gestionnaire de package" 

suivie de 

PM> Install-Package Prism.UnityExtensions -Version 4.1.0

Download Sample

Si vous souhaitez aller plus loin et notamment en fonctionnant avec le modèle MVVM, je vous recommande vivement les articles suivants :

Drag and Drop in WPF
Drag and Drop in WPF - Part II

Ce que j'apprécie vraiment dans ce Sample c'est la mise en place d'un "Adorner", une parure qui à travers  une Property DragAdornerTemplate liée à une DependencyProperty affiche une image en transparence lorsque l'on déplace les objets. Dans le Xaml de la façon suivante :

<ListBox dd:DragDrop.DragAdornerTemplate="{StaticResource PupilDragAdorner}">

Voilà je vous ai tout dis sur mes recherches en matière de Drag & Drop avec WPF. Si vous allez plus loi merci de nous faire part de vos avanceés.

Vous avez apprécié cet article, laissez un commentaire.

Prism InteractionRequest Popup a Window (2)

Dans un post précédent : Prism InteractionRequest Popup a Window (1)on a vu l'utilisation de prism:InteractionRequestTrigger pour déclencher une InteractionRequest permettant de récupérer le ViewModel d'une fenêtre secondaire et à l'intérieur de ce ViewModel une propriété publique SelectedItem. Ainsi dans la fenêtre principale on peut afficher le choix effectué par l'utilisateur dans la fenêtre secondaire :

Récupération du choix utilisateur effectué dans le module Prism HelloWorldModule

Prism Popup a Window comment ça marche ?

La fenêtre Clients implémente l'interface IPopupWindowActionAware de la Class Library Infrastructure cette interface possède deux propriétés :

namespace Infrastructure.InteractionRequests
{
    public interface IPopupWindowActionAware
    {
          Window HostWindow { get; set; }
          Notification HostNotification { get; set; }
    }
}

Et là on est au coeur de cet exemple, l'objet PopupWindowAction dérive de TriggerAction<FrameworkElement>, il utilise des DependencyProperty pour modifier l'apparence de la Popup et override la fonction void Invoke(object parameter) pour construire la Popup et faire à la fin :

// IsModal 
// public static readonly DependencyProperty IsModalProperty
if (this.IsModal)
{
wrapperWindow.ShowDialog();
}
else
{
wrapperWindow.Show();
}

Ainsi le fenêtre secondaire est ou non Modale. Oui je passe rapidement et vous laisse le soin de lire ces sources et d'évaluer leur complexité.

Prism Popup a Window conclusion

Déjà l'on voit qu'une réflexion intense doit être menée à la naissance d'un projet WPF Prism afin de décrire le comportement des différents modules et de leurs interactions. Cette réflexion (ou conception) donne naissance au projet de Class Library Infrastructure qui s'occupe du comportement MVVM des objets utilisés et interagissants dans les différents modules.

Mais ce n'est pas nouveau, il vaut mieux toujours, passer un peu de temps en conception afin d'être certain que l'architecture choisie répondre aux besoins que de se jeter à pisser du code.

Prism InteractionRequest Popup a Window (1)

Etude des sources de Damian Cherubini trouvées dans son SkyDrive et son exemple de PopupWindowsAction Sample.

Les objets mis en oeuvre sont :
Prism.UnityExtensionsPrism.UnityBootstrapper
<i:Interaction.Trigger
<prism:InteractionRequestTrigger
Prism.Interactivity.InteractionRequest
Prism.Commands.DelegateCommand
Prism.Events.EventAggregator

Architecture de du projet PopupWindowAction Sample

Un projet Windows Application "HelloWorld" utilise Prism et Unity pour charger le module "HelloWorldModule" :

namespace HelloWorld
{
    public class Bootstrapper : UnityBootstrapper
    {
        protected override void ConfigureModuleCatalog()
        {
            base.ConfigureModuleCatalog();

            ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
            moduleCatalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
        }    

Le module HelloWorldModule utilise un projet Class Librairy "Infrastructure" qui propose une interface IRegionManagerAware et un objet PopupWindowAction qui vont permettre dans les Views du HelloWorldModule de popuper des Window de la façon suivante :

<UserControl x:Class="HelloWorldModule.Views.HelloWorldView"

    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:inf_int="clr-namespace:Infrastructure.InteractionRequests;assembly=Infrastructure"
    xmlns:local="clr-namespace:HelloWorldModule.Views"
   ...>
<i:Interaction.Triggers>
        <prism:InteractionRequestTrigger SourceObject="{Binding SelectClientRequest, Mode=OneWay}">
            <inf_int:PopupWindowAction>
                <inf_int:PopupWindowAction.WindowContent>
                    <local:SelectClientView />
                </inf_int:PopupWindowAction.WindowContent>
            </inf_int:PopupWindowAction>
        </prism:InteractionRequestTrigger>
</i:Interaction.Triggers>

Des fenêtres secondaires vont permettre à l'utilisateur de choisir une série d'actions dont le résultat sera afficher dans la fenêtre principale : HelloWorldView.xaml.

PopupWindowAction Sample Prism InteractionRequest

PopupWindowAction Sample Exécution

Ici je vais focusser sur le dernier exemple de popupwindow dont la propriété SourceObject est bindée sur SelectClientRequest.

Une fois les Interaction.Trigger correctement configurées, il faut encore un bouton dont la propriété Command est bindée sur RaiseSelectClient :

<Button Margin="5" Content="Raise Select Client View" Command="{Binding RaiseSelectClient}" />

Le résultat sera afficher dans TextBlock dont la propriété Text est Bindée sur la propriété Result du ViewModel :

<TextBlock Margin="5" FontWeight="Bold" Foreground="DarkRed" Text="{Binding Result}"/>

On obtient ainsi à l'exécution de la fenêtre principal :
\\PopupWindowActionSample\HelloWorldModule\Views\HelloWorldView.xaml

Fenêtre principale de PopupWindowAction Sample
Et lorsque l'on clique sur le bouton "Raise Select Client View", on obtient la fenêtre cliente suivante  :

Client Window View
En sélectionnant "John Doe" et en cliquant sur "OK" la fenêtre principale récupère le choix utilisateur et l'on obtient le résultat suivant dans la fenêtre principal :
PopupWindowAction Sample après un choix utilisateur
On a donc bien un allé et retour d'une information, d'un choix utilisateur effectuer dans une PopupWindow et que l'on récupère pour l'afficher dans le Module Principal.

PopupWindowAction comment ça marche ?

D'une part, la propriété SourceObject (EventTriggerBase.SourceObject) de l'InteractionRequestTrigger est bindée sur la commande SelectClientRequest dans la View et dans le ViewModel on trouve le code C# suivant :

namespace HelloWorldModule.ViewModels
{
    public InteractionRequest<Notification> SelectClientRequest { get; private set; }
    public ICommand RaiseSelectClient { get; private set; }


    public HelloWorldViewModel()
    {
        this.SelectClientRequest = new InteractionRequest<Notification>();
        this.RaiseSelectClient = new DelegateCommand(this.OnRaiseSelectClient);

Avec l'utilisation de l'objet Notification, on rentre dans l'utilisation de la DLL, Microsoft.Practices.Prism.Interactivity.dll :
Microsoft.Practices.Prism.Interactivity, Notification et Confirmation
D'autre part, la commande du bouton "Raise Select Client View" est bindé sur la DelegateCommand RaiseSelectClient qui exécute l'Action OnRaiseSelectClient :

private void OnRaiseSelectClient()
{
this.SelectClientRequest.Raise(
  new Notification { Title = "Clients" });
}

Ce même mécanisme permet aux deux fonctions OnRaiseConfirmation et OnRaiseNotification de modifier la propriété Result du HelloWorldViewModel pour indiquer le résultat obtenu dans le TexBlock dont la propriété Text est Bindée sur le Result.

Dans le cas de OnRaiseSelectItem, on récupère la propriété string SelectedItem du SelectItemViewModel pour afficher le résultat.

Utilisation de l'EventAggregator pour récupérer les données du Modèle

Dans le cas de OnRaiseSelectClient, pour récupérée des données structurées du model (ClientData) , on utilise alors le mécanisme d'EventAggregator.

Dans le HelloWorldViewModel on s'enregistre à l’évènement : ClientSelectedEvent et on y inscrit l'Action ClientSelected qui sera exécutée sur réception de l'évènement :

public HelloWorldViewModel()
{

    this.eventAggregator = ServiceLocator.Current.GetInstance<EventAggregator>();
    this.eventAggregator.GetEvent<ClientSelectedEvent>().Subscribe(this.ClientSelected);
    ...
}


public void ClientSelected(ClientData client)
{
if (client != null)
{
this.Result = "The user selected the client: " + client.Name;
}
else
{
this.Result = "The user didn't select a client.";
}
}

Dans le SelectClientViewModel, on publie les données choisies par l'utilisateur :

public ClientData SelectedClient { get; set; }

protected void OkAction()
{
this.eventAggregator.GetEvent<ClientSelectedEvent>().Publish(this.SelectedClient);

if (this.HostWindow != null)
{
this.HostWindow.Close();
}
}

Et voilà comment cela fonctionne ...

PopupWindowAction le projet Infrastructure

Si je m'arrêtais là, je passerais à côté de l'un des objets principaux de ce projet. De façon classique Damian a créé un projet dans lequel il range ce qui pourrait faire partie d'un framework de base.

Et pour afficher une PopupWindow sur InteractionRequestTrigger Damian définit sa propre PopupWindowAction qui dérive de TriggerAction :

namespace Infrastructure.InteractionRequests
{
    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class PopupWindowAction : TriggerAction<FrameworkElement>
        /// <summary>
        /// The content of the child window to display as part of the popup.
        /// </summary>
        public static readonly DependencyProperty WindowContentProperty =
            DependencyProperty.Register(
                "WindowContent",
                typeof(FrameworkElement),
                typeof(PopupWindowAction),
                new PropertyMetadata(null));

Un peu d'humour dans les commentaires cela ne fait pas de mal, j'adore la rubrique TODO !

C'est objet est utilisé dans l'InteractionRequestTrigger que l'on a vu au tout début de cet article.

Franchement, je ne trouve pas cela si simple ... Et je reviendrais sur cet exemple pour compléter mon analyse de ce projet que je trouve extrêmement intéressant. Tout ce code pour afficher une ChildWindow c'est véritablement bluffant !





EventToCommand avec Prism (2)

Comment câbler une InvokeCommandAction avec un CommandParameter qui passe un MouseEventArgs afin de récupérer et d'afficher les coordonnées de la souris dans la View.

Dans EventToCommand avec Prism (1) on à déjà vu pas mal de choses sur ce sujet.

S'en est pas encore fini avec EventToCommand de Prism ? Et bien non... Je regarde les exemples de Laurent Bugnion notamment EventToCommand Sample et je réussi à câbler la plupart des RelayCommand sur des DelegateCommand par exemple de la façon suivante :

<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding SimpleCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>

Ou de la façon suivante pour le bouton qui récupère un texte en paramètre :

<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding ParameterCommand1}"
CommandParameter="{Binding Text, ElementName=ParameterTextBox}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>


Mais lorsque j'aborde l'exemple de l’ellipse (magnifique exemple de GalaSoft) qui permet d'afficher dans l'interface graphique (View) les coordonnées de la souris c'est la catastrophe. Avec une InvokeCommandAction, il est impossible de Binder une propriété CommandParameter sur quoi que se soit qui pourrait passer en paramètre à la DelagateCommand les MouseEventArgs afin d'afficher les coordonnées de la souris.

Et bien ce n'est si étonnant que cela, si on en juge par la page Starting work on Prism 4.1 c'est prévu mais pas encore intégré !

Une autre discussion du CodePlex fait bien référence à l'InvokeCommandAction mais elle ne résout pas ce problème.

Et nous voilà reparti dans les tréfonds du Framework au moins au niveau de DependencyObject .

EventToCommand avec Prims ma solution

Ma solution consiste à récupérer le code de MVVMLight : EventToCommandVS10.cs et de l'intégrer dans mon projet. Je n'ai pas choix car je pense qu'aucune solution n'est encore proposée par Prism v4.1.

InvokeCommandAction de Prims.Interactivity

namespace Microsoft.Practices.Prism.Interactivity
{
    public class InvokeCommandAction : TriggerAction<UIElement>

EventToCommand de MVVMLight 

namespace GalaSoft.MvvmLight.Command
{
    public class EventToCommand : TriggerAction<DependencyObject>

On regardera au passage ce qui est réalisé avec PassEventArgsToCommand.

EventToCommand avec Prism Code Source

Vous vous souvenez surement, j'essaye d'intégrer rapidement les frameworks MVVM, afin de voir et comprendre ce qu'ils apportent de plus par rapport à Prism ou bien trouver ce qui est déjà dans Prism. J'ai donc créé un projet MvvmFramework pour intégrer ce qui n'est pas dans Prism. Ce framework me permet de faire fonctionner mon projet WPFPrimsToolKit.

Les références de mon UserControl :
xmlns:prism="http://www.codeplex.com/prism"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mvvm.i="clr-namespace:MvvmFramework.Interactivity;assembly=FrameworkMvvm"

Me permettent de câbler mon Ellipse de la façon suivante :
<Ellipse Fill="{Binding Brushes.Brush5}"
Stroke="Black"
Margin="10,8"
Grid.ColumnSpan="2"
Grid.Row="7">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove">
<mvvm.i:EventToCommand Command="{Binding MoveMouseCommand}" 
  PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Ellipse>

Et quand je positionne ma souris dans l'ellipse verte, j'obtiens le résultat suivant :

Les MouseCoords sont affichées grâce à EventToCommand : TriggerAction<DependencyObject>

Download Source Code

Et comme un peu de code source vaut mieux qu'un long discours :

Requirements :
Visual Studio 2010 C# 
WPFToolKit
Prism v4.1







EventToCommand avec Prism (1)

Comment réaliser l'EventToCommand Dans Prism ? Au préalable je regarde rapidement comment cela est-il réalisé dans nos MVVM Framework favoris ?

CinchV2

EventToCommandTrigger

<TextBlock Style="{StaticResource aboutTextBlockStyleLinks}"
  Text="Home Page [At Codeplex]">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<CinchV2:EventToCommandTrigger
Command="{Binding AboutViewEventToVMFiredCommand}"
CommandParameter="Home"/>
</i:EventTrigger>                      
</i:Interaction.Triggers>                  
</TextBlock>

public SimpleCommand<Object, EventToCommandArgs> AboutViewEventToVMFiredCommand { get; private set; }

AboutViewEventToVMFiredCommand = new SimpleCommand<Object, EventToCommandArgs>(ExecuteAboutViewEventToVMFiredCommand);
private void ExecuteAboutViewEventToVMFiredCommand(EventToCommandArgs args)
{
switch ((String)args.CommandParameter)
{
            case "Home":

CompletedAwareCommandTrigger

<Grid x:Name="mainGrid" >
<i:Interaction.Triggers>
<CinchV2:CompletedAwareCommandTrigger 
Command="{Binding ShowActionsCommandReversed}">
<ei:GoToStateAction StateName="ShowActionsState"/>
</CinchV2:CompletedAwareCommandTrigger>

<CinchV2:CompletedAwareCommandTrigger
Command="{Binding HideActionsCommandReversed}">
<ei:GoToStateAction StateName="HideActionsState"/>
</CinchV2:CompletedAwareCommandTrigger>

</i:Interaction.Triggers>

ShowActionsCommandReversed = new SimpleCommand<Object, Object>((input) => { });

<VisualState x:Name="ShowActionsState">
/// <summary>
/// Goto "ShowActionsState", which use the VisualStateManagerService
/// </summary>
private void ExecuteShowActionsCommand(Object args)
{
ShowActionsCommandReversed.Execute(null);
}

<VisualState x:Name="HideActionsState"/>

/// <summary>
/// Goto "HideActionsState", which use the VisualStateManagerService
/// </summary>
private void ExecuteHideActionsCommand(Object args)
{
HideActionsCommandReversed.Execute(null);
}

<Label FontFamily="Wingdings" Foreground="Black"
VerticalAlignment="Center" Margin="10,5,5,5"
VerticalContentAlignment="Center"
FontSize="20" FontWeight="Normal"
Content="þ">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<CinchV2:EventToCommandTrigger 
Command="{Binding ShowActionsCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>

ShowActionsCommand = new SimpleCommand<Object, Object>(ExecuteShowActionsCommand);

GalaSoft

EventToCommand

<Button Background="{Binding Brushes.Brush3}"
Margin="10"
Style="{StaticResource ButtonStyle}"
Content="Parameter Command (Hello)"
Grid.Row="4"
ToolTipService.ToolTip="Click to activate command">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding ParameterCommand2}"
CommandParameterValue="Hello" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<cmd:EventToCommand Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

public RelayCommand<string> ParameterCommand2
{
get;
private set;
}

public MainViewModel()
{
            ParameterCommand2 = new RelayCommand<string>(p =>
            {
                Status = string.Format("Parameter command executed ({0})", p);
                LastUsedBrush = Brushes.Brush3;
            });

<Button Background="{Binding Brushes.Brush4}"
Margin="10"
Style="{StaticResource ButtonStyle}"
Content="&quot;Disablable&quot; Command"
Grid.Row="5"
ToolTipService.ToolTip="Click to activate command">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding DisablableCommand}"
CommandParameter="{Binding Text, ElementName=DisableCommandTextBox}"
MustToggleIsEnabled="{Binding IsChecked, ElementName=MustToggleCheckBox}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<cmd:EventToCommand Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

public RelayCommand<string> DisablableCommand
{
get;
private set;
}

public MainViewModel()
{
DisablableCommand = new RelayCommand<string>(p =>
{
Status = string.Format("Disablable command executed ({0})", p);
LastUsedBrush = Brushes.Brush4;
},
p => p != "Hello");

Remarques sur les implémentations de EventToCommand

Dans Cinch la SimpleCommand prend toujours deux paramètres ce qui oblige à lui passer des NULL lorsqu'il n'y a pas de paramètres on verra que dans Prism on déclare deux type de DelagateCommand.

Chez GalaSoft l'utilisation des paramètres n'est pas franchement évidente à mon goût.

EventToCommand avec Prism

Et je trouve enfin une série d'exemples grâce à deux discussion au sein du CodePlex dans Microsoft  patterns & practices: Prism

WPF PRISM modular design
Les conseils de Damian Cherubini sur une application modulaire utilisant Entity Framework.

Display Child window WPF
Exemples réalisés par Damian Cherubini, les sources sont dans son SkyDrive :

<UserControl x:Class="HelloWorldModule.Views.SelectClientView"
                               xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding ChangeDetailCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>

InvokeCommandAction se trouve dans System.Windows.Interactivity.dll
namespace HelloWorldModule.ViewModels
{
    public class SelectClientViewModel : Notification, INotifyPropertyChanged, IPopupWindowActionAware, IRegionManagerAware
    {
        public SelectClientViewModel()
        {
            this.ChangeDetailCommand = new DelegateCommand(this.ChangeDetail);

Et c'est exactement ce que je cherchais à faire !
Dans Prism il ne s'agit donc pas de EventToCommand mais de InvokeCommandAction un grand merci à Damian Cherubini dont les exemples que vous trouverez également dans son SkyDrive sont une mine d'or.

Allez plus loin sur ce blog c'est Ici.

Prism EventToCommand DependencyObject ou FrameworkElement On en est où ?

Oui c'est curieux, un élément essentiel du modèle MVVM n'existe pas encore dans Prism l'EventToCommand.

Comment Binder une commande du ViewModel directement sur un element de la View sans code behind. Posé ainsi le problème à l'air simple mais comme ce n'est pas supporté dans Prism alors chacun doit utiliser son petit bout de code.

CodePlex Patterns & Practices EventToCommand
Discussion dans CodePlex à ce propos.

Suggestion du Pattern & Practices
InvokeCommandAction qui se trouve Microsoft.Practices.Prism.Interactivity ... n'est pas encore documenté !

Oct 2016 : Whaou, je suis de retour aux affaires avec WPF-MVVM et je suis surpris de voir à quel point cet article à encore cours...

Solutions dans les différents frameworks MVVM

GalaSoft :

\\mvvmlight_0f4486b50609\GalaSoft.MvvmLight\GalaSoft.MvvmLight.Extras (NET4)\Command\EventToCommandVS10.cs
public class EventToCommand : TriggerAction<DependencyObject>
à croire que Laurent Bugnion à développe MVVMLight en fonction des versions de Visual Studio ... Mais en tous cas c'est toujours Light ;)

Oct 2016 : On trouvera maintenant un NuGet : MVVLight 5.3.0

Cinch :

\\cinch-70832\cinch\V2 (VS2010 WPF and SL)\CinchV2\Commands
EventToCommandArgs.cs
SimpleCommand.cs
WeakEventHandlerManager.cs
Et en y regardant de plus prêt les commandes utilisée pour Binder directement dans la View sont :
\\cinch-70832\cinch\V2 (VS2010 WPF and SL)\CinchV2\Interactivity\
\\Actions\CommandDrivenGoToStateAction.cs
\\Triggers\EventToCommandTrigger.cs
public class EventToCommandTrigger : TriggerAction<FrameworkElement>\\Triggers\CompletedAwareCommandTrigger.cs
public class CompletedAwareCommandTrigger : TriggerBase<FrameworkElement>\\Triggers\CompletedAwareGotoStateCommandTrigger.cs

Dans la View \\cinch-70832\cinch\V2 (VS2010 WPF and SL)\WPF_Demo\CinchV2DemoWPF\Views\ImageLoaderView.xaml :
<UserControl
      xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
      xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

<Grid x:Name="mainGrid" >
        <i:Interaction.Triggers>
            <CinchV2:CompletedAwareCommandTrigger
                         Command="{Binding ShowActionsCommandReversed}">
                <ei:GoToStateAction StateName="ShowActionsState"/>
            </CinchV2:CompletedAwareCommandTrigger>
        </i:Interaction.Triggers>

Dans le ViewModel \\cinch-70832\cinch\V2 (VS2010 WPF and SL)\WPF_Demo\CinchV2DemoWPF\ViewModels\ImageLoaderViewModel.cs :
public class ImageLoaderViewModel : ViewModelBase
{
public ImageLoaderViewModel(
            IMessageBoxService messageBoxService,
            IOpenFileService openFileService,
            ISaveFileService saveFileService,
            IUIVisualizerService uiVisualizerService,
            IImageProvider imageProvider,
            IImageDiskOperations imageDiskOperations,
            IViewAwareStatus viewAwareStatusService)
        {
             ShowActionsCommandReversed = new SimpleCommand<Object, Object>((input) => { });

public SimpleCommand<Object, Object> ShowActionsCommandReversed { get; private set; }

Oct 2016 : On trouvera maintenant un NuGet de Sacha Barber

Cinch is a Rich Full Featured WPF/SL MVVM Framework 2.0.70832

Advanced MVVM

Oct 2016 - De retour aux affaires avec WPF
Il me faut encore absolument citer Josh Smith car c'est le framework qui est souvent implanté et choisi par les développeurs.

Advanced MVVM

Et un NuGet : Ici

WPF RealTime Application d'Alexis Shelest :

\\Src\Framework\WPF.RealTime.Infrastructure\AttachedCommand\EventToCommandArgs.cs
Indentique à Cinch
\\Src\Framework\WPF.RealTime.Infrastructure\AttachedCommand\EventToCommandTrigger.cs
Plus évolué que dans Cinch
\\Src\Framework\WPF.RealTime.Infrastructure\Commands\SimpleCommand.cs
Indentique à Cinch
Je dirais bien qu'Alexis Shelest à simplifié ce qu'il a trouvé dans Cinch. Il est vrai que ce que l'on trouve dans CinchV2 est peut être un peu compliqué.

WPF/MVVM Real-Time Trading Application

CodePlex

Conclusion sur le Command Binding

Finalement le Command Binding n'est pas un problème aussi simple qu'il n'y parait, avec des problématiques de se câbler à un niveau si bas du framework que d'attaqué directement System.Windows.Interactivity et pour d'autres farfelus d'attaquer Microsoft.Practices.Prism.Interactivity InvokeCommand !.

Notons au passage les évolutions effectuées par Laurent Bugnion dans MVVMLight qui utilise maintenant System.WeakReference pour éviter les fuites mémoire.

La solution est certainement d'utiliser maintenant le module : Microsoft.Practices.Prism.Commands dont voici une partie de l'interface :

Prism v4.1 les DelegateCommand solution du Command Binding, mais je ne suis pas sûr !
Je crois que le plus surprenant c'est que tous ces objets sont basé sur :
System.Windows.Interactivity.dll qui n'est même pas dans le .NET Framework 4.0 ... Il existe donc plusieurs version de cette DLL soit pour Blend soit pour Silverlight ou bien encore WPF.

On en trouvera un exemplaire de cette DLL dans le Microsoft SDKs au fond du répertoire :
C:\Program Files\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries

EventToCommand InvokeCommandAction La Solution ?!







Prism Modularité avec MEF et Unity

Recherchant à utiliser Prism pour son modèle MVVM (et ce n'est peut être pas le meilleure idée que j'ai eu ...), et continuant mes investigations, je trouve des exemples de modularité avec Unity et d'autres avec MEF (Managed Extensibility Framework). Je passe sur la genèse mais il s'en est passé du temps avant l'intégration des frameworks Unity et MEF dans Prism.

Pourquoi ne pas utiliser les deux, ainsi on pourrait facilement intégrer des modules avec Unity ou avec MEF.

Littérature de référence

Sur le sujet de l'utilisation de Prism de Unity et de MEF on trouve la littérature suivante :

Wilfried Woiwré :

http://blog.woivre.fr/Archives/2010/3/allier-mef-et-unity

De très bonnes explications, en français. Puis il renvoie sur le projet de référence sur ce sujet de l'utilisation de Unity et de MEF le MEFContrib du CodePlex
Comprendre l'utilisation de MEF puis MEF à travers IoC :
Article.MEFContrib
Etape 3 - MEF + Factory + Unity :

Utilisation de MEFContrib intégration de Unity et MEF
Remarque : Et oui le flux RSS de Wilfried demande une authentification ...

Piotr Wlodek
http://pwlodek.blogspot.fr/2009/05/unity-mef-integration-layer.html
http://pwlodek.blogspot.fr/2009/08/improved-mef-unity-integration-layer.html

Toute cette littérature est indispensable à la compréhension de l'utilisation de MEF et de Unity et ramène vers le projet du CodePlex : MEFContrib

Prism version v4.1

Oui le projet Article.MEFContrib - Etape 3 - MEF + Factory + Unity : est livré avec un répertoire \Shared Binairies la version de la DLL Microsoft.Practices.Unity.dll est v1.2.0.0 mais j'aimerais utiliser la version de Prism v4.1 et donc la version v2.1.505 de Microsoft.Practices.Unity.dll

Et cela ne fonctionne plus :

Dans la version v1.2 :
namespace Microsoft.Practices.Unity
{
    public abstract class ExtensionContext
    {
        protected ExtensionContext();

        public abstract StagedStrategyChain<UnityBuildStage> BuildPlanStrategies { get; }
        public abstract IUnityContainer Container { get; }
        public abstract ILifetimeContainer Lifetime { get; }
        public abstract IReadWriteLocator Locator { get; }
        public abstract IPolicyList Policies { get; }
        public abstract StagedStrategyChain<UnityBuildStage> Strategies { get; }

        public abstract event EventHandler<RegisterEventArgs> Registering;
        public abstract event EventHandler<RegisterInstanceEventArgs> RegisteringInstance;

        public abstract void RegisterNamedType(Type t, string name);
    }
}

Dans la version v2.1.505 :
namespace Microsoft.Practices.Unity
{
    public abstract class ExtensionContext
    {
        protected ExtensionContext();

        public abstract StagedStrategyChain<UnityBuildStage> BuildPlanStrategies { get; }
        public abstract IUnityContainer Container { get; }
        public abstract ILifetimeContainer Lifetime { get; }
        public abstract IPolicyList Policies { get; }
        public abstract StagedStrategyChain<UnityBuildStage> Strategies { get; }

        public abstract event EventHandler<ChildContainerCreatedEventArgs> ChildContainerCreated;
        public abstract event EventHandler<RegisterEventArgs> Registering;
        public abstract event EventHandler<RegisterInstanceEventArgs> RegisteringInstance;

        public abstract void RegisterNamedType(Type t, string name);
    }
}

On remarquera que l'objet Locator a disparut c'est balo non ... ?

MEF Contrib et .NET Framework 4.0 

J'investigue pour comprendre pourquoi je ne peux pas utiliser MEF Contrib avec le framework 4.0 et Prism v4.1. Je créé un nouveau projet dans une nouvelle solution à l'aide du template :

Création d'un solution WPF MVVM Application
Et puis j'ai remarqué que l'on peut installer le package MefContrib.1.2.2.1 grâce à NuGet. J'installe donc l'ensemble de packages suivants :
Prism.4.1.0.0
Prism.MEFExtensions.4.1.0.0
CommonServiceLocator.1.0
MefContrib.1.2.2.1
MefContrib.Integration.Unity.1.2.2.1
Prism.MEFExtensions.4.1.0.0
Prism.UnityExtensions.4.1.0.0
Unity.2.1.505.2

En récupérant les sources de Article.MEFContrib je me retrouve avec le projet suivant :

Mon Application WPF MVVM avec les sources de Article.MEFContrib
Dont les références sont les suivantes :
Les références du projet WPF MWW Application with Prism and  MEFContrib
Je ne peux pas encore compiler car mon BootStrapper.cs comprend le code suivant :

    public class BootStrapper : UnityBootstrapper
    {
        public CompositionContainer MefContainer { get; private set; }

        protected override IUnityContainer CreateContainer()
        {
            var aggregateCatalog = new AggregateCatalog(new ComposablePartCatalog[] { new DirectoryCatalog(@".\Extensions") });
            var unityContainer = new UnityContainer();
            MefContainer = unityContainer.RegisterFallbackCatalog(aggregateCatalog);

            return unityContainer;
        }

La fonction RegisterFallbackCatalog est définie dans la Class UnityContainerExtensions que j'ai pourtant intégrée dans mon projet !?

using MefContrib.Integration.Unity;
using MefContrib.Integration.Unity.Exporters;
using MefContrib.Integration.Unity.Extensions;
using Microsoft.Practices.Unity;

namespace WpfMvvmApplicationPrimsNuGet.Extensions
{
    public static class UnityContainerExtensions
    {

        public static CompositionContainer RegisterFallbackCatalog(this IUnityContainer unityContainer, ComposablePartCatalog catalog)
        {
            lock(unityContainer)
            {
                var compositionIntegration = GetOrInitCompositionIntegration(unityContainer);
                compositionIntegration.Catalogs.Add(catalog);
                return compositionIntegration.CompositionContainer;
            }
        }



J'ai bien les using qui conviennent vers les packages que j'ai installés grâce à NuGet mais quand je regarde à l'intérieur grâce à l'Object Browser c'est la stupeur !

D'un côté dans le projet Article.MEFContrib j'ai :
A l'intérieur du package MefContrib.Integration.Unit du projet Article.MEFcontrib
Tandis que dans le projet que je viens de créer :
A l'intérieur du package MefContrib.Integration.Unit du projet Article.MEFcontrib
Ce qui n'est sensiblement pas le même contenu !

Conclusion sur le projet Article.MEFContrib

Personnellement je ne comprends pas l'erreur que j'ai commise. J'en déduis que le projet Article.MEFContrib utilise ses propres codes sources de "MEFContrib" et n'est pas compatible avec les packages MEFContrib installés par NuGet.

Il va donc falloir que je reprenne les exemples utilisant le MEFContrib installé par les NuGet packages afin de pouvoir enfin intégrer l'utilisation de MEF ET Unity dans mon propre projet.

Vous avez une idée quelque chose de plus simple, n'hésitez pas à m'en faire part.