【WPF学习手记】控件修饰Adorners

本文详细介绍如何在 WPF 中使用 Adorners 来为 UI 元素添加视觉装饰,包括自定义 Adorner 的创建、AdornerLayer 的使用及绑定属性的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 先看一下效果图:

  •  官方文档有介绍:

https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/adorners-overview

  •  xaml文件
<Window x:Class="AdornerExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AdornerExample"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300"
        Loaded="Window_Loaded">
    <Grid>
        <StackPanel HorizontalAlignment="Center" Margin="5" VerticalAlignment="Center">
            <Button Name="button1" Content="Button1" Margin="5" FontSize="20"/>
            <Button Name="button2" Content="Button1" Margin="5" FontSize="20"/>
            <CheckBox Name="checkBox1" Content="CheckBox1" Margin="5" FontSize="20" VerticalContentAlignment="Center"/>
            <TextBox Name="textBox1" Text="TextBox1" FontSize="20" Margin="5"/>
            <Label Name="label1" Content="Label1" FontSize="20" Margin="5"/>
        </StackPanel>
    </Grid>
</Window>
  • 后台代码
using System.Windows;

namespace AdornerExample
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            AdornerHelper.SetHasAdorner(button1, true);
            AdornerHelper.TxtContent = "99°";
            AdornerHelper.SetHasAdorner(button2, true);
        }
    }
}
  • AdornerHelper类
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace AdornerExample
{
    public class AdornerHelper
    {
        public static string TxtContent { get; set; }

        public AdornerHelper(string txtContent)
        {
            TxtContent = txtContent; 
        }

        public static bool GetHasAdorner(DependencyObject obj)
        {
            return (bool)obj.GetValue(HasAdornerProperty);
        }

        public static void SetHasAdorner(DependencyObject obj, bool value)
        {
            obj.SetValue(HasAdornerProperty, value);
        }

        public static readonly DependencyProperty HasAdornerProperty =
            DependencyProperty.RegisterAttached("HasAdorner", typeof(bool), typeof(AdornerHelper), new PropertyMetadata(false, PropertyChangedCallBack));

        private static void PropertyChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                if (d is Visual element)
                {
                    var adornerLayer = AdornerLayer.GetAdornerLayer(element);
                    if (adornerLayer != null)
                    {
                        adornerLayer.Add(new AdornerStyle(element as UIElement, TxtContent));
                    }
                }
            }
        }

        public static bool GetIsShowAdorner(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsShowAdornerProperty);
        }

        public static void SetIsShowAdorner(DependencyObject obj, bool value)
        {
            obj.SetValue(IsShowAdornerProperty, value);
        }

        public static readonly DependencyProperty IsShowAdornerProperty =
            DependencyProperty.RegisterAttached("IsShowAdorner", typeof(bool), typeof(AdornerHelper), new PropertyMetadata(false, IsShowChangedCallBack));

        private static void IsShowChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is UIElement element)
            {
                var adornerLayer = AdornerLayer.GetAdornerLayer(element);
                if (adornerLayer != null)
                {
                    var adorners = adornerLayer.GetAdorners(element);
                    if (adorners != null && adorners.Count() != 0)
                    {
                        if (!(adorners.FirstOrDefault() is AdornerStyle adorner))
                        {
                            return;
                        }
                        if ((bool)e.NewValue)
                        {
                            adorner.ShowAdorner();
                        }
                        else
                        {
                            adorner.HideAdorner();
                        }
                    }
                }
            }
        }
    }
}
  • AdornerStyle类
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;

namespace AdornerExample
{
    public class AdornerStyle : Adorner
    {
        private VisualCollection visual;
        private Canvas canvas;
        private TextBlock txtBlock;
        private Ellipse myEllipse;

        public AdornerStyle(UIElement adornedElement, string txtContent) : base(adornedElement)
        {
            visual = new VisualCollection(this);
            txtBlock = new TextBlock
            {
                Text = txtContent,
                Foreground = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xA5, 0x00)),
                TextAlignment = TextAlignment.Left,
            };
            myEllipse = new Ellipse
            {
                Fill = new SolidColorBrush(Color.FromArgb(0xFF, 0x25, 0x25, 0x25)),
            };
            canvas = new Canvas();
            canvas.Children.Add(myEllipse);
            canvas.Children.Add(txtBlock);
            visual.Add(canvas);
        }

        public void ShowAdorner()
        {
            canvas.Visibility = Visibility.Visible;
        }

        public void HideAdorner()
        {
            canvas.Visibility = Visibility.Collapsed;
        }

        protected override int VisualChildrenCount
        {
            get
            {
                return visual.Count;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            return visual[index];
        }

        protected override Size MeasureOverride(Size constraint)
        {
            return base.MeasureOverride(constraint);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            canvas.Arrange(new Rect(finalSize));
            txtBlock.Margin = new Thickness(canvas.Margin.Left + canvas.ActualWidth + 5, canvas.Margin.Top + 5, 0, 0);
            myEllipse.Margin = new Thickness(canvas.Margin.Left + canvas.ActualWidth, canvas.Margin.Top, 0, 0);
            myEllipse.Width = Math.Max(txtBlock.ActualWidth + 10, txtBlock.ActualHeight + 10);
            myEllipse.Height = myEllipse.Width;

            return base.ArrangeOverride(finalSize);
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            Rect adornedElementRect = new Rect(AdornedElement.RenderSize);

            // Some arbitrary drawing implements.
            Pen renderPen = new Pen(new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xA5, 0x00)), 2.0);
            SolidColorBrush renderBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xA5, 0x00));

            // Draw a circle at each corner.
            double renderRadius = 3.0;
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, renderRadius, renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, renderRadius, renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, renderRadius, renderRadius);
            drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, renderRadius, renderRadius);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值