马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
在WPF中利用VisualCollection创建复杂Adorner详解
什么是Adorner?
Adorner是WPF中一种特别的UI装饰元素,它可以叠加在其他UI元素上提供额外的视觉结果或交互功能,而不会影响原有元素的布局。常见的应用场景包罗:
- 选择框(当选中元素时出现的边框)
- 调解大小手柄
- 拖放指示器
- 解释标记
VisualCollection简介
VisualCollection是WPF中用于管理一组Visual对象的集合类。在创建复杂Adorner时,它特别有用,因为:
- 可以高效管理多个可视化子元素
- 自动处置惩罚视觉树的添加和移除
- 提供对子元素的索引访问
创建复杂Adorner的步调
1. 创建自定义Adorner类
起首需要从Adorner基类派生本身的类:
- public class ComplexAdorner : Adorner
- {
- private VisualCollection _visualChildren;
-
- public ComplexAdorner(UIElement adornedElement)
- : base(adornedElement)
- {
- _visualChildren = new VisualCollection(this);
-
- // 初始化你的装饰元素
- InitializeAdorner();
- }
-
- private void InitializeAdorner()
- {
- // 在这里创建和添加你的可视化元素
- }
-
- // 必须重写的方法
- protected override int VisualChildrenCount => _visualChildren.Count;
-
- protected override Visual GetVisualChild(int index) => _visualChildren[index];
-
- protected override Size ArrangeOverride(Size finalSize)
- {
- // 在这里布局你的子元素
- return finalSize;
- }
- }
复制代码 2. 添加可视化元素
在InitializeAdorner方法中,我们可以添加各种可视化元素:
- private void InitializeAdorner()
- {
- // 添加一个半透明矩形背景
- var background = new Rectangle
- {
- Fill = new SolidColorBrush(Color.FromArgb(50, 0, 0, 255)),
- RadiusX = 5,
- RadiusY = 5
- };
- _visualChildren.Add(background);
-
- // 添加一个文本标签
- var textBlock = new TextBlock
- {
- Text = "Adorner Text",
- Foreground = Brushes.White,
- Background = Brushes.Black,
- Padding = new Thickness(5)
- };
- _visualChildren.Add(textBlock);
-
- // 添加一个关闭按钮
- var closeButton = new Button
- {
- Content = "X",
- Width = 20,
- Height = 20,
- Background = Brushes.Red,
- Foreground = Brushes.White
- };
- closeButton.Click += CloseButton_Click;
- _visualChildren.Add(closeButton);
- }
复制代码 3. 实现布局逻辑
在ArrangeOverride方法中定义子元素的布局:
- protected override Size ArrangeOverride(Size finalSize)
- {
- // 背景覆盖整个装饰元素
- var background = _visualChildren[0] as Rectangle;
- background.Arrange(new Rect(finalSize));
-
- // 文本标签放在左上角
- var textBlock = _visualChildren[1] as TextBlock;
- textBlock.Arrange(new Rect(10, 10, textBlock.DesiredSize.Width, textBlock.DesiredSize.Height));
-
- // 关闭按钮放在右上角
- var closeButton = _visualChildren[2] as Button;
- closeButton.Arrange(new Rect(finalSize.Width - 30, 10, 20, 20));
-
- return finalSize;
- }
复制代码 4. 添加交互逻辑
可以为Adorner添加交互功能,例如上面的关闭按钮:
- private void CloseButton_Click(object sender, RoutedEventArgs e)
- {
- var layer = AdornerLayer.GetAdornerLayer(AdornedElement);
- if (layer != null)
- {
- layer.Remove(this);
- }
- }
复制代码 5. 利用Adorner
在代码中利用自定义Adorner:
- // 获取要装饰的元素
- var elementToAdorn = myControl; // 替换为你的UI元素
- // 获取或创建AdornerLayer
- var layer = AdornerLayer.GetAdornerLayer(elementToAdorn) ?? new AdornerLayer();
- if (layer.GetAdorners(elementToAdorn) == null)
- {
- // 创建并添加Adorner
- var adorner = new ComplexAdorner(elementToAdorn);
- layer.Add(adorner);
- }
复制代码 完整示例:可调解大小的Adorner
下面是一个更复杂的示例,创建一个可以调解大小的Adorner:
- public class ResizableAdorner : Adorner
- {
- private VisualCollection _visualChildren;
- private Thumb _topLeft, _topRight, _bottomLeft, _bottomRight;
- private Rectangle _border;
-
- public ResizableAdorner(UIElement adornedElement)
- : base(adornedElement)
- {
- _visualChildren = new VisualCollection(this);
-
- BuildAdorner();
- }
-
- private void BuildAdorner()
- {
- _border = new Rectangle
- {
- Stroke = Brushes.Blue,
- StrokeThickness = 2,
- StrokeDashArray = new DoubleCollection(new double[] { 2, 2 })
- };
- _visualChildren.Add(_border);
-
- BuildThumb(ref _topLeft, Cursors.SizeNWSE);
- BuildThumb(ref _topRight, Cursors.SizeNESW);
- BuildThumb(ref _bottomLeft, Cursors.SizeNESW);
- BuildThumb(ref _bottomRight, Cursors.SizeNWSE);
-
- _bottomLeft.DragDelta += HandleBottomLeft;
- _bottomRight.DragDelta += HandleBottomRight;
- _topLeft.DragDelta += HandleTopLeft;
- _topRight.DragDelta += HandleTopRight;
- }
-
- private void BuildThumb(ref Thumb thumb, Cursor cursor)
- {
- thumb = new Thumb
- {
- Width = 10,
- Height = 10,
- Background = Brushes.Blue,
- Cursor = cursor
- };
- _visualChildren.Add(thumb);
- }
-
- private void HandleBottomLeft(object sender, DragDeltaEventArgs e)
- {
- var element = AdornedElement as FrameworkElement;
- if (element != null)
- {
- element.Width = Math.Max(0, element.Width - e.HorizontalChange);
- element.Height = Math.Max(0, element.Height + e.VerticalChange);
- }
- }
-
- // 其他Handle方法类似...
-
- protected override Size ArrangeOverride(Size finalSize)
- {
- _border.Arrange(new Rect(finalSize));
-
- _topLeft.Arrange(new Rect(-5, -5, 10, 10));
- _topRight.Arrange(new Rect(finalSize.Width - 5, -5, 10, 10));
- _bottomLeft.Arrange(new Rect(-5, finalSize.Height - 5, 10, 10));
- _bottomRight.Arrange(new Rect(finalSize.Width - 5, finalSize.Height - 5, 10, 10));
-
- return finalSize;
- }
-
- protected override int VisualChildrenCount => _visualChildren.Count;
- protected override Visual GetVisualChild(int index) => _visualChildren[index];
- }
复制代码 性能考虑
当利用VisualCollection创建复杂Adorner时,需要留意:
- 只管减少可视化元素数量 - 每个Visual都会增加渲染开销
- 避免频仍更新 - 批量更新比多次小更新更高效
- 利用合适的缓存策略 - 对于静态元素,可以考虑缓存为位图
- 实时移除不需要的Adorner - 不利用时从AdornerLayer中移除
总结
通过VisualCollection创建复杂Adorner是WPF中强大的UI扩展技术。它允许你:
- 在不修改原有控件的环境下添加装饰和功能
- 创建复杂的交互式覆盖层
- 保持代码的构造性和可维护性
掌握这项技术可以极大地加强你的WPF应用程序的视觉结果和用户体验。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |