如何在样式设置器中添加混合行为 [英] How to add a Blend Behavior in a Style Setter

查看:17
本文介绍了如何在样式设置器中添加混合行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为按钮创建了一个混合行为.如何将其设置为应用程序中的所有按钮.

I have crated a Blend behavior for Button. How can I set that to all of my Buttons in the app.

<Button ...>
  <i:Interaction.Behaviors>
    <local:MyBehavior />
  </i:Interaction.Behaviors>
</Button>

但是,当我尝试时:

<Style>
  <Setter Property="i:Interaction.Behaviors">
    <Setter.Value>
      <local:MyBehavior />
    </Setter.Value>
  </Setter>
</Style>

我收到错误

属性Behaviors"没有可访问的 setter.

The property "Behaviors" does not have an accessible setter.

推荐答案

我遇到了同样的问题,我想出了一个解决方案.我在解决这个问题后发现了这个问题,我发现我的解决方案与 Mark 的解决方案有很多共同点.但是,这种方法有点不同.

I had the same problem and I've come up with a solution. I found this question after I solved it and I see that my solution bears a lot in common with Mark's. However, this approach is a little different.

主要问题是行为和触发器与特定对象相关联,因此您不能对多个不同的关联对象使用相同的行为实例.当您定义您的行为时,内联 XAML 会强制实施这种一对一关系.但是,当您尝试在样式中设置行为时,该样式可以重新用于它适用的所有对象,这将在基本行为类中引发异常.事实上,作者们付出了相当大的努力来阻止我们甚至尝试这样做,因为他们知道这是行不通的.

The main problem is that behaviors and triggers associate with a specific object and so you cannot use the same instance of a behavior for multiple different associated objects. When you define your behavior inline XAML enforces this one-to-one relationship. However, when you try to set a behavior in a style, the style can be re-used for all the objects it applies to and this will throw exceptions in the base behavior classes. In fact the authors went to considerable effort to prevent us from even trying to do this, knowing that it wouldn't work.

第一个问题是我们甚至无法构造行为设置器值,因为构造函数是内部的.所以我们需要自己的行为和触发集合类.

The first problem is that we cannot even construct a behavior setter value because the constructor is internal. So we need our own behavior and trigger collection classes.

下一个问题是行为和触发器附加属性没有设置器,因此只能使用内嵌 XAML 添加它们.我们使用自己的附加属性来解决这个问题,这些属性操作主要行为和触发属性.

The next problem is that the behavior and trigger attached properties don't have setters and so they can only be added to with in-line XAML. This problem we solve with our own attached properties that manipulate the primary behavior and trigger properties.

第三个问题是我们的行为集合仅适用于单一样式目标.我们通过利用一个很少使用的 XAML 功能 x:Shared="False" 来解决这个问题,该功能在每次引用资源时都会创建一个新的资源副本.

The third problem is that our behavior collection is only good for a single style target. This we solve by utilizing a little-used XAML feature x:Shared="False" which creates a new copy of the resource each time it is referenced.

最后一个问题是行为和触发器不像其他样式设置器;我们不想用新行为替换旧行为,因为它们可以做完全不同的事情.因此,如果我们接受一旦添加了行为就无法将其删除(这就是行为当前的工作方式),我们可以得出结论,行为和触发器应该是可添加的,这可以由我们的附加属性处理.

The final problem is that behaviors and triggers are not like other style setters; we don't want to replace the old behaviors with the new behaviors because they could do wildly different things. So if we accept that once you add a behavior you cannot take it away (and that's the way behaviors currently work), we can conclude that behaviors and triggers should be additive and this can be handled by our attached properties.

以下是使用此方法的示例:

Here is a sample using this approach:

<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>

该示例使用触发器,但行为的工作方式相同.在示例中,我们显示:

The example uses triggers but behaviors work the same way. In the example, we show:

  • 样式可以应用于多个文本块
  • 几种类型的数据绑定都可以正常工作
  • 在输出窗口中生成文本的调试操作

这是一个示例行为,我们的 DebugAction.更准确地说,它是一种行为,但通过滥用语言,我们将行为、触发因素和行为称为行为".

Here's an example behavior, our DebugAction. More properly it is an action but through the abuse of language we call behaviors, triggers and actions "behaviors".

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 添加行为> 和触发器一样.

Finally, our collections and attached properties to make this all work. By analogy with Interaction.Behaviors, the property you target is called SupplementaryInteraction.Behaviors because by setting this property, you will add behaviors to Interaction.Behaviors and likewise for triggers.

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);
    }
}

就这样,通过样式应用的全功能行为和触发器.

and there you have it, fully-functional behaviors and triggers applied through styles.

这篇关于如何在样式设置器中添加混合行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆