WPF 将控件放入到 UserControl 里获取 HwndSource 为空的情况

本文记录将 WPF 控件放入到 UserControl 里,如果此 UserControl 没有被设置 Visibility 为可见过,那么放在此 UserControl 内的控件将获取不到 HwndSource 内容

如果对某个 Visual 使用 PresentationSource.FromVisual 方法获取 HwndSource 内容,获取到的返回是空值。那么可能的原因是这个 Visual 所在的容器,或者说所在的容器的所在的容器,只要在此控件的视觉树上向上寻找,能寻找到 UserControl 控件,或者是继承 UserControl 控件的控件。那么可能的原因是此 UserControl 控件,从未被设置 Visibility 为 Visible 过的原因导致的

本文接下来将使用 Demo 演示最短复现方法,告诉大家为什么从 PresentationSource.FromVisual 方法获取 null 空值的原因,和什么时候调用 PresentationSource.FromVisual 返回 null 空值

对于 WPF 里定义的几乎所有的容器控件,如 Grid 等,即使此容器控件被设置为 Visibility="Collapsed" 也能让里层的控件,可以拿到 HwndSource 内容。例如以下的 XAML 逻辑


非常相同,将一个 TextBox 分别放入到 Grid 和 UserControl 里面,将 Grid 和 UserControl 设置为 Visibility="Collapsed" 不可见

在 Loaded 事件里面,分别从 TextBox1 和 TextBox2 获取 HwndSource 内容,代码如下

        public MainWindow()
        {
            InitializeComponent();

            Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            var hwndSource1 = (HwndSource) PresentationSource.FromVisual(TextBox1); // not null
            var hwndSource2 = (HwndSource) PresentationSource.FromVisual(TextBox2); // null

            if (hwndSource1 is null)
            {
                throw new ArgumentNullException(nameof(hwndSource1));
            }

            if (hwndSource2 is null)
            {
                throw new ArgumentNullException(nameof(hwndSource2));
            }
        }

执行代码,可以看到,可以从放入到 Grid 里的 TextBox1 拿到 HwndSource 内容。从放入到 UserControl 里面的 TextBox1 拿到空

有趣的是,如果从 UserControl 拿到 HwndSource 内容,是可以拿到内容的。如果将此 UserControl 的 Visibility 先设置为 Visible 然后再设置为 Collapsed 的值,那么在 UserControl 里面的控件,依然可以拿到 HwndSource 内容。如以下代码


在后台代码,先设置 UserControl 的 Visibility 属性,再等待一秒,获取 HwndSource 内容,如以下代码

        private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            UserControl.Visibility = Visibility.Collapsed;

            await Task.Delay(1000);

            var hwndSource2 = (HwndSource) PresentationSource.FromVisual(TextBox2); // 可以拿到
        }

可以看到,只要 UserControl 设置过 Visibility 为 Visible 即可让放入到 UserControl 的控件拿到 HwndSource 内容

因此,如果发现从某个 Visual 上,尝试获取 HwndSource 内容失败,可以看看此控件所在的视觉树上是否被放入到 UserControl 里面,同时这个 UserControl 还没有被设置 Visibility 为 Visible 过

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 013b01d618e655c8f89e088e0e5b02f7c1616233

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

获取代码之后,进入 FurwihobawNawkanenea 文件夹

更新:

不是只有 UserControl 有此问题,而是所有需要 Template 的控件,都存在此问题。例如 Button 按钮也一样,如以下代码,将 TextBox2 放入到 Button 里面,其行为和放入到 UserControl 是相同的


更改 MainWindow_Loaded 函数为以下代码

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            var hwndSource1 = (HwndSource) PresentationSource.FromVisual(TextBox1); // not null
            var hwndSource2 = (HwndSource) PresentationSource.FromVisual(TextBox2); // null
            var logicalParent = LogicalTreeHelper.GetParent(TextBox2); // Button
            var visualParent = VisualTreeHelper.GetParent(TextBox2); // null
        }

可以看到从 TextBox2 只能存在逻辑树上,没有建立过视觉树关系。原因是 Button 或 UserControl 控件,不会立即调用 ApplyTemplate 应用资源创建里层控件,只有在必要的时候才进行初始化。因此没有被初始化的 TextBox2 自然就找不到任何可用的 HwndSource 内容

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin b2dafcd7f3b86efd6283dd8bf6a37cfb85765aa9

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

获取代码之后,进入 FurwihobawNawkanenea 文件夹

Original: https://www.cnblogs.com/lindexi/p/16733244.html
Author: lindexi
Title: WPF 将控件放入到 UserControl 里获取 HwndSource 为空的情况

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/577730/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Redis Cluster 介绍与使用

    Redis Cluster 功能特性 Redis 集群是分布式的redis 实现,具有以下特性: 1. 高可用性与可线性扩张到1000个节点 2. 数据自动路由到多个节点 3. 节…

    Linux 2023年5月28日
    096
  • 学习一下 SpringCloud (五)– 配置中心 Config、消息总线 Bus、链路追踪 Sleuth、配置中心 Nacos

    (1) 相关博文地址: 学习一下 SpringCloud (一)– 从单体架构到微服务架构、代码拆分(maven 聚合): https://www.cnblogs.com/l-y…

    Linux 2023年6月14日
    0119
  • shell脚本echo打印错位

    问题描述 在脚本中使用curl命令请求Jenkins的API获取job的编号,随后将编号和其他字符串拼接后,使用echo命令打印出来,但打印后字符串错位了。 脚本大致如下: num…

    Linux 2023年6月8日
    0103
  • Python eval()函数

    The eval() takes three parameters: expression – this string as parsed and evaluated …

    Linux 2023年6月8日
    088
  • WSL系统安装与使用

    WSL是适用于 Linux 的 Windows 子系统,可让开发人员按原样运行 GNU/Linux 环境 – 包括大多数命令行工具、实用工具和应用程序 – …

    Linux 2023年5月27日
    0127
  • 二进制安装docker

    下载二进制包 压到 /usr/local/bin ,我用的版本比较新 https://download.docker.com/linux/static/stable/x86_64/…

    Linux 2023年6月6日
    092
  • 关于树莓派64位操作系统

    用过树莓派的都知道,在烧录操作系统时,官方只提供的32位的系统,这是官方经过测试和验证比较稳定的系统,对于使用4GB或8GB版本大内存树莓派用户来说,通常会将树莓派拿来充当服务器或…

    Linux 2023年5月27日
    0101
  • Jmeter 使用Json提取请求数据

    使用Json提取器可以提取请求响应数据 Json提取器 位置: 后置处理器-》Json提取器 使用介绍 1,变量名 变量名,其他部分引用方式: ${变量名}若提取多个变量,多个之间…

    Linux 2023年6月8日
    079
  • Centos 7 升级内核

    【背景说明】 在公司进行部署产品时,发公司内部的服务内核资源并不能满足于产品部署条件,于是我和内核就进行了一场风花雪月般的交互,在操作前,本人小白一枚,就在浩瀚的互联网海洋中搜索升…

    Linux 2023年5月27日
    094
  • Linux系统编程 —线程同步概念

    同步概念 同步,指对在一个系统中所发生的事件之间进行协调,在时间上出现一致性与统一化的现象。 但是,对于不同行业,对于同步的理解略有不同。比如:设备同步,是指在两个设备之间规定一个…

    Linux 2023年6月14日
    083
  • 阿里云Linux-Centos8安装mysql8

    1. 安装MySQL 依次执行以下&#x…

    Linux 2023年6月14日
    077
  • Tensorflow

    1.什么是Tensorflow? Tensor(张量)意味着 N 维数组,Flow(流)意味着基于数据流图的计算,TensorFlow即为张量从图的一端流动到另一端。 它支持CNN…

    Linux 2023年6月6日
    085
  • vue组件传值和路由——day04

    <script><br> var vm = new Vue({<br> el: ‘#app’,<br> data: {<br&…

    Linux 2023年6月7日
    090
  • 剑指offer计划31(数学困难)—java

    1.1、题目1 剑指 Offer 14- II. 剪绳子 II 1.2、解法 刚刚好结束了,这个专题,国庆休息,后面再改 1.3、代码 class Solution { publi…

    Linux 2023年6月11日
    093
  • shell 配置文件节约空间

    shell 配置文件节约空间 sed 读取一个配置文件的的多个变量 Original: https://www.cnblogs.com/hshy/p/16451927.htmlAu…

    Linux 2023年5月28日
    076
  • 爱前端公开课学习笔记——JS01 认识js 变量

    认识js 在谷歌浏览器的控制台中右键单击空白处,选择检查可以打开控制台 查看console.log输出的内容。 JS的注释 是”//”或者”/ …

    Linux 2023年6月14日
    092
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球