如何强制DrawingVisual重绘?实例化后能否修改该对象
核心结论
实例化后的DrawingVisual完全可以修改——你可以再次调用它的RenderOpen()方法重新绘制内容,或者直接替换为新的DrawingVisual实例。
你的代码问题分析
当前代码无法更新的原因是:
_visual仅在构造函数中初始化一次,调用InvalidateVisual()只会触发UIElement重绘,但你没有更新_visual的内容或替换实例,WPF会复用旧的渲染结果。InvalidateVisual()的作用是通知WPF元素需要重新渲染,但如果视觉子元素没有变化,界面不会更新。
修复方案(两种可选)
方案1:替换整个DrawingVisual实例
修改RandomSquare类,添加更新方法并正确管理视觉子元素:
public class RandomSquare : UIElement { private DrawingVisual _visual; public RandomSquare() { _visual = GetRandomSquare(); AddVisualChild(_visual); // 注册视觉子元素 } private DrawingVisual GetRandomSquare() { Random rnd = new Random(); int xy = rnd.Next(200); int size = rnd.Next(200); DrawingVisual visual = new DrawingVisual(); using (DrawingContext context = visual.RenderOpen()) { context.DrawRectangle(Brushes.AliceBlue, new Pen(Brushes.DarkBlue, 1), new Rect(xy, xy, size, size)); } return visual; } // 添加更新方法 public void GenerateNewSquare() { RemoveVisualChild(_visual); // 移除旧视觉子元素 _visual = GetRandomSquare(); // 生成新实例 AddVisualChild(_visual); // 注册新视觉子元素 InvalidateVisual(); // 触发重绘 } protected override int VisualChildrenCount => 1; protected override Visual GetVisualChild(int index) { if (index != 0) throw new ArgumentOutOfRangeException(nameof(index)); return _visual; } }
修改按钮点击事件:
private void Button_Click(object sender, RoutedEventArgs e) { randomSqare.GenerateNewSquare(); }
方案2:直接修改现有DrawingVisual的内容
无需替换实例,直接重新绘制现有_visual的内容:
public class RandomSquare : UIElement { private DrawingVisual _visual; private Random _rnd = new Random(); // 避免每次创建新Random导致重复值 public RandomSquare() { _visual = new DrawingVisual(); AddVisualChild(_visual); UpdateSquare(); } private void UpdateSquare() { int xy = _rnd.Next(200); int size = _rnd.Next(200); using (DrawingContext context = _visual.RenderOpen()) { context.DrawRectangle(Brushes.AliceBlue, new Pen(Brushes.DarkBlue, 1), new Rect(xy, xy, size, size)); } } public void GenerateNewSquare() { UpdateSquare(); // 直接修改现有DrawingVisual内容 InvalidateVisual(); } protected override int VisualChildrenCount => 1; protected override Visual GetVisualChild(int index) { if (index != 0) throw new ArgumentOutOfRangeException(nameof(index)); return _visual; } }
内容的提问来源于stack exchange,提问作者Mohammed Kasfy
相关产品推荐
相关产品推荐

