装饰器 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)); }
截图