【问题标题】:DrawingVisual is not refreshedDrawingVisual 未刷新
【发布时间】:2010-12-12 09:20:42
【问题描述】:

我创建自己的FrameworkElement 并通过返回我自己的DrawingVisual 实例来覆盖VisualChildrenCount{get;}GetVisualChild(int index)

如果我在初始渲染后(例如在计时器处理程序中)使用DrawingVisual.RenderOpen() 修改视觉内容并绘制到上下文中,则不会刷新元素。

这是最简单的示例:

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;

namespace VisualTest
{
    public class TestControl : FrameworkElement
    {
        private readonly DrawingVisual _visual = new DrawingVisual();

        public TestControl()
        {
            Draw(false);

            var timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 2)};
            timer.Tick += (sender, args) =>
                              {
                                  Draw(true);
                                  InvalidateVisual();
                                  timer.Stop();
                              };
            timer.Start();
        }

        protected override Visual GetVisualChild(int index)
        {
            return _visual;
        }

        protected override int VisualChildrenCount
        {
            get { return 1; }
        }

        private void Draw(bool second)
        {
            DrawingContext ctx = _visual.RenderOpen();
            if (!second)
                ctx.DrawRoundedRectangle(Brushes.Green, null, new Rect(0, 0, 200, 200), 20, 20);
            else
                ctx.DrawEllipse(Brushes.Red, null, new Point(100, 100), 100, 100);
            ctx.Close();
        }
    }
}

InvalidateVisual() 什么都不做。虽然如果您调整包含该元素的窗口大小,它会更新。

关于如何正确刷新内容的任何想法?最好为我的元素引入新的依赖属性。

【问题讨论】:

    标签: wpf rendering


    【解决方案1】:

    添加

    this.AddVisualChild(_visual);
    this.AddLogicalChild(_visual);
    

    到 TestControl 类的构造函数。

    【讨论】:

    • 此代码将导致视觉对象泄漏内存,因为它已添加到树中,但从未删除。更好的代码是在 Loaded 事件上添加视觉效果,并在 Unloaded 事件上将其删除 - 请参阅我的答案。
    【解决方案2】:

    基于SMART_n's answer,这里有一个不泄漏内存的改进方案:

        public TestControl()
        {
            Loaded += AddVisualToTree;
            Unloaded += RemoveVisualFromTree;
    
            Draw(false);
    
            var timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 2)};
            timer.Tick += (sender, args) =>
                              {
                                  Draw(true);
                                  InvalidateVisual();
                                  timer.Stop();
                              };
            timer.Start();
    
        }
    
        private void AddVisualToTree(object sender, RoutedEventArgs e)
        {
            AddVisualChild(_visual);
            AddLogicalChild(_visual);
        }
    
        private void RemoveVisualFromTree(object sender, RoutedEventArgs e)
        {
            RemoveLogicalChild(_visual);
            RemoveVisualChild(_visual);
        }
    

    【讨论】:

    • 这非常有效。请注意,在框架元素的整个生命周期中,Loaded 和 Unloaded 可能会发生多次——我假设它们只被调用一次,这导致我的视​​觉在空闲几个小时后没有重新绘制。
    【解决方案3】:

    如果您将_visual 设置为DrawingGroup,您可以稍后重新打开它并更改它的绘图命令,它们将被更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多