Adorner实现边框线条动画

在 WPF 中,Adorner 是一种特殊的装饰层,能够在 UI 元素之上绘制视觉效果。常用于提供视觉反馈或装饰功能,例如焦点指示、拖放效果等。

自定义 Adorne 类

要创建自定义 Adorner,需要继承 Adorner 类并重写 OnRender 方法。在 OnRender 方法中,您可以使用 DrawingContext 绘制自定义图形。

示例:创建带动画边框的 Adorner

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;

public class AnimatedBorderAdorner : Adorner
{
    private double _animationProgress;
    private AnimationClock _animationClock;

    public AnimatedBorderAdorner(UIElement adornedElement) : base(adornedElement)
    {
        StartAnimation();
    }

    private void StartAnimation()
    {
        DoubleAnimation animation = new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(2)));
        animation.RepeatBehavior = RepeatBehavior.Forever;
        //animation.AutoReverse = true;
        animation.AutoReverse = false;

        // Create a clock for the animation and start it
        _animationClock = animation.CreateClock();
        _animationClock.CurrentTimeInvalidated += (s, e) =>
        {
            if (_animationClock.CurrentProgress.HasValue)
            {
                _animationProgress = _animationClock.CurrentProgress.Value;
                // Request a redraw
                InvalidateVisual();
            }
            ApplyAnimationClock(AnimationProgressProperty, _animationClock);
        };
    }

    public double AnimationProgress
    {
        get { return (double)GetValue(AnimationProgressProperty); }
        set { SetValue(AnimationProgressProperty, value); }
    }
    // Using a DependencyProperty as the backing store for AnimationProgress.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AnimationProgressProperty =
        DependencyProperty.Register("AnimationProgress", typeof(double), typeof(AnimatedBorderAdorner), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        Rect adornedElementRect = new Rect(this.AdornedElement.RenderSize);

        // Calculate the dash offset based on the animation progress
        double dashOffset = - adornedElementRect.Width * _animationProgress;
        // Create a new Pen object for each render
        Pen pen = new Pen(Brushes.ForestGreen, 2);
        FormattedText ft = new FormattedText("ON",
            CultureInfo.CurrentCulture,
            FlowDirection.RightToLeft,
            new Typeface(new FontFamily("微软雅黑"), FontStyles.Normal, FontWeights.Bold, FontStretches.Normal),
            8,
            Brushes.Green,
            96);
        drawingContext.DrawText(ft, new Point(adornedElementRect.TopRight.X - 2, adornedElementRect.TopRight.Y));
        pen.DashStyle = new DashStyle(new double[] {adornedElementRect.Width / 4, adornedElementRect.Width / 4}, dashOffset);
        drawingContext.DrawRectangle(null, pen, adornedElementRect);
    }
}

应用 Adorner

为了将 Adorner 应用到 UI 元素,需要获取该元素的 AdornerLayer,然后添加或移除 Adorner

示例:在 ToggleButton 上应用 Adorner

private void ToggleButton_Click(object sender, RoutedEventArgs e)
{
    ToggleButton toggleButton = sender as ToggleButton;
    AdornerLayer layer = AdornerLayer.GetAdornerLayer(toggleButton);

    if (layer != null)
    {
        Adorner[] adorners = layer.GetAdorners(toggleButton);
        AnimatedBorderAdorner existingAdorner = adorners?.OfType<AnimatedBorderAdorner>().FirstOrDefault();

        if (existingAdorner != null)
        {
            layer.Remove(existingAdorner);
        }
        else
        {
            layer.Add(new AnimatedBorderAdorner(toggleButton));
        }
    }
}

XAML 中定义 UI 元素

在 XAML 中,可以使用 AdornerDecorator 包裹目标 UI 元素,以确保 Adorner 能够正确显示。

示例:定义 ToggleButton

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <AdornerDecorator>
            <ToggleButton Width="100" Height="50" Content="Toggle" Click="ToggleButton_Click"/>
        </AdornerDecorator>
    </Grid>
</Window>

重要属性和方法

  • AdornerLayer:用于管理 Adorner 的层。可以通过 AdornerLayer.GetAdornerLayer(UIElement) 方法获取。
  • ApplyAnimationClock:将动画应用到 DependencyProperty,以便在动画进度变化时触发重绘。
  • InvalidateVisual:请求重绘 Adorner

关键点总结

  1. 创建自定义 Adorner:继承 Adorner 类,重写 OnRender 方法。
  2. 添加动画:使用 DoubleAnimationAnimationClockAdorner 添加动画效果。
  3. 管理 Adorner:通过 AdornerLayer 添加或移除 Adorner
  4. 确保视觉效果:在 XAML 中使用 AdornerDecorator 包裹目标 UI 元素。
  5. 性能优化:在 OnRender 方法中避免复杂计算和创建大量对象,尽量复用资源。

通过这些步骤和示例,您可以在 WPF 应用程序中创建和管理复杂的 Adorner,以实现丰富的视觉效果和用户交互。

posted @ 2024-05-28 10:43  非法关键字  阅读(46)  评论(0编辑  收藏  举报