Tôi đã gặp vấn đề tương tự và tôi đã đưa ra giải pháp. Tôi tìm thấy câu hỏi này sau khi tôi giải quyết nó và tôi thấy rằng giải pháp của tôi có rất nhiều điểm chung với của Mark. Tuy nhiên, cách tiếp cận này có một chút khác biệt.
Vấn đề chính là các hành vi và trình kích hoạt liên kết với một đối tượng cụ thể và do đó bạn không thể sử dụng cùng một trường hợp của một hành vi cho nhiều đối tượng liên kết khác nhau. Khi bạn xác định hành vi của mình, XAML nội dòng sẽ thực thi mối quan hệ 1-1 này. Tuy nhiên, khi bạn cố gắng thiết lập một hành vi trong một kiểu, kiểu đó có thể được sử dụng lại cho tất cả các đối tượng mà nó áp dụng và điều này sẽ đưa ra các ngoại lệ trong các lớp hành vi cơ sở. Trên thực tế, các tác giả đã nỗ lực đáng kể để ngăn chặn chúng tôi thậm chí cố gắng làm điều này, biết rằng nó sẽ không hiệu quả.
Vấn đề đầu tiên là chúng ta thậm chí không thể xây dựng một giá trị bộ cài đặt hành vi vì hàm tạo là bên trong. Vì vậy, chúng ta cần các lớp thu thập hành vi và kích hoạt của riêng mình.
Vấn đề tiếp theo là các thuộc tính đính kèm hành vi và trình kích hoạt không có bộ định tuyến và vì vậy chúng chỉ có thể được thêm vào với XAML nội dòng. Vấn đề này chúng tôi giải quyết với các thuộc tính đính kèm của riêng chúng tôi thao tác các hành vi chính và thuộc tính kích hoạt.
Vấn đề thứ ba là bộ sưu tập hành vi của chúng tôi chỉ tốt cho một mục tiêu kiểu duy nhất. Điều này chúng tôi giải quyết bằng cách sử dụng một tính năng XAML ít được sử dụng x:Shared="False"
để tạo ra một bản sao mới của tài nguyên mỗi khi nó được tham chiếu.
Vấn đề cuối cùng là các hành vi và trình kích hoạt không giống như các trình thiết lập kiểu khác; chúng tôi không muốn thay thế các hành vi cũ bằng các hành vi mới bởi vì chúng có thể làm những điều cực kỳ khác biệt. Vì vậy, nếu chúng tôi chấp nhận rằng một khi bạn thêm một hành vi mà bạn không thể xóa nó đi (và đó là cách các hành vi hiện đang hoạt động), chúng tôi có thể kết luận rằng các hành vi và trình kích hoạt phải là phụ gia và điều này có thể được xử lý bởi các thuộc tính đính kèm của chúng tôi.
Đây là một ví dụ sử dụng cách tiếp cận này:
<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>
Ví dụ sử dụng trình kích hoạt nhưng các hành vi hoạt động theo cùng một cách. Trong ví dụ, chúng tôi hiển thị:
- phong cách có thể được áp dụng cho nhiều khối văn bản
- một số loại liên kết dữ liệu đều hoạt động chính xác
- một hành động gỡ lỗi tạo ra văn bản trong cửa sổ đầu ra
Đây là một hành vi ví dụ, của chúng tôi DebugAction
. Nói đúng hơn nó là một hành động nhưng thông qua việc lạm dụng ngôn ngữ mà chúng ta gọi là hành vi, tác nhân và hành động là "hành vi".
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);
}
}
Cuối cùng, bộ sưu tập của chúng tôi và các thuộc tính đính kèm để làm cho tất cả điều này hoạt động. Tương tự với Interaction.Behaviors
, thuộc tính mà bạn nhắm mục tiêu được gọi SupplementaryInteraction.Behaviors
vì bằng cách đặt thuộc tính này, bạn sẽ thêm các hành vi vào Interaction.Behaviors
và tương tự như vậy cho các trình kích hoạt.
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);
}
}
và ở đó bạn có nó, các hành vi và kích hoạt đầy đủ chức năng được áp dụng thông qua các kiểu.