You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,提问作者张成龙

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 22:37:51