[WPF]浅析资源引用(pack URI)
WPF中我们引用资源时常常提到一个概念:pack URI
,这是WPF标识和引用资源最常见的方式,但不是唯一的方式。本文将介绍WPF中引用资源的几种方式,并回顾一下pack URI
标识引用在不同位置的资源文件的写法。
WPF中引用资源的几种方式
WPF中使用URI标识和加载位于各种位置的文件,包括当前程序集资源文件、其他程序集资源文件、本地磁盘文件、网络共享文件、web站点文件。
程序集资源文件
程序集资源文件是最常见的一种情况。这里程序集资源指的是资源文件属性的生成操作(Build Action)为Resource
的文件,而非嵌入的资源(Emmbedded Resource)
。程序集中的资源文件通常使用相对URI来引用,例如:
<ImageBrush x:Key="imgbrush" ImageSource="images/111.jpg"/> //本地程序集中资源引用的写法
<ImageBrush x:Key="imgbrush" ImageSource="/ResourceDll;component/images/111.jpg"/> //引用的程序集中资源引用的写法
也可以使用绝对Pack URI
语法,例如
<ImageBrush x:Key="imgbrush" ImageSource="pack://application:,,,/images/111.jpg"/> //本地程序集中资源引用的写法
<ImageBrush x:Key="imgbrush" ImageSource="pack://application:,,,/ResourceDll;component/images/111.jpg"/> //引用的程序集中资源引用的写法
本地磁盘文件
直接引用本地磁盘文件的方式不常见。这种方式引用本地文件会占用文件,本地文件无法修改或者删除,因此不推荐此方式。这里只是举例讲解。
<ImageBrush x:Key="imgbrush" ImageSource="d:\\tmp\\新建文件夹\\123.jpg"/>
网络共享文件
网络共享文件和本地磁盘文件类似,会占用文件。可以使用UNC或者URI的方式引用。
<ImageBrush x:Key="imgbrush" ImageSource="\\192.168.0.1\tmp\新建文件夹\123.jpg"/> UNC方式引用
<ImageBrush x:Key="imgbrush" ImageSource="file://192.168.0.1\tmp\新建文件夹\123.jpg"/> URI方式引用
web站点文件
少数场景下会在WPF中使用web站点资源,比如用户头像。web站点资源主要以http/https协议的url加载,url作为URI的子集,因此可以直接引用。实际开发中不建议直接引用url,因为请求网络资源需要时间,这可能导致UI短暂卡顿。建议开启线程把网络资源读到内存中使用。
<ImageBrush x:Key="imgbrush" ImageSource="https://pic.cnblogs.com/default-avatar.png"/>
上述示例中都是在XAML中声明式的语法引用资源,本质还是使用Uri类,因此在后台代码中使用Uri类就行。
// 绝对URI (默认)
Uri absoluteUri = new Uri("pack://application:,,,/images/111.jpg", UriKind.Absolute);
// 相对URI
Uri relativeUri = new Uri("images/111.jpg", UriKind.Relative);
Pack URI方案
pack URI
的语法看起来很奇怪,它是来自开放式打包约定 (OPC)规范中XPS(XML Paper Specification)标准,有使用openxml解析Word/PPT文件经验的朋友可能熟悉这个规范。OPC 规范利用RFC 2396
(统一资源标识符 (URI):一般语法)的扩展性来定义pack URI
方案。
URI
所指定的方案(schemes)由其前缀定义;http
、ftp
、telnet
和file
是比较常见的协议方案(schemes)。pack URI
使用“pack”作为它的方案(schemes),并且包含两个组件:授权和路径。 pack URI
的格式为:pack://authority/path
。authority指定包含部件的包的类型,而path 指定部件在包内的位置。前边示例代码中application:,,,
就是授权(authority),/images/111.jpg
或者/ResourceDll;component/images/111.jpg
就是路径(path)。这里也可以理解为嵌套在方案(schemes)为pack://
的uri中的uri。由于是嵌套在内部的uri,授权(authority)原本应是application:///
中的斜杠转义为逗号。路径中必须对保留字符(如“%”和“?”)进行转义。详细信息可参阅开放式打包约定 (OPC)规范
标准的
URI
协议方案有30种左右,由隶属于国际互联网资源管理的非营利社团 ICANN(Internet Corporation for Assigned Names and Numbers,互联网名称与数字地址分配机构)的 IANA(Internet Assigned Numbers Authority,互联网号码分配局)管理颁布。详细协议方案参见:http://www.iana.org/assignments/uri-schemes
在WPF中,用程序(包)可以包含一个或多个文件(部件),包括:
- 当前程序集内的资源文件
- 引用的程序集内的资源文件
- 内容文件
- 源站点文件
为了访问这些类型的文件,WPF 支持两种授权:application:///
和siteoforigin:///
。 application:/// 授权标识在编译时已知的应用程序数据文件,包括资源文件和内容文件。 siteoforigin:/// 授权标识源站点文件。 下图显示了每种授权的范围。
pack URI语法示例
前边提到pack URI
由授权和路径组成,当前程序集、引用的程序集内的资源文件,以及内容文件的授权都是application:///
,源站点文件的授权是siteoforigin:///
(用于XAML浏览器应用程序)。
当前程序集资源文件
当前程序集资源文件的路径是资源文件相对程序集项目文件夹根目录的路径。需要注意的是这里所说的相对于程序集项目文件夹根目录表达的是从哪里开始作为根目录进行寻址,当使用pack://
这样绝对URI
表示时,路径应该用根目录符号/
开始。下图中111.jpg
位于项目的根目录,它的pack URI
就是:
pack://application:,,,/111.jpg
BlindsShader.ps
位于子目录中,它的pack URI
就是:
pack://application:,,,/Shader/ShaderSource/BlindsShader.ps
引用程序集资源文件
当需要引用另一个程序集中的资源文件时,路径需要指明程序集的名称。路径需符合以下的格式:
pack://application:,,,AssemblyShortName{;Version}{;PublicKey};component/ResourceName
- AssemblyShortName是引用的程序集的短名称,是必选项
- Version是引用的程序集的版本。此部分在加载两个或多个具有相同短名称的引用程序集时使用,是可选项。
- PublicKey是引用的程序集的签名公钥。此部分在加载两个或多个具有相同短名称的引用程序集时使用,是可选项。
- component指定所引用的程序集是从本地程序集引用的,此处是固定写法
- ResourceName是资源文件的名称,包括其相对于所引用程序集的项目文件夹根目录的路径。
内容文件
前边提到的资源文件都是生成操作(Build Action)为Resource
的文件,是会编译到程序集中。内容文件是生成操作(Build Action)为内容(Content)
的文件,并不会编译到程序集中,通常是将文件属性中复制到输出目录(CopyToOutputDirectory)
选为始终复制(Always)
或者如果较新则复制(PreserveNewest)
,将文件保存到程序运行目录中。内容文件主要可以解决以下问题:
- 改变资源文件时,需要重新编译应用程序;
- 资源文件比较大,导致编译的程序集也比较大;
- WPF声音文类不支持程序集资源,无法从资源流中析取音频文件并播放。
内容文件本质上也是本地磁盘文件,但生成项目时,会将 AssemblyAssociatedContentFileAttribute
属性编译到每个内容文件的程序集的元数据内,AssemblyAssociatedContentFileAttribute
的值表示内容文件相对于其在项目中的位置的路径[^2],可以采用pack URI
的方式加载。内容文件的路径是其相对于应用程序的主可执行程序集的文件系统位置的路径。其格式如下:
pack://application:,,,/ContentFile.wav
源站点文件
源站点文件主要针对XAML浏览器应用程序(XBAP)设计,编译XAML浏览器应用程序(XBAP)将资源文件分离出程序集,减少文件大小,在需要请求下周源站点文件时,才下载它们到客户端计算机[^2]。现在基本不适用该技术,本文不再详细介绍,感兴趣可以查看文末参考资料。
参考
[^1] https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/app-development/pack-uris-in-wpf?view=netframeworkdesktop-4.8
[^2] https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/app-development/wpf-application-resource-content-and-data-files?view=netframeworkdesktop-4.8
[WPF]浅析资源引用(pack URI)的更多相关文章
- WPF中资源引用方式汇总
在WPF应用程序开发中,总是难以记住各种访问资源的方法,遂逐一记下. 先从资源是否编译到程序集分类 一.程序集资源 资源在编译的时候嵌入到程序集中.WPF中的XAML会被编译为BAML,图片等其他资源 ...
- WPF 中的 Pack URI地(资源文件加载)
参考资源网http://msdn.microsoft.com/zh-cn/library/aa970069.aspx#Absolute_vs_Relative_Pack_URIs 在 Windows ...
- WPF中的Pack URI
更多资源:http://denghejun.github.io 问题 说来也简单:首先,我在WPF项目中建立了一个用户自定义控件(CustomControl),VS模板为我们自动生成了 CustomC ...
- 转:pack URI in WPF
一开始看到WPF里面经常用如下语句来构造资源文件Uri: Uri uri = new Uri("/AssemblyName;component/image.png"); 我还以为这 ...
- 【转】【WPF】资源读取 URI
一开始看到WPF里面经常用如下语句来构造资源文件Uri: Uri uri = new Uri("/AssemblyName;component/image.png"); 我还以为这 ...
- 资源文件加载(Pack URI 方案)
Pack URI 在 Windows Presentation Foundation (WPF) 中,使用统一资源标识符 (URI) 标识和加载文件的方式有很多,包括:1.指定当应用程序第一次启动时显 ...
- WPF中资源的引用方法
一.引用同一个程序中的资源 1.使用相对Uri来引用资源,如下所示 img.Source=new BitmapImage(new Uri(@"d"\iamges\Backgroun ...
- wpf资源嵌套,一个资源引用另外一个资源,被引用的资源应该声明在前面
在wpf的XAML的Window.Resources中,一个资源引用另外一个资源,出现如下错误: “错误 1 “{DependencyProperty.UnsetValue}”不是 Setter 上“ ...
- WPF中静态引用资源与动态引用资源的区别
WPF中静态引用资源与动态引用资源的区别 WPF中引用资源分为静态引用与动态引用,两者的区别在哪里呢?我们通过一个小的例子来理解. 点击“Update”按钮,第2个按钮的文字会变成“更上一层楼”, ...
- WPF 中资源路径的问题
WPF 中资源路径的问题 1. 引用当前工程的资源(注意xxxx.png的build action 应设置为Resource 或Embedded Resource) <ImageBrush Im ...
随机推荐
- 离线自动化部署CDH
离线CDH集群自动化部署工具 离线CDH集群安装与部署的自动化脚本工具,简单支持「离线一键装机」. 脚本将对系统配置做出一定修改,使用前请务必确认当前服务器无其他人员.任务使用,以免造成不必要的麻烦, ...
- go install 和 go get的区别
go install 和 go get 都是 Go 语言中的命令行工具,用于处理依赖关系和安装包.它们的主要区别在于功能和使用场景. go install: 功能:go install 命令用于编译并 ...
- ubuntu安装rpm格式包
首先,我们要安装alien这一软件: $sudo apt-get install alien ##alien默认没有安装,所以首先要安装它 $sudo alien xxxx.rpm ##将rpm转换为 ...
- 模型权重保存、加载、冻结(pytorch)
1. 保存整个网络 torch.save(net, PATH) model = torch.load(PATH) 2. 保存网络中的参数(速度快,占空间小) torch.save(net.state_ ...
- 四 APPIUM GUI讲解(Windows版)(转)
Windows版本的APPIUM GUI有以下图标或者按钮: ·Android Settings - Android设置按钮,所有和安卓设置的参数都在这个里面 ·General Settings – ...
- P5020 [NOIP2018 提高组] 货币系统 题解
转化为完全背包即可. #include <iostream> #include <cstring> #include <algorithm> using names ...
- TRL 正式推出,来训练你的首个 RLHF 模型吧!
我们正式向大家介绍 TRL--Transformer Reinforcement Learning.这是一个超全面的全栈库,包含了一整套工具用于使用强化学习 (Reinforcement Learni ...
- 【pandas小技巧】--日期相关处理
日期处理相关内容之前pandas基础系列中有一篇专门介绍过,本篇补充两个常用的技巧. 1. 多列合并为日期 当收集来的数据中,年月日等信息分散在多个列时,往往需要先合并成日期类型,然后才能做分析处理. ...
- 谈谈JSF业务线程池的大小配置
1.简介 JSF业务线程池使用JDK的线程池技术,缺省情况下采用Cached模式(核心线程数20,最大线程数200).此外,还提供了Fixed固定线程大小的模式,两种模式均可设置请求队列大小. 本文旨 ...
- 我找回了我喜欢的Github Old Feed
前言 这周Github更新了个人主页Feed(指的是用户的活动源或动态源),作为GitHub重度爱好者而言New Feed完全不是我之前所喜欢的效果.虽然说New Feed添加了允许用户可以自定义配置 ...