WPF中如何通过代码动态调整DrawingVisual内矩形大小?附选型疑问
嘿,作为WPF绘图新手,你能考虑到性能并切换到DrawingVisual真的很明智!先直接回答你的两个问题:
1. DrawingVisual是否比Shape更合适?
绝对是的!Shape类(比如Rectangle、Ellipse)属于FrameworkElement,它们自带了布局、样式、数据绑定等一系列WPF高级特性,但这些特性在你需要处理1000个可交互元素的场景下,会带来大量不必要的性能开销——每个Shape都要经历完整的WPF布局管线,内存占用也更高。
而DrawingVisual是轻量级的Visual子类,它跳过了FrameworkElement的很多冗余逻辑,专注于图形渲染,内存占用低、渲染速度快,非常适合你这种需要大量绘制元素的绘图应用场景。所以你的选择完全正确!
2. 如何动态增大DrawingVisual中的矩形尺寸?
你之前尝试直接修改Rectangle的Width/Height无效,是因为你当前的代码是一次性绘制矩形的——调用drawingContext.Close()后,DrawingVisual的内容就固定了,没法直接编辑已绘制的图形。要动态调整,你需要存储图形的参数,在需要修改时重新绘制。
下面是修改后的代码示例,我帮你重构了SVisualContainer类,让它支持动态调整矩形尺寸:
using System; using System.Windows; using System.Windows.Media; public class SVisualContainer : UIElement { private VisualCollection _children; private DrawingVisual _drawingVisual; // 存储矩形的位置和尺寸参数,方便后续修改 private Rect _rectangleBounds; public SVisualContainer() { _children = new VisualCollection(this); // 初始化矩形参数 _rectangleBounds = new Rect(new Point(160, 100), new Size(320, 80)); _drawingVisual = CreateDrawingVisual(); _children.Add(_drawingVisual); } private DrawingVisual CreateDrawingVisual() { DrawingVisual visual = new DrawingVisual(); // 使用using自动管理DrawingContext的生命周期 using (DrawingContext dc = visual.RenderOpen()) { dc.DrawRectangle(Brushes.LightBlue, null, _rectangleBounds); } return visual; } // 提供一个公开方法,用于动态增大矩形尺寸 public void EnlargeRectangle(double addWidth, double addHeight) { // 更新矩形参数 _rectangleBounds.Width += addWidth; _rectangleBounds.Height += addHeight; // 重新绘制矩形 using (DrawingContext dc = _drawingVisual.RenderOpen()) { dc.DrawRectangle(Brushes.LightBlue, null, _rectangleBounds); } // 触发控件重绘,确保界面更新 InvalidateVisual(); } // 也可以提供直接设置尺寸的方法 public void SetRectangleSize(double width, double height) { _rectangleBounds.Width = width; _rectangleBounds.Height = height; using (DrawingContext dc = _drawingVisual.RenderOpen()) { dc.DrawRectangle(Brushes.LightBlue, null, _rectangleBounds); } InvalidateVisual(); } protected override int VisualChildrenCount => _children.Count; protected override Visual GetVisualChild(int index) { if (index < 0 || index >= _children.Count) { throw new ArgumentOutOfRangeException(nameof(index)); } return _children[index]; } }
之后你就可以在外部调用这个方法来动态调整尺寸了:
// 假设你已经实例化了sVisual sVisual.EnlargeRectangle(50, 30); // 宽度增加50,高度增加30
为什么ScaleTransform不是最佳选择?
ScaleTransform是对整个Visual进行缩放,它会让矩形的所有部分(包括位置)按比例放大,如果你只是想保持矩形的左上角位置不变,单纯增大宽高,重新绘制的方式会更精准,也更符合你“调整大小”的需求。
另外,如果你后续需要实现拖拽功能,也可以用类似的思路:存储矩形的X/Y坐标,修改后重新绘制,这样比依赖Canvas的Left/Top属性更高效,因为你可以直接控制图形的原始位置,不需要经过Canvas的布局计算。
内容的提问来源于stack exchange,提问作者heapoverflow




