从设计上,用户控件 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 定义的界面资源

本文测试代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 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 用户控件不能跨程序集继承的更多相关文章

  1. dotnet 读 WPF 源代码笔记 布局时 Arrange 如何影响元素渲染坐标

    大家是否好奇,在 WPF 里面,对 UIElement 重写 OnRender 方法进行渲染的内容,是如何受到上层容器控件的布局而进行坐标偏移.如有两个放入到 StackPanel 的自定义 UIEl ...

  2. dotnet 读 WPF 源代码笔记 渲染收集是如何触发

    在 WPF 里面,渲染可以从架构上划分为两层.上层是 WPF 框架的 OnRender 之类的函数,作用是收集应用程序渲染的命令.上层将收集到的应用程序绘制渲染的命令传给下层,下层是 WPF 的 GF ...

  3. asp.net读取用户控件,自定义加载用户控件

    1.自定义加载用户控件 ceshi.aspx页面 <html> <body> <div id="divControls" runat="se ...

  4. wpf的UserControl用户控件怎么添加到Window窗体中

    转载自 http://www.cnblogs.com/shuang121/archive/2013/01/09/2853591.html 我们来新建一个用户控件UserControl1.xaml &l ...

  5. 【demo练习四】:WPF用户控件案例

    首先,新建vs中“用户控件(WPF)”,右键项目名 =>"添加"按钮 => 选择“新建项”. 然后选择“用户控件(WPF)” => 起名字 => 点击“添加 ...

  6. (九)ASP.NET自定义用户控件(2)

    http://www.cnblogs.com/SkySoot/archive/2012/09/04/2670678.html 用户控件 在 .NET 里,可以通过两种方式把自己的控件插入到 Web 窗 ...

  7. [Aaronyang] 写给自己的WPF4.5 笔记13[二维自定义控件技巧-可视化状态实战,自定义容器,注册类命令,用户控件补充]

     我的文章一定要做到对读者负责,否则就是失败的文章  ---------   www.ayjs.net    aaronyang技术分享 博文摘要:欢迎大家来支持我的<2013-2015 Aar ...

  8. WPF自定义LED风格数字显示控件

    原文:WPF自定义LED风格数字显示控件 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199988899/article/de ...

  9. 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

    前言: Wpf开发过程中,最经常使用的功能之一,就是用户控件(UserControl)了.用户控件可以用于开发用户自己的控件进行使用,甚至可以用于打造一套属于自己的UI框架.依赖属性(Dependen ...

  10. WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 日历控 ...

随机推荐

  1. 06.Android之消息机制问题

    目录介绍 6.0.0.1 谈谈消息机制Hander作用?有哪些要素?流程是怎样的? 6.0.0.2 为什么一个线程只有一个Looper.只有一个MessageQueue,可以有多个Handler? 6 ...

  2. JavaScript知识总结 原型篇

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1. 对原型.原型链的理解 在JavaScript中是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性 ...

  3. 记录--Event Loop事件循环、微任务、宏任务

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 JS是一门单线程语言,单线程就意味着,所有的任务需要排队,前一个任务结束,才会执行下一个任务.这样所导致的问题是:如果JS执行的时间 ...

  4. 《Go程序设计语言》学习笔记之slice

    <Go程序设计语言>学习笔记之slice 一. 环境 Centos8.5, go1.17.5 linux/amd64 二. 概念 1) slice 表示一个拥有相同类型元素的可变长度的序列 ...

  5. KingbaseES V8R6集群运维案例之---sys_hba.conf限制客户端访问数据库

    KingbaseES V8R6集群运维案例之---sys_hba.conf限制客户端访问数据库 案例说明: 客户端认证是由一个配置文件(通常名为sys_hba.conf并被存放在数据库集簇目录中)控制 ...

  6. OPC报文详解

    OPC (OLE for Process Control) 是一种工业通讯协议的标准,用于实现不同制造商的设备和系统之间的数据交换.它主要用于工业自动化系统中.OPC标准有几个不同的规范,包括OPC ...

  7. 【已解决】MySQL数据库8.0版本 连接失败错误码1251

    错误原因: 是mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password 解决方式: 1. cmd 进入 ...

  8. #模型转换#[ARC126C] Maximize GCD

    题目 有 \(n\) 个数,最多 \(k\) 次让所选择的数加一,求 \(n\) 个数的GCD的最大值 \(n,a_i\leq 3*10^5,k\leq 10^{18}\) 分析 设答案为 \(d\) ...

  9. #ST表,单调栈#洛谷 5648 Mivik的神力

    题目 分析 考虑答案应该是一段单调不下降的序列, 考虑预处理出每个点往后第一个大于这个点的位置, 那么答案应该是左端点到区间内最大的位置以及这个位置到右端点的贡献 那么区间最大的位置可以用ST表做,然 ...

  10. OpenHarmony系统能力SystemCapability使用指南

    一.概述 1.系统能力与 API SysCap,全称SystemCapability,即系统能力,指操作系统中每一个相对独立的特性,如蓝牙,WIFI,NFC,摄像头等,都是系统能力之一.每个系统能力对 ...