C#WPF - 边框风格动画

时间:2017-08-10 08:28:13

标签: c# wpf xaml

我想给一个像行为一样的按钮,因为我想应用不对称的圆角边缘,摆脱标准按钮的焦点闪烁效果。我想在将鼠标悬停在它上面并点击它时应用不同的样式。除了两种样式之间的过渡之外,它的效果很好。考虑以下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教程中收集到的代码我已经阅读完了,因为我还没有牢牢掌握所附属性的工作原理等等。

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

默认外观:

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

MouseOver看:

<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)"/>

现在的问题是,只要单击边框并执行IsPressed EnterActions和ExitActions,第一个MultiTrigger的动画就不再有效了。我的触发器,EnterActions和ExitActions显然是错误的,但我不知道它是什么。

非常感谢任何建议!

1 个答案:

答案 0 :(得分:2)

使用<RemoveStoryboard>作为退出操作:

<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下一样。我怎么能这样做?

将退出FillBehavior的{​​{1}}属性设置为Storyboards

Stop