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.
Durch die Zusammenfassung der Antworten und diesen großartigen Artikel „ Verhalten in Stilen mischen“ kam ich zu dieser generischen kurzen und praktischen Lösung:
Ich habe eine generische Klasse erstellt, die von jedem Verhalten geerbt werden kann.
Sie können es also einfach mit vielen Komponenten wie diesen wiederverwenden:
Und in XAML genug, um zu erklären:
Grundsätzlich hat die AttachableForStyleBehavior-Klasse xaml-Dinge erstellt und die Verhaltensinstanz für jede Komponente im Stil registriert. Weitere Details finden Sie unter dem Link.
quelle
1.Erstellen Sie die angehängte Eigenschaft
2.Erstellen Sie ein Verhalten
3.Erstellen Sie einen Stil und legen Sie die angehängte Eigenschaft fest
quelle
Ich habe eine andere Idee, um die Erstellung einer angehängten Eigenschaft für jedes Verhalten zu vermeiden:
Benutzeroberfläche zum Erstellen von Verhalten:
Kleine Helfer-Sammlung:
Hilfsklasse, die das Verhalten anhängt:
Nun Ihr Verhalten, das IBehaviorCreator implementiert:
Und jetzt benutze es in xaml:
quelle
Ich konnte den Originalartikel nicht finden, aber ich konnte den Effekt neu erstellen.
quelle
Der Verhaltenscode erwartet ein Visual, daher können wir es nur auf einem Visual hinzufügen. Die einzige Option, die ich sehen konnte, ist das Hinzufügen zu einem der Elemente in der ControlTemplate, um das Verhalten dem Stil hinzuzufügen und die gesamte Instanz eines bestimmten Steuerelements zu beeinflussen.
quelle
Der Artikel Einführung in angehängte Verhaltensweisen in WPF implementiert ein angehängtes Verhalten nur mit Stil und kann auch verwandt oder hilfreich sein.
Mit der Technik im Artikel "Einführung in angehängte Verhaltensweisen" werden die Interaktivitäts-Tags mithilfe von "Stil" vollständig vermieden. Ich weiß nicht, ob dies nur daran liegt, dass es sich um eine veraltete Technik handelt oder ob dies noch einige Vorteile bringt, wenn man es in einigen Szenarien bevorzugen sollte.
quelle
Ich mag den Ansatz, den die Antworten von Roman Dvoskin und Jonathan Allen in diesem Thread zeigen. Als ich diese Technik zum ersten Mal lernte, profitierte ich von diesem Blog-Beitrag, der mehr Erklärungen zu dieser Technik enthält. Um alles im Kontext zu sehen, finden Sie hier den gesamten Quellcode für die Klasse, über die der Autor in seinem Blogbeitrag spricht.
quelle
Individuelles Verhalten / Auslöser als Ressourcen deklarieren:
Fügen Sie sie in die Sammlung ein:
quelle
Basierend auf dieser Antwort habe ich eine einfachere Lösung gefunden, bei der nur eine Klasse benötigt wird und es nicht erforderlich ist, etwas anderes in Ihr Verhalten zu implementieren.
und die Beispielverwendung ist
Vergessen Sie nicht, diese XML-Dateien hinzuzufügen, um ArrayList zu verwenden:
quelle