私は同じ問題を抱えていて、解決策を考え出しました。私はそれを解決した後にこの質問を見つけました、そして私は私の解決策がマークのものと多くの共通点を持っているのを見る。ただし、このアプローチは少し異なります。
主な問題は、ビヘイビアとトリガーが特定のオブジェクトに関連付けられているため、複数の異なる関連付けられたオブジェクトにビヘイビアの同じインスタンスを使用できないことです。動作をインラインで定義すると、XAMLはこの1対1の関係を適用します。ただし、スタイルにビヘイビアーを設定しようとすると、そのスタイルが適用されるすべてのオブジェクトに再利用される可能性があり、これにより基本ビヘイビアークラスで例外がスローされます。実際、著者は、それが機能しないことを知って、私たちがこれを行おうとさえしないようにかなりの努力をしました。
最初の問題は、コンストラクターが内部であるため、動作セッター値を構築することさえできないことです。したがって、独自の動作とトリガーコレクションクラスが必要です。
次の問題は、ビヘイビアーとトリガーがアタッチされたプロパティにセッターがないため、インラインXAMLでのみ追加できることです。この問題は、主要な動作を操作し、プロパティをトリガーする独自のアタッチされたプロパティを使用して解決します。
3番目の問題は、動作コレクションが単一のスタイルターゲットにのみ適していることです。これは、あまり使用されていない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);
}
}
これで、完全に機能する動作とトリガーがスタイルを通じて適用されます。