Adorner實現邊框線條動畫

非法关键字發表於2024-05-28

在 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,以實現豐富的視覺效果和使用者互動。

相關文章