【问题标题】:C# WPF - Border Style AnimationsC# WPF - 边框样式动画
【发布时间】:2017-08-10 08:28:13
【问题描述】:

我想给 Border 一个类似按钮的行为,因为我想应用不对称的圆形边缘并摆脱标准按钮的焦点闪烁效果。当鼠标悬停在它上面并单击它时,我想对其应用不同的样式。除了两种样式之间的过渡外,它运行良好。考虑以下 XAML

<local:ClickableBorder local:FrameworkElementExt.AttachIsPressed="True" CornerRadius="5,10,5,10" BorderThickness="1" Height="27.334" Margin="154.667,31.333,223.667,0" VerticalAlignment="Top">
<local:ClickableBorder.Style>
    <Style TargetType="{x:Type local:ClickableBorder}">
        <Setter Property="BorderBrush" Value="Black"/>
        <Setter Property="Background" Value="LightGray"/>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver"  Value="True"/>
                    <Condition Property="IsEnabled"  Value="True"/>
                </MultiTrigger.Conditions>
                <MultiTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="White" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="DarkGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.EnterActions>
                <MultiTrigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="Black" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="LightGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.ExitActions>
            </MultiTrigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="local:FrameworkElementExt.IsPressed"  Value="True"/>
                    <Condition Property="IsEnabled"  Value="True"/>
                </MultiTrigger.Conditions>
                <MultiTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="DarkRed" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="Red" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.EnterActions>
                <MultiTrigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="Black" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="LightGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.ExitActions>
            </MultiTrigger>
        </Style.Triggers>
    </Style>
</local:ClickableBorder.Style>

以及背后的相关代码

public class FrameworkElementExt
{
    public static readonly DependencyProperty IsPressedProperty = DependencyProperty.RegisterAttached("IsPressed", typeof(bool), typeof(FrameworkElementExt), new PropertyMetadata(false));

    public static readonly DependencyProperty AttachIsPressedProperty = DependencyProperty.RegisterAttached("AttachIsPressed", typeof(bool), typeof(FrameworkElementExt), new PropertyMetadata(false, PropertyChangedCallback));

    public static void PropertyChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
    {
        FrameworkElement element = (FrameworkElement)depObj;
        if (element != null)
        {
            if ((bool)args.NewValue)
            {
                element.MouseDown += new MouseButtonEventHandler(element_MouseDown);
                element.MouseUp += new MouseButtonEventHandler(element_MouseUp);
                element.MouseLeave += new MouseEventHandler(element_MouseLeave);
            }
            else
            {
                element.MouseDown -= new MouseButtonEventHandler(element_MouseDown);
                element.MouseUp -= new MouseButtonEventHandler(element_MouseUp);
                element.MouseLeave -= new MouseEventHandler(element_MouseLeave);
            }
        }
    }

    static void element_MouseLeave(object sender, MouseEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)sender;
        if (element != null)
        {
            element.SetValue(IsPressedProperty, false);
        }
    }
    static void element_MouseUp(object sender, MouseButtonEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)sender;
        if (element != null)
        {
            element.SetValue(IsPressedProperty, false);
        }
    }
    static void element_MouseDown(object sender, MouseButtonEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)sender;
        if (element != null)
        {
            element.SetValue(IsPressedProperty, true);
        }
    }
    public static bool GetIsPressed(UIElement element)
    {
        return (bool)element.GetValue(IsPressedProperty);
    }
    public static void SetIsPressed(UIElement element, bool val)
    {
        element.SetValue(IsPressedProperty, val);
    }
    public static bool GetAttachIsPressed(UIElement element)
    {
        return (bool)element.GetValue(AttachIsPressedProperty);
    }
    public static void SetAttachIsPressed(UIElement element, bool val)
    {
        element.SetValue(AttachIsPressedProperty, val);
    }
}

public class ClickableBorder : Border

{
    public static readonly RoutedEvent ClickEvent;

    static ClickableBorder()
    {
        ClickEvent = ButtonBase.ClickEvent.AddOwner(typeof(ClickableBorder));
    }

    public event RoutedEventHandler Click
    {
        add { AddHandler(ClickEvent, value); }
        remove { RemoveHandler(ClickEvent, value); }
    }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        CaptureMouse();
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);

        if (IsMouseCaptured)
        {
            ReleaseMouseCapture();
            if (IsMouseOver)
            {
                RaiseEvent(new RoutedEventArgs(ClickEvent, this));
            }
        }
    }
}

现在,我从一些已阅读的 WPF 教程中收集了背后的代码,因为我还没有牢牢掌握附加属性的工作原理等等。

Border 现在基本上是可点击的并且具有 IsPressed 属性。后者将用作样式触发条件。所以目前我有三个样式设置器/动画对。

默认外观:

<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Background" Value="LightGray"/>

鼠标悬停查看:

<ColorAnimation Duration="0:0:0.200" To="White" Storyboard.TargetProperty="BorderBrush.Color"/>
<ColorAnimation Duration="0:0:0.200" To="DarkGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>

IsPressed 外观:

<ColorAnimation Duration="0:0:0.200" To="DarkRed" Storyboard.TargetProperty="BorderBrush.Color"/>
<ColorAnimation Duration="0:0:0.200" To="Red" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>

现在的问题是,一旦单击 Border 并执行 IsPressed EnterActions 和 ExitActions,第一个 MultiTrigger 的动画就不再起作用了。显然我的触发器、EnterActions 和 ExitActions 有问题,但我不知道是什么。

非常感谢任何建议!

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    使用&lt;RemoveStoryboard&gt; 作为退出操作:

    <Style TargetType="{x:Type local:ClickableBorder}">
        <Setter Property="BorderBrush" Value="Black"/>
        <Setter Property="Background" Value="LightGray"/>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver"  Value="True"/>
                    <Condition Property="IsEnabled"  Value="True"/>
                </MultiTrigger.Conditions>
                <MultiTrigger.EnterActions>
                    <BeginStoryboard Name="sb">
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="White" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="DarkGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.EnterActions>
                <MultiTrigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="sb" />
                </MultiTrigger.ExitActions>
            </MultiTrigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="local:FrameworkElementExt.IsPressed"  Value="True"/>
                    <Condition Property="IsEnabled"  Value="True"/>
                </MultiTrigger.Conditions>
                <MultiTrigger.EnterActions>
                    <BeginStoryboard Name="sb2">
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="DarkRed" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="Red" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.EnterActions>
                <MultiTrigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="sb2" />
                </MultiTrigger.ExitActions>
            </MultiTrigger>
        </Style.Triggers>
    </Style>
    

    编辑:

    好的,现在情节提要为每个状态正确设置颜色。但是,当执行 ExitAction 时,颜色现在会突然改变而不是动画。我希望它像在 EnterActions 下一样以一定的持续时间进行动画处理。我该怎么做?

    将出口StoryboardsFillBehavior属性设置为Stop

    <Style TargetType="{x:Type local:ClickableBorder}">
        <Setter Property="BorderBrush" Value="Black"/>
        <Setter Property="Background" Value="LightGray"/>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver"  Value="True"/>
                    <Condition Property="IsEnabled"  Value="True"/>
                </MultiTrigger.Conditions>
                <MultiTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="White" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="DarkGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.EnterActions>
                <MultiTrigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard FillBehavior="Stop">
                            <ColorAnimation Duration="0:0:0.200" To="Black" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="LightGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.ExitActions>
            </MultiTrigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="local:FrameworkElementExt.IsPressed"  Value="True"/>
                    <Condition Property="IsEnabled"  Value="True"/>
                </MultiTrigger.Conditions>
                <MultiTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Duration="0:0:0.200" To="DarkRed" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="Red" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.EnterActions>
                <MultiTrigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard FillBehavior="Stop">
                            <ColorAnimation Duration="0:0:0.200" To="Black" Storyboard.TargetProperty="BorderBrush.Color"/>
                            <ColorAnimation Duration="0:0:0.200" To="LightGray" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/>
                        </Storyboard>
                    </BeginStoryboard>
                </MultiTrigger.ExitActions>
            </MultiTrigger>
        </Style.Triggers>
    </Style>
    

    【讨论】:

    • 好的,现在情节提要为每个状态正确设置颜色。但是,当执行 ExitAction 时,颜色现在会突然改变而不是动画。我希望它像在 EnterActions 下一样以一定的持续时间进行动画处理。我该怎么做?
    • 将出口情节提要的 FillBehavior 属性设置为停止:&lt;Storyboard FillBehavior="Stop"&gt;
    • 这会使样式在 EnterAction 完成后立即恢复,即使鼠标仍然悬停在控件上。
    • 嗯...您是否仅在 的情节提要上设置了 FillBehavior 属性?这对我来说似乎按预期工作。
    • 不,我把它放在 EnterActions 中。在 ExitActions 中,我只有标签“RemoveStoryBoard”,它不允许我设置 FillBehavior:&lt;MultiTrigger.ExitActions&gt; &lt;RemoveStoryboard BeginStoryboardName="SbMouseOver"/&gt; &lt;/MultiTrigger.ExitActions&gt; 您能否发布您的“ExitActions”XAML 示例?
    猜你喜欢
    • 2012-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多