- 先看一下效果图:
- 官方文档有介绍:
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);
}
}
}