2009-09-28 9 views
10

J'explore le mécanisme des comportements attachés Silverlight afin d'utiliser le modèle Model-View-ViewModel dans mes applications Silverlight. Pour commencer, j'essaye de faire fonctionner un simple Hello World, mais je suis complètement coincé dans une erreur pour laquelle je ne suis pas capable de trouver une solution.Erreur lors de la liaison d'une propriété Dependency sur un comportement personnalisé

Ce que j'ai en ce moment est une page qui contient juste un bouton qui devrait afficher un message quand on clique dessus. L'événement click est géré en utilisant une classe dérivée de Behavior, et le message est spécifié en tant que propriété de dépendance du comportement lui-même. Le problème survient lorsque vous tentez de lier la propriété de message à une propriété sur une classe viewmodel utilisée comme contexte de données: l'affichage de l'appel indique InitializeComponent dans la vue.

Voici tout le code que j'utilise, comme vous pouvez le voir, c'est plutôt simple. Tout d'abord le balisage de la page principale et la vue qu'elle contient:


MaPage

<UserControl x:Class="MyExample.MyPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:MyExample" 
    > 
    <Grid x:Name="LayoutRoot"> 
     <local:MyView/> 
    </Grid> 
</UserControl> 


MyView (TextBlock est là juste pour vérifier que la syntaxe de liaison est correcte)

<UserControl x:Class="MyExample.MyView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
    xmlns:local="clr-namespace:MyExample" 
    Width="400" Height="300"> 
    <StackPanel Orientation="Vertical" x:Name="LayoutRoot" Background="White"> 
     <StackPanel.Resources> 
      <local:MyViewmodel x:Key="MyResource"/> 
     </StackPanel.Resources> 
     <TextBlock Text="This button will display the following message:"/> 
     <TextBlock Text="{Binding MyMessage, Source={StaticResource MyResource}}" FontStyle="Italic"/> 
     <Button x:Name="MyButton" Content="Click me!"> 
      <i:Interaction.Behaviors> 
       <local:MyBehavior Message="{Binding MyMessage, Source={StaticResource MyResource}}"/> 
      </i:Interaction.Behaviors> 
     </Button> 
    </StackPanel> 
</UserControl> 


Maintenant le code, il y a deux classes: l'une pour le comportement et l'autre pour le viewmodel:

MyViewmodel

public class MyViewmodel 
{ 
    public string MyMessage 
    { 
     get { return "Hello, world!"; } 
    } 
} 


MyBehavior

public class MyBehavior : Behavior<Button> 
{ 
    public static readonly DependencyProperty MessageProperty = 
     DependencyProperty.Register("Message", 
     typeof(string), typeof(MyBehavior), 
     new PropertyMetadata("(no message)")); 

    public string Message 
    { 
     get { return (string)GetValue(MessageProperty); } 
     set { SetValue(MessageProperty, value); } 
    } 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     AssociatedObject.Click += new RoutedEventHandler(AssociatedObject_Click); 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
     AssociatedObject.Click -= new RoutedEventHandler(AssociatedObject_Click); 
    } 

    void AssociatedObject_Click(object sender, RoutedEventArgs e) 
    { 
     MessageBox.Show(Message); 
    } 
} 


Simple assez, mais Ce code renvoie AG_E_PARSER_BAD_PROPERTY_VALUE [Line: 15 Position: 43] (au début de la valeur définie pour la propriété Message) lors de l'exécution. Je suis sûr qu'il me manque quelque chose, mais quoi?

Informations supplémentaires: si je supprime la liaison de la propriété Message sur MyBehavior (c'est-à-dire si je définissez sa valeur à une chaîne statique), cela fonctionne correctement. En outre, je vise silverlight 3 RTW.

Merci beaucoup!


MISE À JOUR

Il semble que, contrairement à WPF, Silverlight ne prend pas en charge la liaison de données sur un objet provenant de DependencyObject, mais seulement sur des objets provenant de FrameworkElement. Ce n'est pas le cas pour Behavior, donc la liaison ne fonctionne pas.

J'ai trouvé une solution de contournement here, sous la forme de quelque chose appelé liants de substitution. Fondamentalement, vous spécifiez l'élément et la propriété à lier, ainsi que la valeur, en tant qu'attributs de FrameworkElement contenant l'objet non-FrameworkElement.


UPDATE 2

Le liant de remplacement ne fonctionne pas lorsque le FrameworkElement contient un sous-élément Interaction.Behaviors. J'ai trouvé une autre solution here, et celle-ci semble fonctionner. Cette fois, l'astuce utilisée est un DeepSetter. Vous définissez l'un de ces setters comme une ressource statique sur le StackPanel contenant, puis référencez la ressource à partir du comportement. Donc, dans mon exemple, nous devrions élargir la section des ressources StackPanel comme suit:

<StackPanel.Resources> 
    <local:MyViewmodel x:Key="MyResource"/> 
    <local:DeepSetter 
     x:Key="MyBehaviorSetter" 
     TargetProperty="Message" 
     BindingExport="{Binding MyMessage, Source={StaticResource MyResource}}"/> 
</StackPanel.Resources> 

... et modifier la déclaration de comportement du bouton comme suit:

<local:MyBehavior local:DeepSetter.BindingImport="{StaticResource MyBehaviorSetter}"/> 

MISE À JOUR 3

Bonne nouvelles: la liaison de données pour tout DependecyObject sera disponible sur Silverlight 4: http://timheuer.com/blog/archive/2009/11/18/whats-new-in-silverlight-4-complete-guide-new-features.aspx#dobind

+1

J'utilise un comportement avec un DP personnalisé avec SL 4, je n'ai pas d'erreur mais la liaison n'est pas utilisée ie le getter/setter de la source n'est jamais appelée. As-tu essayé ? – MatthieuGD

+0

Je suis enfermé dans SilverLight3 donc j'ai fait une méthode d'extension qui me permet d'extraire un comportement d'un contrôle et de définir la propriété désirée. C'est hacky mais ne pouvait pas le faire fonctionner autrement. – jtruelove

Répondre

1

Pour obtenir le support DataBinding dont la classe doit hériter de FrameworkElement.Hoping MSFT va prendre en charge dans Silverlight 4

+0

En effet, cela est pris en charge dans Silverlight 4: http://timheuer.com/blog/archive/2009/11/18/whats-new-in-silverlight-4-complete-guide-new-features.aspx#dobind – Konamiman

Questions connexes