Affichage des articles dont le libellé est InvokeCommandAction. Afficher tous les articles
Affichage des articles dont le libellé est InvokeCommandAction. Afficher tous les articles

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.