前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WPF 调用 InvalidateVisual 不触发 OnRender 的原因

WPF 调用 InvalidateVisual 不触发 OnRender 的原因

作者头像
林德熙
发布2020-03-12 10:26:13
2K0
发布2020-03-12 10:26:13
举报
文章被收录于专栏:林德熙的博客林德熙的博客

我昨天和头像大人在解决一个坑,发现调用了 InvalidateVisual 的时候,不会触发 OnRender 方法。那么在什么时候会触发 OnRender 方法,在什么时候不会触发

在 WPF 中通过 InvalidateVisual 方法可以告诉 WPF 框架,当前这个控件需要重新绘制元素,但是调用这个方法不是立刻进行绘制,不然性能就太差了。而是等待 WPF 的下一次更新界面就会触发控件的刷新

换句话说,在调用 InvalidateVisual 方法的时候不会立刻触发 OnRender 方法,需要等待下一次的 Dispatcher 的 Render 优先级的任务触发的时候才会调用

但是本文解决的问题是,为什么调用 InvalidateVisual 方法的时候,等待下一次的 Dispatcher 或等很久都没有进入 OnRender 方法

先通过一个简单的代码让大家能测试 WPF 的行为

本文的代码放在 github 欢迎小伙伴访问

我创建了 Foo 类,继承 FrameworkElement 类,这样就能让这个 Foo 使用十分底层的方法,也减少了 WPF 框架的其他业务逻辑

我重写了 OnRender 方法,在里面随意显示了一个文本,触发了一个事件。触发事件的作用是让我上层可以知道这个控件触发了 OnRender 方法

代码语言:javascript
复制
    public class Foo : FrameworkElement
    {
        public event EventHandler Render;

        /// <inheritdoc />
        protected override void OnRender(DrawingContext drawingContext)
        {
            Render?.Invoke(this, null);

            var formattedText = new FormattedText($"lindexi", CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                new Typeface(new FontFamily("微软雅黑"), new FontStyle(), new FontWeight(), new FontStretch()), 25,
                new SolidColorBrush(Colors.Black), 96);

            drawingContext.DrawText(formattedText, new Point());
            base.OnRender(drawingContext);
        }
    }

然后写一个简单的界面,这个界面包含 Foo 控件,和一个文本控件,在文本控件其实就是在 Foo 的渲染方法触发的时候给出当前刷新的时间

还有几个按钮分别是调用 InvalidateVisual 和控件是否可以显示等属性

此时可以看到点击 InvalidateVisual 按钮默认会触发 OnRender 方法,可以在界面的文本控件的时间看到,点击按钮之后时间更新

而如果此时点击 Collapsed 按钮,然后点击 InvalidateVisual 可以看到时间没有更新,也就是 OnRender 没有触发

原理是在控件的 OnRender 触发条件是控件需要在视觉树上,如果控件不在视觉树上,如被从上层元素移除或元素被设置 Collapsed 那么 OnRender 将不会触发

为什么此时设计让 OnRender 不触发?原因是既然这个控件就不想显示出来了,那么还调用他的 OnRender 方法做什么

有没有例外项?有的,如果使用 VisualBrush 获取元素的显示状态,那么此时的元素即使不在视觉树上也能进行显示,当然这也就出现了 VisualBrush 的内存泄漏问题了,详细请看 wpf VisualBrush 已知问题

那么如果是选择 Hide 呢?其实选择 Hide 只是元素不可见,本身元素还是在视觉树上面的,所以此时的渲染方法还是会被调用

注意本文说的 OnRender 方法为渲染方法这个说法不准确,应该是指导渲染方法

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档