ฉันมีปัญหาเดียวกันและหาทางแก้ไขได้ ฉันพบคำถามนี้หลังจากที่ฉันแก้ไขแล้วและฉันเห็นว่าวิธีแก้ปัญหาของฉันเหมือนกันมากกับของมาร์ค อย่างไรก็ตามแนวทางนี้แตกต่างกันเล็กน้อย
ปัญหาหลักคือพฤติกรรมและทริกเกอร์เชื่อมโยงกับอ็อบเจ็กต์เฉพาะดังนั้นคุณจึงไม่สามารถใช้อินสแตนซ์เดียวกันของพฤติกรรมสำหรับอ็อบเจ็กต์ที่เกี่ยวข้องหลาย ๆ อัน เมื่อคุณกำหนดพฤติกรรมของคุณ 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);
}
}
และคุณก็มีพฤติกรรมและทริกเกอร์ที่ใช้งานได้อย่างสมบูรณ์ผ่านสไตล์