J'ai eu le même problème et j'ai trouver une solution. J'ai trouvé cette question après je l'ai résolu, et je vois que ma solution porte beaucoup en commun avec Marc. Cependant, cette approche est un peu différente.
Le principal problème est que les comportements et les déclencheurs de l'associer à un objet spécifique, et donc vous ne pouvez pas utiliser la même instance d'un comportement pour différents objets associés. Lorsque vous définissez votre comportement XAML inline applique ce one-to-one relation. Toutefois, lorsque vous essayez de définir un comportement dans un style, le style peut être à nouveau utilisé pour tous les objets auxquels elle s'applique et cela permettra de lancer des exceptions dans la base de classes de comportement. En fait, les auteurs ont fait des efforts considérables pour nous empêcher de même essayer de faire ça, sachant que ça ne marcherait pas.
Le premier problème est que nous ne pouvons même pas construire un comportement de poseur de valeur parce que le constructeur est interne. Donc, nous avons besoin de notre propre comportement et de déclencher des classes de collection.
Le problème suivant est que le comportement et déclencher des propriétés attachées n'ont pas les setters et donc ils ne peuvent être ajoutés à avec en ligne de XAML. Ce problème, nous avons à résoudre avec nos propres propriétés attachées manipuler la primaire le comportement et les propriétés d'un trigger.
Le troisième problème est que notre comportement collection est seulement bon pour un style unique cible. Cela nous résoudre en utilisant un peu utilisé le XAML fonctionnalité x:Shared="False"
qui crée une nouvelle copie de la ressource à chaque fois qu'il est référencé.
Le dernier problème est que les comportements et les déclencheurs ne sont pas comme les autres style setters; nous ne voulons pas remplacer les vieilles habitudes avec les nouveaux comportements parce qu'elles pourraient faire différer considérablement les choses. Donc, si nous acceptons qu'une fois que vous ajoutez un comportement que vous ne peut le prendre loin (et c'est la façon dont les comportements travaille actuellement), nous pouvons conclure que les comportements et les déclencheurs doivent être additif, ce qui peut être pris en charge par nos propriétés attachées.
Voici un exemple de l'utilisation de cette approche:
<Grid>
<Grid.Resources>
<sys:String x:Key="stringResource1">stringResource1</sys:String>
<local:Triggers x:Key="debugTriggers" x:Shared="False">
<i:EventTrigger EventName="MouseLeftButtonDown">
<local:DebugAction Message="DataContext: {0}" MessageParameter="{Binding}"/>
<local:DebugAction Message="ElementName: {0}" MessageParameter="{Binding Text, ElementName=textBlock2}"/>
<local:DebugAction Message="Mentor: {0}" MessageParameter="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}}"/>
</i:EventTrigger>
</local:Triggers>
<Style x:Key="debugBehavior" TargetType="FrameworkElement">
<Setter Property="local:SupplementaryInteraction.Triggers" Value="{StaticResource debugTriggers}"/>
</Style>
</Grid.Resources>
<StackPanel DataContext="{StaticResource stringResource1}">
<TextBlock Name="textBlock1" Text="textBlock1" Style="{StaticResource debugBehavior}"/>
<TextBlock Name="textBlock2" Text="textBlock2" Style="{StaticResource debugBehavior}"/>
<TextBlock Name="textBlock3" Text="textBlock3" Style="{StaticResource debugBehavior}"/>
</StackPanel>
</Grid>
L'exemple utilise des déclencheurs, mais les comportements de travailler de la même façon. Dans l'exemple, nous montrons:
- le style peut être appliqué à plusieurs blocs de texte
- plusieurs types de liaison de données fonctionnent toutes correctement
- une action de débogage qui génère le texte dans la fenêtre de sortie
Voici un exemple de comportement, nos DebugAction
. Plus correctement, il est une action, mais par abus de langage, nous appelons les comportements, les déclencheurs et les actions de "comportements".
public class DebugAction : TriggerAction<DependencyObject>
{
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(DebugAction), new UIPropertyMetadata(""));
public object MessageParameter
{
get { return (object)GetValue(MessageParameterProperty); }
set { SetValue(MessageParameterProperty, value); }
}
public static readonly DependencyProperty MessageParameterProperty =
DependencyProperty.Register("MessageParameter", typeof(object), typeof(DebugAction), new UIPropertyMetadata(null));
protected override void Invoke(object parameter)
{
Debug.WriteLine(Message, MessageParameter, AssociatedObject, parameter);
}
}
Enfin, nos collections et des propriétés attachées au travail. Par analogie avec l' Interaction.Behaviors
, la propriété de la cible est appelé SupplementaryInteraction.Behaviors
parce que, par la définition de cette propriété, vous pourrez ajouter des comportements à Interaction.Behaviors
et de même pour les déclencheurs.
public class Behaviors : List<Behavior>
{
}
public class Triggers : List<TriggerBase>
{
}
public static class SupplementaryInteraction
{
public static Behaviors GetBehaviors(DependencyObject obj)
{
return (Behaviors)obj.GetValue(BehaviorsProperty);
}
public static void SetBehaviors(DependencyObject obj, Behaviors value)
{
obj.SetValue(BehaviorsProperty, value);
}
public static readonly DependencyProperty BehaviorsProperty =
DependencyProperty.RegisterAttached("Behaviors", typeof(Behaviors), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyBehaviorsChanged));
private static void OnPropertyBehaviorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behaviors = Interaction.GetBehaviors(d);
foreach (var behavior in e.NewValue as Behaviors) behaviors.Add(behavior);
}
public static Triggers GetTriggers(DependencyObject obj)
{
return (Triggers)obj.GetValue(TriggersProperty);
}
public static void SetTriggers(DependencyObject obj, Triggers value)
{
obj.SetValue(TriggersProperty, value);
}
public static readonly DependencyProperty TriggersProperty =
DependencyProperty.RegisterAttached("Triggers", typeof(Triggers), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyTriggersChanged));
private static void OnPropertyTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var triggers = Interaction.GetTriggers(d);
foreach (var trigger in e.NewValue as Triggers) triggers.Add(trigger);
}
}
et là vous l'avez, entièrement fonctionnelle des comportements et des déclencheurs appliquée à travers les styles.