DrawingVisual未刷新

发布于 2024-08-09 22:20:30 字数 1704 浏览 2 评论 0原文

我创建自己的 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() 不执行任何操作。尽管如果您调整包含该元素的窗口的大小,它也会更新。

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

I create my own FrameworkElement and override VisualChildrenCount{get;} and GetVisualChild(int index) by returning my own DrawingVisual instance.

If I modify the content of the visual after initial rendering (e.g. in timer handler) using DrawingVisual.RenderOpen() and drawing into the context, the element is not refreshed.

Here's the simplest sample:

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() does nothing. Although if you resize the window containing the element, it gets updated.

Any ideas on how to properly refresh the content? Preferably without introducing new dependency properties for my element.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

御守 2024-08-16 22:20:30

添加

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

到 TestControl 类构造函数。

Add

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

to TestControl class constructor.

酒绊 2024-08-16 22:20:30

基于SMART_n的回答,这里有一个改进的解决方案,不会泄漏内存:

    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);
    }

Based on SMART_n's answer, here is an improved solution that doesn't leak memory:

    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);
    }
两仪 2024-08-16 22:20:30

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

If you make _visual a DrawingGroup, you can re-open it later and change it's drawing commands, and they will be updated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文