У мене була та сама проблема, і я придумав рішення. Я знайшов це питання після того, як вирішив його, і бачу, що моє рішення має багато спільного з Марковим. Однак цей підхід дещо інший.
Основна проблема полягає в тому, що поведінка та тригери асоціюються з певним об'єктом, і тому ви не можете використовувати один і той же екземпляр поведінки для кількох різних асоційованих об'єктів. Коли ви визначаєте свою поведінку, вбудований XAML застосовує цей взаємозв'язок один до одного. Однак при спробі встановити поведінку в стилі стиль можна повторно використовувати для всіх об'єктів, до яких він застосовується, і це призведе до винятків у базових класах поведінки. Насправді автори доклали чимало зусиль, щоб не дати нам навіть спробувати це зробити, знаючи, що це не спрацює.
Перша проблема полягає в тому, що ми навіть не можемо сконструювати значення параметра встановлення поведінки, оскільки конструктор є внутрішнім. Отже, нам потрібна наша власна поведінка та активація класів колекції.
Наступна проблема полягає в тому, що властивості поведінки та прикріплених тригерів не мають установок, і тому їх можна додавати лише за допомогою вбудованого XAML. Цю проблему ми вирішуємо за допомогою власних прикріплених властивостей, які маніпулюють первинною поведінкою та властивостями тригера.
Третя проблема полягає в тому, що наша колекція поведінки корисна лише для однієї цільової стилістики. Це ми вирішуємо, використовуючи мало використовувану функцію XAML, x:Shared="False"
яка створює нову копію ресурсу кожного разу, коли на нього посилається.
Нарешті, проблема полягає в тому, що поведінка та тригери не схожі на інші встановлення стилів; ми не хочемо замінювати стару поведінку новою поведінкою, оскільки вони могли робити дико різні речі. Отже, якщо ми визнаємо, що як тільки ви додасте поведінку, ви не можете її забрати (і саме так зараз працює поведінка), ми можемо зробити висновок, що поведінка та тригери повинні бути адитивними, і це може бути оброблено нашими прикріпленими властивостями.
Ось зразок із використанням цього підходу:
<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>
У прикладі використовуються тригери, але поведінка працює однаково. У прикладі ми показуємо:
- стиль можна застосувати до декількох текстових блоків
- кілька типів прив'язки даних працюють правильно
- дія налагодження, яка генерує текст у вікні виводу
Ось приклад поведінки, наш DebugAction
. Більш правильно це дія, але через зловживання мовою ми називаємо поведінку, тригери та дії "поведінкою".
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);
}
}
Нарешті, наші колекції та додані властивості, щоб все це працювало. За аналогією з Interaction.Behaviors
властивістю, на яку ви націлюєтесь, викликається, SupplementaryInteraction.Behaviors
оскільки, встановивши цю властивість, ви додасте поведінку до Interaction.Behaviors
тригерів, а також до них.
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);
}
}
і ось у вас це, повнофункціональна поведінка та тригери, застосовані через стилі.