WPF自定义UserControl渲染后追加绘制内容不显示问题求助
问题解决:WPF自定义控件动态追加绘制内容
问题原因
你在drawRect方法里创建的DrawingContext属于全新的DrawingVisual,但这个DrawingVisual并未被添加到TestControl的可视化树中,WPF不会自动渲染未加入可视化树的元素。另外,OnRender方法的DrawingContext是WPF在控件渲染阶段临时提供的,渲染完成后会被回收,无法在后续方法中直接复用或追加内容。
解决方案一:统一在OnRender中绘制(推荐)
通过维护一个绘制数据集合存储所有需要绘制的图形信息,每次控件渲染(包括触发重绘)时,在OnRender中遍历集合统一绘制所有内容。
修改后的TestControl代码
public class TestControl : UserControl { // 存储绘制项,用元组区分图形类型和参数 private readonly List<object> _drawItems = new List<object>(); public TestControl() { // 初始化添加圆形绘制信息 _drawItems.Add(("Circle", Brushes.Red, new Point(50, 50), 50, 50)); } protected override void OnRender(DrawingContext context) { // 遍历所有绘制项,逐一绘制 foreach (var item in _drawItems) { if (item is (string type, Brush brush, Point center, double radiusX, double radiusY) circleData && circleData.type == "Circle") { context.DrawEllipse(circleData.brush, null, circleData.center, circleData.radiusX, circleData.radiusY); } else if (item is (string type, Brush brush, Rect rect) rectData && rectData.type == "Rect") { context.DrawRectangle(rectData.brush, null, rectData.rect); } } base.OnRender(context); } public void drawRect() { // 添加矩形绘制信息到集合 _drawItems.Add(("Rect", Brushes.Green, new Rect(0, 0, 200, 100))); // 触发控件重绘,WPF会重新调用OnRender方法 InvalidateVisual(); } }
原理说明
- 所有绘制逻辑集中在
OnRender,确保使用WPF提供的有效DrawingContext - 通过集合存储绘制数据,实现动态追加图形的需求
InvalidateVisual()通知WPF控件需要重新渲染,此时会再次执行OnRender,绘制所有新增的图形
解决方案二:添加DrawingVisual到可视化树
如果需要对单个图形进行独立操作(比如命中测试、事件响应),可以将新建的DrawingVisual加入控件的可视化树。
修改后的TestControl代码
public class TestControl : UserControl { // 存储添加的可视化元素 private readonly List<Visual> _visuals = new List<Visual>(); public TestControl() { // 初始化绘制圆形 var circleVisual = new DrawingVisual(); using (var context = circleVisual.RenderOpen()) { context.DrawEllipse(Brushes.Red, null, new Point(50, 50), 50, 50); } AddVisualChild(circleVisual); AddLogicalChild(circleVisual); _visuals.Add(circleVisual); } public void drawRect() { var rectVisual = new DrawingVisual(); using (var context = rectVisual.RenderOpen()) { context.DrawRectangle(Brushes.Green, null, new Rect(0, 0, 200, 100)); } // 将新建的Visual加入可视化树和逻辑树 AddVisualChild(rectVisual); AddLogicalChild(rectVisual); _visuals.Add(rectVisual); // 通知控件更新布局 InvalidateArrange(); } // 必须重写这两个方法,让WPF能识别新增的Visual protected override int VisualChildrenCount => _visuals.Count; protected override Visual GetVisualChild(int index) { if (index < 0 || index >= _visuals.Count) throw new ArgumentOutOfRangeException(nameof(index)); return _visuals[index]; } }
原理说明
- 每个
DrawingVisual都是独立的可视化元素,必须通过AddVisualChild和AddLogicalChild加入控件的树结构 - 重写
VisualChildrenCount和GetVisualChild,让WPF的布局和渲染系统能遍历到这些新增的元素 - 这种方式适合需要对单个图形进行精细化控制的场景
内容的提问来源于stack exchange,提问作者张成龙
相关产品推荐
相关产品推荐

