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 :

wf4_binding_model0

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 :

wf4_binding_model2

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?!!!

wf4_binding_model3

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 :

wf4_binding_model1

Moralité : Avant de grogner après un Binding WPF, il vaut mieux lire la documentation ;)