Ich hatte das gleiche Problem und habe eine Lösung gefunden. Ich habe diese Frage gefunden, nachdem ich sie gelöst habe, und ich sehe, dass meine Lösung viel mit der von Mark gemeinsam hat. Dieser Ansatz ist jedoch etwas anders.
Das Hauptproblem besteht darin, dass Verhaltensweisen und Auslöser einem bestimmten Objekt zugeordnet sind und Sie daher nicht dieselbe Instanz eines Verhaltens für mehrere verschiedene zugeordnete Objekte verwenden können. Wenn Sie Ihr Verhalten inline definieren, erzwingt XAML diese Eins-zu-Eins-Beziehung. Wenn Sie jedoch versuchen, ein Verhalten in einem Stil festzulegen, kann der Stil für alle Objekte wiederverwendet werden, auf die er angewendet wird, und dies löst Ausnahmen in den Basisverhaltensklassen aus. Tatsächlich haben die Autoren erhebliche Anstrengungen unternommen, um zu verhindern, dass wir dies überhaupt versuchen, da wir wussten, dass es nicht funktionieren würde.
Das erste Problem ist, dass wir nicht einmal einen Verhaltenssetzwert erstellen können, da der Konstruktor intern ist. Wir brauchen also unser eigenes Verhalten und lösen Sammlungsklassen aus.
Das nächste Problem besteht darin, dass das Verhalten und die angehängten Trigger-Eigenschaften keine Setter haben und daher nur mit Inline-XAML hinzugefügt werden können. Dieses Problem lösen wir mit unseren eigenen angehängten Eigenschaften, die das primäre Verhalten manipulieren und Eigenschaften auslösen.
Das dritte Problem ist, dass unsere Verhaltenssammlung nur für ein einzelnes Stilziel geeignet ist. Dies lösen wir, indem wir eine wenig genutzte XAML-Funktion verwenden, x:Shared="False"
die bei jedem Verweis eine neue Kopie der Ressource erstellt.
Das letzte Problem ist, dass Verhalten und Auslöser nicht wie bei anderen Stilgebern sind. Wir wollen die alten Verhaltensweisen nicht durch die neuen ersetzen, weil sie ganz andere Dinge tun könnten. Wenn wir also akzeptieren, dass Sie ein einmal hinzugefügtes Verhalten nicht mehr entfernen können (und so funktionieren Verhaltensweisen derzeit), können wir daraus schließen, dass Verhalten und Auslöser additiv sein sollten und dies durch unsere angehängten Eigenschaften behandelt werden kann.
Hier ist ein Beispiel für diesen Ansatz:
<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>
In diesem Beispiel werden Trigger verwendet, aber das Verhalten funktioniert genauso. Im Beispiel zeigen wir:
- Der Stil kann auf mehrere Textblöcke angewendet werden
- Verschiedene Arten der Datenbindung funktionieren ordnungsgemäß
- Eine Debug-Aktion, die Text im Ausgabefenster generiert
Hier ist ein Beispiel für unser Verhalten DebugAction
. Eigentlich ist es eine Handlung, aber durch den Missbrauch der Sprache nennen wir Verhaltensweisen, Auslöser und Handlungen "Verhaltensweisen".
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);
}
}
Schließlich unsere Sammlungen und angehängten Eigenschaften, damit dies alles funktioniert. In Analogie zu Interaction.Behaviors
wird die Eigenschaft aufgerufen, auf die Sie abzielen, SupplementaryInteraction.Behaviors
da Sie durch Festlegen dieser Eigenschaft Verhaltensweisen zu Interaction.Behaviors
und ebenfalls für Trigger hinzufügen .
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);
}
}
und da haben Sie es, voll funktionsfähige Verhaltensweisen und Trigger, die durch Stile angewendet werden.