Style Setter中的行为无法正常工作

时间:2014-12-31 03:34:31

标签: c# windows-runtime winrt-xaml

在我的Windows-Runtime应用程序中,我有一个主题,其样式为DoubleTapped操作定义了Behavior

这些是XML命名空间:

xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"

这就是风格:

<Style x:Name="DisplayImage" TargetType="ScrollViewer">
    <Setter Property="VerticalScrollBarVisibility" Value="Hidden" />
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="ZoomMode" Value="Disabled" />
    <Setter Property="i:Interaction.Behaviors">
        <Setter.Value>
            <i:BehaviorCollection>
                <core:EventTriggerBehavior EventName="DoubleTapped">
                    <local:ScrollViewerDoubleTap />
                </core:EventTriggerBehavior>
            </i:BehaviorCollection>
        </Setter.Value>
    </Setter>
</Style>

这是我的Behavior

[DefaultEvent(typeof(ScrollViewer),"DoubleTapped")]
public class ScrollViewerDoubleTap : DependencyObject, IAction
{
    public object Execute(object sender, object parameter)
    {
        ScrollViewer sv = (ScrollViewer)sender;
        if (sv.HorizontalScrollBarVisibility == ScrollBarVisibility.Disabled)
        {
            sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
        }
        else
        {
            sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
        }
        return sender;
    }
}

这就是我使用它的方式:

<ScrollViewer Style="{StaticResource Image}" MaxWidth="1067">
    <Border BorderBrush="Black" BorderThickness="1">
        <Image Source="MyImage.png"/>
    </Border>
</ScrollViewer>

当我在具有此样式的页面上双击第一个图像时,它可以完美地工作;但是,当我双击页面上的其他图像时,行为代码永远不会运行。我知道它永远不会运行,因为我用断点运行它,当我双击第一个图像而不是第二个图像时它会破坏。我会很感激为什么会发生这种情况。

2 个答案:

答案 0 :(得分:2)

这不会起作用,因为行为,操作或触发器被设计为附加到单个元素。当你在一个样式的setter中定义它时,它就像你试图将它与多个元素相关联,并且正如你已经看到的那样,只有当你用这个样式与第一个元素交互时才会调用触发器

有一种简单的方法可以解决这个问题。基本上,您需要确保与此样式关联的每个元素都具有您创建的触发器的新实例。您可以将所有这些逻辑包含在附加属性中,然后您的样式只需要引用此属性。

<Style x:Name="DisplayImage" TargetType="ScrollViewer">
    <Setter Property="VerticalScrollBarVisibility" Value="Hidden" />
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="ZoomMode" Value="Disabled" />
    <Setter Property="local:FrameworkElementEx.AttachBehaviors" Value="True" />
</Style>

这是附加属性的实现方式。

public static class FrameworkElementEx
{
    public static bool GetAttachBehaviors(DependencyObject obj)
    {
        return (bool)obj.GetValue(AttachBehaviorsProperty);
    }

    public static void SetAttachBehaviors(DependencyObject obj, bool value)
    {
        obj.SetValue(AttachBehaviorsProperty, value);
    }

    public static readonly DependencyProperty AttachBehaviorsProperty =
        DependencyProperty.RegisterAttached("AttachBehaviors", typeof(bool), typeof(FrameworkElementEx), new PropertyMetadata(false, Callback));

    private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behaviors = Interaction.GetBehaviors(d);

        var eventTriggerBehavior = new EventTriggerBehavior
        {
            EventName = "DoubleTapped"
        };
        eventTriggerBehavior.Actions.Add(new ScrollViewerDoubleTap());

        behaviors.Add(eventTriggerBehavior);
    }
}

答案 1 :(得分:2)

我们可以使用纯XAML

来做到这一点

...以及可重复使用的附加属性,它会收到DataTemplate BehaviorCollection(或单个Behavior)。

您不必更改代码隐藏。

<Style x:Key="SomeImageStyle" 
       xmlns:Behaviors="using:MyBehaviors"
       xmlns:i="using:Microsoft.Xaml.Interactivity"
       xmlns:core="using:Microsoft.Xaml.Interactions.Core"
       TargetType="Image">
  <Setter Property="local:AttachedBehaviorsEx.AttachedBehaviors">
    <Setter.Value>
            <DataTemplate>
                    <core:EventTriggerBehavior EventName="Click">
                        <Behaviors:SomeAction SomeParameter="someValue" />
                    </core:EventTriggerBehavior>
            </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>

或者,如果您一次需要一些Behaviors

    <Setter.Value>
            <DataTemplate>
                <i:BehaviorCollection>
                    <core:EventTriggerBehavior EventName="Click">
                        <Behaviors:SomeAction SomeParameter="someValue" />
                    </core:EventTriggerBehavior>
                    <core:EventTriggerBehavior EventName="Tapped">
                        <Behaviors:SomeAction SomeParameter="someOtherValue" />
                    </core:EventTriggerBehavior>
                </i:BehaviorCollection>
            </DataTemplate>
    </Setter.Value>

附加财产

你甚至不需要改变它。

using Microsoft.Xaml.Interactivity;
using Windows.UI.Xaml;
using System;

namespace MyBehaviors
{
    public static class AttachedBehaviorsEx
    {
        public static DataTemplate GetAttachedBehaviors(DependencyObject obj)
        {
            return (DataTemplate)obj.GetValue(AttachedBehaviorsProperty);
        }

        public static void SetAttachedBehaviors(DependencyObject obj, DataTemplate value)
        {
            obj.SetValue(AttachedBehaviorsProperty, value);
        }

        public static readonly DependencyProperty AttachedBehaviorsProperty =
            DependencyProperty.RegisterAttached("AttachedBehaviors", typeof(DataTemplate), typeof(AttachedBehaviorsEx), new PropertyMetadata(null, Callback));

        private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BehaviorCollection collection = null;
            var template = (DataTemplate)e.NewValue;
            if (template != null)
            {
                var value = template.LoadContent();

                if (value is BehaviorCollection)
                    collection = (BehaviorCollection)value;
                else if (value is IBehavior)
                    collection = new BehaviorCollection { value };
                else throw new Exception($"AttachedBehaviors should be a BehaviorCollection or an IBehavior.");
            }
            // collection may be null here, if e.NewValue is null
            Interaction.SetBehaviors(d, collection);
        }
    }
}

为什么它更好?

与Justin XL建议相比,这是一种更灵活的方法。

他的代码需要修改代码隐藏才能重新使用它。每次要重新使用时,都需要设置EventName(在此行EventName = "DoubleTapped")和Behavior(此行eventTriggerBehavior.Actions.Add(new ScrollViewerDoubleTap());)。< / p>