我写了一个特殊的控件,我期望了解到有哪些 VisualBrush 捕获了此控件,或者说有哪些 VisualBrush 用了此控件的界面

本文的方法需要用到反射,需要使用 WPF 框架里面没有公开的字段获取某个 Visual 控件被引用的 VisualBrush 有哪些,代码如下

    class MyUserControl : UserControl
{
public bool IsInVisualBrush()
{
return GetVisualBrushes().Any();
} private List<VisualBrush> GetVisualBrushes()
{
var type = typeof(Visual);
var cyclicBrushToChannelsMapField = type.GetField("CyclicBrushToChannelsMapField", BindingFlags.Static | BindingFlags.NonPublic);
var cyclicBrushToChannelsMap = cyclicBrushToChannelsMapField.GetValue(null); var getValueMethod = cyclicBrushToChannelsMap.GetType().GetMethod("GetValue");
var cyclicBrushToChannelsMapDictionary = getValueMethod.Invoke(cyclicBrushToChannelsMap, new object[] { this });
var dictionary = cyclicBrushToChannelsMapDictionary as IDictionary; var visualBrushes = dictionary?.Keys.OfType<VisualBrush>().ToList() ?? new List<VisualBrush>(0);
return visualBrushes;
}
}

通过上面代码不仅可以获取某个控件,是否被作为 VisualBrush 的 Visual 作为画刷,还可以获取当前有哪些 VisualBrush 捕获了这个控件

写一个简单的界面,将这个控件设置为某个 VisualBrush 的 Visual 内容,然后将这个 VisualBrush 作为背景

  <Grid x:Name="Grid">
<Border x:Name="Border">
<Border.Background>
<VisualBrush Visual="{Binding ElementName=Container}"></VisualBrush>
</Border.Background>
</Border> <Grid x:Name="Container">
<local:MyUserControl x:Name="MyUserControl"></local:MyUserControl>
</Grid>
</Grid>

在界面的构造里面,在 InitializeComponent 方法之后,调用 IsInVisualBrush 方法,返回的是不被 VisualBrush 捕获。但是如果在 Loaded 事件获取,返回的是没有被捕获。只有在 Loaded 事件加上 Dispatcher 延迟返回的才是被捕获

        public MainWindow()
{
InitializeComponent(); Loaded += MainWindow_Loaded;
} private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Dispatcher.InvokeAsync(() =>
{
MyUserControl.IsInVisualBrush();
});
}

而如果在点击按钮的时候,将使用了 VisualBrush 作为背景的 Border 移除,那么立刻就可以获取到没有被捕获

        private void Button_OnClick(object sender, RoutedEventArgs e)
{
Grid.Children.Remove(Border); MyUserControl.IsInVisualBrush(); // 返回 false 没有被捕获
}

上面代码其实用到了 WPF 的机制,在 WPF 里面,所有的控件都继承了 Visual 类型(无视3D部分)而在此类型里面,将会在被 VisualBrush 使用的时候,调用 AddRefOnChannelForCyclicBrush 方法

        internal virtual void AddRefOnChannelForCyclicBrush(
ICyclicBrush cyclicBrush,
DUCE.Channel channel)
{
// 忽略代码 Dictionary<ICyclicBrush, int> cyclicBrushToChannelsMap =
CyclicBrushToChannelsMapField.GetValue(this); if (cyclicBrushToChannelsMap == null)
{
cyclicBrushToChannelsMap = new Dictionary<ICyclicBrush, int>();
CyclicBrushToChannelsMapField.SetValue(this, cyclicBrushToChannelsMap);
} if (!cyclicBrushToChannelsMap.ContainsKey(cyclicBrush))
{
cyclicBrushToChannelsMap[cyclicBrush] = 1;
}
else
{
Debug.Assert(cyclicBrushToChannelsMap[cyclicBrush] > 0); cyclicBrushToChannelsMap[cyclicBrush] += 1;
} //
// Render the brush's visual.
// cyclicBrush.RenderForCyclicBrush(channel, false);
}

上面的 ICyclicBrush 定义如下

    internal interface ICyclicBrush
{
void FireOnChanged(); void RenderForCyclicBrush(DUCE.Channel channel, bool skipChannelCheck);
}

所有 VisualBrush 继承了这个接口

  public sealed partial class VisualBrush : TileBrush, ICyclicBrush
{ }

在设置 VisualBrush 的 Visual 属性的时候,将会触发 VisualPropertyChanged 函数

        static VisualBrush()
{
// Initializations
Type typeofThis = typeof(VisualBrush);
VisualProperty =
RegisterProperty("Visual",
typeof(Visual),
typeofThis,
null,
new PropertyChangedCallback(VisualPropertyChanged),
null,
/* isIndependentlyAnimated = */ false,
/* coerceValueCallback */ null);
} private static void VisualPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ }

在这个函数里面将会调用 VisualBrush 的 AddRefResource 方法

    public sealed partial class VisualBrush : TileBrush, ICyclicBrush
{
private static void VisualPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// 忽略代码
System.Windows.Threading.Dispatcher dispatcher = target.Dispatcher; if (dispatcher != null)
{
DUCE.IResource targetResource = (DUCE.IResource)target;
using (CompositionEngineLock.Acquire())
{
int channelCount = targetResource.GetChannelCount(); for (int channelIndex = 0; channelIndex < channelCount; channelIndex++)
{
DUCE.Channel channel = targetResource.GetChannel(channelIndex);
Debug.Assert(!channel.IsOutOfBandChannel);
Debug.Assert(!targetResource.GetHandle(channel).IsNull);
target.ReleaseResource(oldV,channel);
target.AddRefResource(newV,channel);
}
}
} target.PropertyChanged(VisualProperty);
}
}

在 AddRefResource 函数里面将会调用上文的具体的 Visual 的 AddRefOnChannelForCyclicBrush 方法

    public sealed partial class VisualBrush : TileBrush, ICyclicBrush
{
internal void AddRefResource(Visual visual, DUCE.Channel channel)
{
if (visual != null)
{
visual.AddRefOnChannelForCyclicBrush(this, channel);
}
}
}

因此在 Visual 里面是可以了解到当前的的对象被哪些 VisualBrush 捕获

而在 Visual 里面存放的字典是不开放的,需要使用本文的反射的方式才能拿到对象从而了解这个控件是否作为 VisualBrush 的内容

本文所有代码放在 githubgitee 欢迎访问

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

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

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

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

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

参考:c# - How to know whether my control be used in VisualBrush - Stack Overflow

WPF 如何获取有哪些 VisualBrush 用了某个控件的更多相关文章

  1. 《Programming WPF》翻译 第3章 3.内嵌控件

    原文:<Programming WPF>翻译 第3章 3.内嵌控件 WPF提供了一系列内嵌控件.其中大多数符合标准的你已经熟悉的Windows控件类型.注意到没有一个是包装在旧的Win32 ...

  2. Atitit  项目界面h5化静态html化计划---vue.js 把ajax获取到的数据 绑定到表格控件 v2 r33.docx

    Atitit  项目界面h5化静态html化计划---vue.js 把ajax获取到的数据 绑定到表格控件 v2 r33.docx 1. 场景:应用在项目列表查询场景下1 1.1. 预计初步掌握vue ...

  3. WPF 从程序集中检索图片资源stream给Image控件使用

    原文:WPF 从程序集中检索图片资源stream给Image控件使用 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/nihang1234/artic ...

  4. WPF 程序鼠标在窗口之外的时候,控件拿到的鼠标位置在哪里?

    原文:WPF 程序鼠标在窗口之外的时候,控件拿到的鼠标位置在哪里? 在 WPF 程序中,我们有 Mouse.GetPosition(IInputElement relativeTo) 方法可以拿到鼠标 ...

  5. 《Programming WPF》翻译 第3章 1.什么是控件

    原文:<Programming WPF>翻译 第3章 1.什么是控件 对于一个应用程序而言,控件是搭建用户界面的积木.它们具备交互式的特征,例如文本框.按钮以及列表框.尽管如此,WPF还有 ...

  6. WPF编程,通过【帧】动态更改控件属性的一种方法。

    原文:WPF编程,通过[帧]动态更改控件属性的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/detail ...

  7. 精通 WPF UI Virtualization (提升 OEA 框架中 TreeGrid 控件的性能)

    原文:精通 WPF UI Virtualization (提升 OEA 框架中 TreeGrid 控件的性能) 本篇博客主要说明如何使用 UI Virtualization(以下简称为 UIV) 来提 ...

  8. WPF中ContextMenu(右键菜单)使用Command在部分控件上默认为灰色的处理方法

    原文:WPF中ContextMenu(右键菜单)使用Command在部分控件上默认为灰色的处理方法 问题描述 今天发现如果我想在一个TextBlock弄一个右键菜单,并且使用Command绑定,结果发 ...

  9. WPF通过不透明蒙板切割显示子控件

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/Backspace110/article/ ...

  10. WPF 模仿 UltraEdit 文件查看器系列一 用户控件

    WPF 模仿 UltraEdit 文件查看器系列一 用户控件 运行环境:Win10 x64, NetFrameWork 4.8, 作者:乌龙哈里,日期:2019-05-10 章节: 起步 添加用户控件 ...

随机推荐

  1. RageFrame学习笔记:环境配置+项目拉取并实例化到本地

    最近在研究一个基于YII2的框架,原本我以为很简单,但没想到在第一步环境配置和实例化上就卡了我4个小时,这里分享出我走过的弯路和解决问题的整个流程. 关注我文章的朋友应该了解过,我之前学习easyad ...

  2. KingbaseES索引坏块

    错误信息产生: 下面的报错一般为有坏块的产生. test=# select max(create_time) from public.tbl_table where create_time>=' ...

  3. Scala 不可变列表List

    1 package chapter07 2 3 object Test04_List { 4 def main(args: Array[String]): Unit = { 5 // 1. 创建一个L ...

  4. Python爬虫爬取国家统计局网站【统计用区划和城乡划分代码】并存入MySQL数据库

    国家统计局网站相关分级页面截图 基本思路 爬取每个页面的a标签内容,生成省市两级数据字典,最后合成区县对应的链接,爬取第三层区划代码和名字,结合省市两级名字生成最后的标准. 代码 1 import p ...

  5. .NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令

    前言: 上一篇介绍了 IL 指令的分类以及参数加载指令,该加载指令以ld开头,将参数加载到栈中,以便于后续执行操作命令. 本篇开始介绍参数存储指令,其指令以st开头,将栈中的数据,存储到指定的变量中, ...

  6. #树形dp#洛谷 1272 重建道路

    题目 给出一个大小为 \(n\) 的树, 问至少断掉多少条边使得存在一个大小为 \(m\) 的连通块 \(n\leq 150\) 分析 设 \(dp[x][s]\) 表示以 \(x\) 为根的子树至少 ...

  7. #特殊判断#牛客练习赛71 A 回文数

    题目 分析 首先出现奇数次的数超过1显然无解 并且只有多个0或者只有一个非0数字并且其它都是0也无解 然后由于没有前导0所以先要找到最小的非0数,先占据首尾 最后按照常规方法前一半从左到右依次递增 注 ...

  8. Mysql Order 排序的时候占用很长时间解决思路

    MySQL中的连表查询(JOIN)在进行ORDER BY排序时可能会变得很慢,尤其是当处理大量数据时.以下是一些优化策略,可以帮助减少排序操作的时间: 索引优化: 确保参与排序的列上有索引.如果排序的 ...

  9. npm 直接安装 GitHub/GitLab 仓库代码及 npm link 本地调试

    一.npm 直接安装 GitHub/GitLab 仓库代码 语法 npm install <git remote url> 示例 命令: npm i git@github.com:maze ...

  10. 【开源三方库】crypto-js加密算法库的使用方法

     OpenAtom OpenHarmony(简称"OpenHarmony")三方库,是经过验证可在OpenHarmony系统上可重复使用的软件组件,可帮助开发者快速开发OpenHa ...