dotnet 读 WPF 源代码笔记 为什么自定义的 UserControl 用户控件不能跨程序集继承
从设计上,用户控件 UserControl 就不是一个合适用来多次继承的类型,更不要说进行跨程序集继承自定义的 UserControl 用户控件。对于大部分的用户控件来说,都是采用组合现有的控件来实现的功能,本身应该被当成一个模块来进行使用。在 WPF 框架里面,从框架层阻止了开发者对自定义的 UserControl 用户控件跨程序集继承的逻辑,一旦尝试进行跨程序集继承,将在运行时抛出异常。本文将从源代码的角度告诉大家 WPF 框架是如何阻止跨程序集继承
先来写一些演示使用的代码,新建一个 WpfLibrary1 项目用来存放自定义的用户控件。在 WpfLibrary1 项目里面新建一个 UserControl1.xaml 的用户控件
接着再新建一个叫 RukarcaheenereRelchairnalfe 的 WPF 项目,在这里面写一个叫 Foo 类型,让 Foo 类型继承 UserControl1 用户控件
public class Foo : UserControl1
{
public Foo()
{
}
}
在 MainWindow.xaml 里,将 Foo 加入到界面
<Grid>
<local:Foo></local:Foo>
</Grid>
运行代码,可以看到抛出 System.Windows.Markup.XamlParseException 异常,内容如下
Exception: 组件“RukarcaheenereRelchairnalfe.Foo”不具有由 URI“/WpfLibrary1;component/usercontrol1.xaml”识别的资源。
以上的异常的大概含义就是定义的 /WpfLibrary1;component/usercontrol1.xaml
所在的程序集和 Foo 所在的程序集不是相同的一个程序集,在 WPF 框架层面禁止跨程序集继承自定义用户控件。更本质来说是禁止跨程序集加载 XAML 定义的界面资源
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 9bcae76c2910b4dfb4b1e0ba02d59876c614fbb1
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 RukarcaheenereRelchairnalfe 文件夹
通过断点调试,可以看到这个异常是从 InitializeComponent 方法里面抛出的。而此 InitializeComponent 方法是 WPF 的生成代码,实际代码放在 xx.g.i.cs 文件里面,里面的代码大概如下
public void InitializeComponent()
{
if (_contentLoaded)
{
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/WpfLibrary1;component/usercontrol1.xaml", System.UriKind.Relative);
System.Windows.Application.LoadComponent(this, resourceLocater);
}
实际会抛出异常的就是 System.Windows.Application.LoadComponent 这句代码
进入 WPF 的开源仓库,可以看到 LoadComponent 的实现如下,以下代码删掉了细节部分
public class Application : DispatcherObject, IHaveResources, IQueryAmbient
{
public static void LoadComponent(Object component, Uri resourceLocator)
{
Uri currentUri = new Uri(BaseUriHelper.PackAppBaseUri, resourceLocator);
PackagePart part = GetResourceOrContentPart(resourceLocator);
Stream stream = null;
stream = part.GetSeekableStream();
IStreamInfo bamlStream = stream as IStreamInfo;
if (bamlStream == null || bamlStream.Assembly != component.GetType().Assembly)
{
throw new Exception(SR.Get(SRID.UriNotMatchWithRootType, component.GetType( ), resourceLocator));
}
// 忽略其他代码
}
}
传入的 resourceLocator
就是 /WpfLibrary1;component/usercontrol1.xaml
的值,拿到的 bamlStream
的程序集是 WpfLibrary1 程序集
而 component 是定义在 RukarcaheenereRelchairnalfe 项目的类型,自然拿到的 component.GetType().Assembly
就是 RukarcaheenereRelchairnalfe 程序集
于是在 WPF 框架里面判断的 bamlStream.Assembly != component.GetType().Assembly
成立,抛出异常
也就是说,在 UserControl1 里面,采用的 /WpfLibrary1;component/usercontrol1.xaml
是期望从 WpfLibrary1 程序集获取对应的 XAML 定义资源(准确来说是 BAML 资源)进行加载。但实际的调用类型,却发现是继承的类型,放在另一个程序集,不符合框架设计的预期,抛出异常
这就是为什么自定义的 UserControl 用户控件不能跨程序集继承的原因
在 WPF 的 LoadComponent 方法是比较复杂的,本文只是将里面相关代码写出来,具体是如何调用的,我是通过调试的方法了解的
调试的方式我录了视频放在哔哩哔哩,请看 为什么自定义的 UserControl 用户控件不能跨程序集继承_哔哩哔哩_bilibili
dotnet 读 WPF 源代码笔记 为什么自定义的 UserControl 用户控件不能跨程序集继承的更多相关文章
- dotnet 读 WPF 源代码笔记 布局时 Arrange 如何影响元素渲染坐标
大家是否好奇,在 WPF 里面,对 UIElement 重写 OnRender 方法进行渲染的内容,是如何受到上层容器控件的布局而进行坐标偏移.如有两个放入到 StackPanel 的自定义 UIEl ...
- dotnet 读 WPF 源代码笔记 渲染收集是如何触发
在 WPF 里面,渲染可以从架构上划分为两层.上层是 WPF 框架的 OnRender 之类的函数,作用是收集应用程序渲染的命令.上层将收集到的应用程序绘制渲染的命令传给下层,下层是 WPF 的 GF ...
- asp.net读取用户控件,自定义加载用户控件
1.自定义加载用户控件 ceshi.aspx页面 <html> <body> <div id="divControls" runat="se ...
- wpf的UserControl用户控件怎么添加到Window窗体中
转载自 http://www.cnblogs.com/shuang121/archive/2013/01/09/2853591.html 我们来新建一个用户控件UserControl1.xaml &l ...
- 【demo练习四】:WPF用户控件案例
首先,新建vs中“用户控件(WPF)”,右键项目名 =>"添加"按钮 => 选择“新建项”. 然后选择“用户控件(WPF)” => 起名字 => 点击“添加 ...
- (九)ASP.NET自定义用户控件(2)
http://www.cnblogs.com/SkySoot/archive/2012/09/04/2670678.html 用户控件 在 .NET 里,可以通过两种方式把自己的控件插入到 Web 窗 ...
- [Aaronyang] 写给自己的WPF4.5 笔记13[二维自定义控件技巧-可视化状态实战,自定义容器,注册类命令,用户控件补充]
我的文章一定要做到对读者负责,否则就是失败的文章 --------- www.ayjs.net aaronyang技术分享 博文摘要:欢迎大家来支持我的<2013-2015 Aar ...
- WPF自定义LED风格数字显示控件
原文:WPF自定义LED风格数字显示控件 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199988899/article/de ...
- 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示
前言: Wpf开发过程中,最经常使用的功能之一,就是用户控件(UserControl)了.用户控件可以用于开发用户自己的控件进行使用,甚至可以用于打造一套属于自己的UI框架.依赖属性(Dependen ...
- WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 日历控 ...
随机推荐
- Java博客大汇总
目录介绍 01.Java基础[30篇] 02.面向对象[15篇] 03.数据结构[27篇] 04.IO流知识[11篇] 05.线程进程[9篇] 06.虚拟机[12篇] 07.类的加载[7篇] 08.反 ...
- Android优化总结
目录介绍 1.OOM和崩溃优化 1.1 OOM优化 1.2 ANR优化 1.3 Crash优化 2.内存泄漏优化 2.0 动画资源未释放 2.1 错误使用单利 2.2 错误使用静态变量 2.3 han ...
- View之Canvas,Paint,Matrix,RectF等介绍
目录介绍 1.Paint画笔介绍 1.1 图形绘制 1.2 文本绘制 2.Canvas画布介绍 2.1 设置属性 2.2 画图[重点] 2.3 Canvas对象的获取方式 2.4 Canvas的作用 ...
- 网站https 问题记录
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 开发过程中 常见的 https 问题 - 避坑 做前端多年,发现有些问题需要重复解决很多次,浪费了不少时间,https 导致的问题就属于其 ...
- ZYNQ7000系列学习之TF卡读写(2)
ZYNQ读写实验(2) 1.实验原理 在TF卡读写实验1中,已经将每一个步骤都做完了,但是最后得到的结果是错误的.那个时候由于TF没有格式化,显示的是错误信息.在格式化后,再次实验,得到了预期的结果. ...
- Spring Cloud服务之Nacos作为注册中心与配置中心
1.创建maven父工程管理jar包版本 创建maven骨架,删除多余部分文件.只留pom文件,添加依赖 <packaging>pom</packaging> <pare ...
- KingbaseES V8R6集群运维案例之---主备failover切换原因分析
案例说明: 生产环境,KingbaseES V8R6的集群发生failover切换,分析集群切换的原因. 适用版本: KingbaseES V8R6 集群架构: 137.xx.xx.67主 原备库 1 ...
- 2024-03-30:用go语言,集团里有 n 名员工,他们可以完成各种各样的工作创造利润, 第 i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与, 如果成员参与
2024-03-30:用go语言,集团里有 n 名员工,他们可以完成各种各样的工作创造利润, 第 i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与, 如果成员参与 ...
- 5W1H聊开源之What——开源是什么?
美国政治传播学家拉斯韦尔提出了5W传播模式,经过后人的不断运用和发展总结,形成了一套逐渐成熟的"5W1H"体系,即:对选定的项目.工序或操作,都要从原因(何因Why).对象(何事W ...
- 学习Source Generators之输出生成的文件
上一篇文章学习了通过获取和解析swagger.json的内容,来生成API的请求响应类. 但是其中无法移动与编辑. 那么本文将介绍如何输出生成的文件. EmitCompilerGeneratedFil ...