Adorner 装饰器
装饰器 Adorner
装饰器是WPF中较为常用的技术之一,也是不同于XAML的技术。
较为特殊。
特殊于装饰器全部由C#构成,不同于ControlTenmpate和Style的元素。
装饰器在某些方面能够简化前两者的代码量。
现在简单的说一下装饰器的入门用法(通常用法和附加属性一起使用)
Adorner是一个抽象类。
由于显示装饰器的方式有两种
-
直接装载现有WPF控件
-
绘制控件
直接装载现有控件:
这种方法需要重载四个Adorner方法
- GetVisualChild //获取Visual的子控件索引
- ArrangeOverride //确定装饰器的定位
- MeasureOverride //确定装饰器要约束道德大小
- VisualChildrenCount//获取VisualCollection的集合数量
重写之后就是
编写 私有的VsualCollection来存储你要装载的控件。
然后利用MeasureOverride和ArrangeOverride这两个方法来进行定位和约束大小。
下面的代码是 可以随时更新内容的装饰器
using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Shapes; namespace 装饰器 { public class TestAdorner : Adorner { private Grid _Grid; private Ellipse _Ellipse; private TextBlock _TextBlock; private VisualCollection collection; private UIElement _UIElement; public void UPDATE(string Text) { var grid = collection[0] as Grid; (grid.Children[1] as TextBlock).Text=Text; } public TestAdorner(UIElement adornedElement) : base(adornedElement) { collection = new VisualCollection(this); _Grid = new Grid() { Width=20 , Height=20 };
_Ellipse = new Ellipse() { Fill = new SolidColorBrush(Colors.Red) };
_TextBlock = new TextBlock() { HorizontalAlignment = HorizontalAlignment.Center , VerticalAlignment = VerticalAlignment.Center , FontSize=15 }; _Grid.Children.Add(_Ellipse); _Grid.Children.Add(_TextBlock); collection.Add(_Grid); _UIElement = adornedElement; } protected override int VisualChildrenCount => collection.Count; protected override Visual GetVisualChild(int index) => collection[index]; protected override Size MeasureOverride(Size constraint) => base.MeasureOverride(constraint); protected override Size ArrangeOverride(Size finalSize) { _Grid.Arrange(new Rect(finalSize));
_Grid.Margin = new Thickness((_UIElement as Button).ActualWidth-30, 0, 0, (_UIElement as Button).ActualHeight-30);
return base.ArrangeOverride(finalSize); } } }
XAML页面
<Grid> <Button x:Name="TestBtn" Content="选中" Loaded="A_Loaded" Height="100" Width="300"/> </Grid>
CS页面
namespace 装饰器 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { AdornerLayer layer; DispatcherTimer timer; public MainWindow() { InitializeComponent();
timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1000) };
timer.Tick += Timer_Tick; }
private void Timer_Tick(object sender, EventArgs e) { if (i == 1000) timer.Stop();
var b= layer.GetAdorners(TestBtn) ?? null;
if(b!=null) { var k=b[0] as TestAdorner;
k.UPDATE(i.ToString()); } else { var j = new TestAdorner(TestBtn);
j.UPDATE(0.ToString());
layer.Add(j); } i++; } int i = 0; private void A_Loaded(object sender, RoutedEventArgs e) {
layer = AdornerLayer.GetAdornerLayer(TestBtn);
timer.Start();
} } }
效果图
绘制控件
绘制需要重载一个方法就好了
- OnRender//绘制控件
不过值得注意的是,绘制方式无法更新。至少我是不会。
现在给出代码
namespace 装饰器 { public class TestAdornerOnRender : Adorner { public TestAdornerOnRender(UIElement adornedElement) : base(adornedElement) { } protected override void OnRender(DrawingContext drawingContext) { FormattedText t = new FormattedText( "!!!!!", CultureInfo.InstalledUICulture, FlowDirection.LeftToRight, new Typeface("微软雅黑"), 15, new SolidColorBrush(Colors.Red) ); drawingContext.DrawText(t, new Point(270, 0)); base.OnRender(drawingContext); } } }
xaml页面
<Grid> <Button x:Name="TestBtn" Content="选中" Loaded="A_Loaded" Height="100" Width="300"> </Button> </Grid>
cs 页面
private void A_Loaded(object sender, RoutedEventArgs e) { var layer = AdornerLayer.GetAdornerLayer(TestBtn); layer.Add(new TestAdornerOnRender(TestBtn)); }
截图
分类:
WPF 特殊技
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现