将XAML行为附加到相同类型的所有控件

时间:2016-04-11 17:11:09

标签: wpf xaml attachedbehaviors

我有一个InvokeCommandAction附加到GotFocus的{​​{1}}事件,如此:

TextBox

这样做很好,但我有几十个<TextBox Grid.Row="0" Grid.Column="1" Width="40" HorizontalAlignment="Right"> <i:Interaction.Triggers> <i:EventTrigger EventName="GotFocus"> <i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="Enter data [message to be displayed]" /> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> es使用相同的设置。我希望只是将该触发器附加到TextBox类型的所有控件上,而不是重复代码(正如我目前为每个代码所做的那样)。

通常,我会在{x:Type TextBox}部分设置属性,如下所示:

Resources

不幸的是,这不适用于<UserControl.Resources> <Style TargetType="TextBlock"> <Setter Property="Padding" Value="5,0,0,0" /> <Setter Property="VerticalAlignment" Value="Center" /> </Style> </UserControl.Resources>

  

附加属性“触发器”只能应用于从“DependencyObject”派生的类型。

理想情况下,我想做这样的事情:

Triggers

然后我只需要设置每个<UserControl.Resources> <Style TargetType="{x:Type TextBox}"> <i:Interaction.Triggers> <i:EventTrigger EventName="GotFocus"> <i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="{Binding Tag}" /> </i:EventTrigger> </i:Interaction.Triggers> </Style> </UserControl.Resources> 的{​​{1}}属性来指定要显示的消息。我是在正确的轨道上吗?我是否需要将其更改为使用Tag或类似内容?

修改

我在这里看到了类似的问题:Interaction Triggers in Style in ResourceDictionary WPF

在阅读了该问题的答案后,我尝试了以下内容:

TextBox

然后分配给这样的控件:

ControlTemplate

这也不起作用,仍在抱怨:

  

附加属性“触发器”只能应用于从“DependencyObject”派生的类型。

编辑2

以下是<UserControl.Resources> <TextBox x:Key="TextBoxWithTag"> <i:Interaction.Triggers> <i:EventTrigger EventName="GotFocus"> <i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" /> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </UserControl.Resources> 信息。它设置了与<ContentControl Grid.Row="0" Grid.Column="1" Width="40" HorizontalAlignment="Right" Content="{StaticResource TextBoxWithTag}" Tag="test tag" /> 绑定的GotFocusCommand的值。

这是我的string

TextBlock

然后是XAML:

ViewModel

1 个答案:

答案 0 :(得分:6)

有几种方法可以做你想要的。一个例子:

public static class UIBehaviors {
    public static readonly DependencyProperty AttachedTriggersProperty = DependencyProperty.RegisterAttached(
        "AttachedTriggers", typeof (EventTriggerCollection), typeof (UIBehaviors), new PropertyMetadata(null, OnAttachedTriggersChanged));

    private static void OnAttachedTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        var triggers = Interaction.GetTriggers(d);
        if (e.OldValue != null) {
            foreach (var trigger in (EventTriggerCollection) e.OldValue) {
                triggers.Remove(trigger);
            }
        }
        if (e.NewValue != null) {
            foreach (var trigger in (EventTriggerCollection) e.NewValue) {
                triggers.Add(trigger);
            }
        }
    }

    public static void SetAttachedTriggers(DependencyObject element, EventTriggerCollection value) {
        element.SetValue(AttachedTriggersProperty, value);
    }

    public static EventTriggerCollection GetAttachedTriggers(DependencyObject element) {
        return (EventTriggerCollection) element.GetValue(AttachedTriggersProperty);            
    }
}

public class EventTriggerCollection : Collection<EventTrigger> {

}

这里我们声明附加属性,它接受一组EventTrigger(来自Interactivity程序集)。设置此属性后,我们只需附加所有这些触发器,例如i:Interaction.Triggers即可。然后像这样使用它:

<Window.Resources>
    <local:EventTriggerCollection x:Shared="False" x:Key="textBoxTriggers">
        <i:EventTrigger EventName="GotFocus">
            <i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TextBox}, Path=Tag}" />
        </i:EventTrigger>
    </local:EventTriggerCollection>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="local:UIBehaviors.AttachedTriggers" Value="{StaticResource textBoxTriggers}"/>
    </Style>
</Window.Resources>

请注意我如何绑定到TextBox.Tag属性。您不能像在问题中那样绑定它,因为您的数据上下文将是视图模型(使用GotFocusCommand)。 还要注意触发器集合如何作为资源字典中的单独元素移动,并为其设置x:Shared =“false”。这将导致每次访问此属性时都会创建新的触发器集,因此每个TextBox都有自己的触发器集。

然后任何

<TextBox Text="Test" Tag="test message" />

将在TextBox的数据上下文中调用GotFocusCommand,并将“test message”作为参数。