vendredi 19 mars 2010 13:42
JeremyJeanson
[WF4] Un Binding Activity/ActivityDesigner qui passe mal?
Certain d’entre vous on peut être vécu cette situation embarrassante après quelques temps passer avec WF4 :
Au début avec mon “ActivityDesigner”, tout allait bien. Et puis un jour j’ai au des problèmes de “Binding”. Alors nous sommes allé sur le site VivreMonActiyfityDesigner.fr…
Trêve de plaisanterie : Vous avez commencé à vouloir coder des activités qui sortent de l’ordinaire et dont le Binding ne peut être fait sur des contrôles de base de WF4. Vous avez besoin de faire un Binding sur des contrôles plus classiques comme des Textblock ou Textbox mais le choses ne se passent pas bien : Ce qui est modifié sur l’activité ne remonte pas à l’interface.
La faute à qui? WPF? Un Xaml qui différerait entre WF4 et WPF?
Commençons par reconstituer le soucis : j’ai crée une activité qui a une propriété nommée Time qui contient une String et qui est mise à jour par un Designer.
Vb
Imports System.Activities
Imports System.ComponentModel
<Designer(GetType(MyActivityDesigner))>
Public NotInheritable Class MyActivity
Inherits CodeActivity
Public Property Time() As String
Protected Overrides Sub Execute(ByVal context As CodeActivityContext)
'...
End Sub
End Class
C#
using System;
using System.Activities;
using System.ComponentModel;
[Designer(typeof(MyActivityDesigner))]
public sealed Class MyActivity : CodeActivity
{
public String Time { get; set; }
protected override void Execute(CodeActivityContext context)
{
//...
}
}
Xaml
<sap:ActivityDesigner x:Class="MyActivityDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
<StackPanel>
<TextBlock Text="{Binding Path=ModelItem.Time}"/>
<Button Content="Update" Click="Button_Click"/>
</StackPanel>
</sap:ActivityDesigner>
Avec une méthode Button_Click contenant le code suivant :
Vb
Dim activity As MyActivity = CType(Me.ModelItem.GetCurrentValue(), MyActivity)
activity.Time = DateTime.Now.ToString()
C#
MyActivity as activity = (MyActivity)this.ModelItem.GetCurrentValue();
activity.Time = DateTime.Now.ToString();
Vous avez donc une interface qui ressemble à ceci :
Malheureusement quand on fait un click sur votre bouton votre TextBlock n’est pas mis à jour. L’explication à ce phénomène est simple. Vous n’avez pas saisi le fonctionnement du ModelItem. Et donc vous l’utilisez mal.
Je ne vais pas faire un long discours sur le ModelItem . Je pense que j’y reviendrai plus tard dans un article plus complet. Pour faire simple : le ModelItem est un proxy qui a pour mission de s’intercaler entre votre interface et votre activité.
Un petit graphe est toujours plus simple :
Mais le code votre code contient un appel à l’activité. On se retrouve donc avec une association (mise en rouge ici) entre votre ActivityDesigner et son activité. Ce qui ne cadre pas avec l’utilisation du ModelItem. C’est un peu comme si on utilisait un service WCF pour expose une entité qu’il manipule via a une DAL côté serveur mais qu’on utilisait directement sa DAL côté client?!!!
Votre souci est bien là!
Vous devez utiliser le ModelItem pour piloter l’activité. heureusement le ModelItem a un utilisation très simple comme le démontre le code suivant:
Vb
Me.ModelItem.Properties("Time").SetValue(DateTime.Now.ToString())
C#
this.ModelItem.Properties["Time"].SetValue(DateTime.Now.ToString());
Et comme par miracle notre Binding est opérationnel :
Moralité : Avant de grogner après un Binding WPF, il vaut mieux lire la documentation ;)
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :