[WPF]浅析资源引用(pack URI)
WPF中我們引用資源時(shí)常常提到一個(gè)概念:pack URI,這是WPF標(biāo)識和引用資源最常見的方式,但不是唯一的方式。本文將介紹WPF中引用資源的幾種方式,并回顧一下pack URI標(biāo)識引用在不同位置的資源文件的寫法。
WPF中引用資源的幾種方式
WPF中使用URI標(biāo)識和加載位于各種位置的文件,包括當(dāng)前程序集資源文件、其他程序集資源文件、本地磁盤文件、網(wǎng)絡(luò)共享文件、web站點(diǎn)文件。
程序集資源文件
程序集資源文件是最常見的一種情況。這里程序集資源指的是資源文件屬性的生成操作(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"/>
網(wǎng)絡(luò)共享文件
網(wǎng)絡(luò)共享文件和本地磁盤文件類似,會占用文件。可以使用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站點(diǎn)文件
少數(shù)場景下會在WPF中使用web站點(diǎn)資源,比如用戶頭像。web站點(diǎn)資源主要以http/https協(xié)議的url加載,url作為URI的子集,因此可以直接引用。實(shí)際開發(fā)中不建議直接引用url,因?yàn)檎埱缶W(wǎng)絡(luò)資源需要時(shí)間,這可能導(dǎo)致UI短暫卡頓。建議開啟線程把網(wǎng)絡(luò)資源讀到內(nèi)存中使用。
<ImageBrush x:Key="imgbrush" ImageSource="https://pic.cnblogs.com/default-avatar.png"/>
上述示例中都是在XAML中聲明式的語法引用資源,本質(zhì)還是使用Uri類,因此在后臺代碼中使用Uri類就行。
// 絕對URI (默認(rèn))
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)規(guī)范中XPS(XML Paper Specification)標(biāo)準(zhǔn),有使用openxml解析Word/PPT文件經(jīng)驗(yàn)的朋友可能熟悉這個(gè)規(guī)范。OPC 規(guī)范利用RFC 2396(統(tǒng)一資源標(biāo)識符 (URI):一般語法)的擴(kuò)展性來定義pack URI方案。
URI所指定的方案(schemes)由其前綴定義;http、ftp、telnet和file 是比較常見的協(xié)議方案(schemes)。pack URI使用“pack”作為它的方案(schemes),并且包含兩個(gè)組件:授權(quán)和路徑。 pack URI的格式為:pack://authority/path。authority指定包含部件的包的類型,而path 指定部件在包內(nèi)的位置。前邊示例代碼中application:,,,就是授權(quán)(authority),/images/111.jpg或者/ResourceDll;component/images/111.jpg就是路徑(path)。這里也可以理解為嵌套在方案(schemes)為pack://的uri中的uri。由于是嵌套在內(nèi)部的uri,授權(quán)(authority)原本應(yīng)是application:///中的斜杠轉(zhuǎn)義為逗號。路徑中必須對保留字符(如“%”和“?”)進(jìn)行轉(zhuǎn)義。詳細(xì)信息可參閱開放式打包約定 (OPC)規(guī)范
標(biāo)準(zhǔn)的
URI協(xié)議方案有30種左右,由隸屬于國際互聯(lián)網(wǎng)資源管理的非營利社團(tuán) ICANN(Internet Corporation for Assigned Names and Numbers,互聯(lián)網(wǎng)名稱與數(shù)字地址分配機(jī)構(gòu))的 IANA(Internet Assigned Numbers Authority,互聯(lián)網(wǎng)號碼分配局)管理頒布。詳細(xì)協(xié)議方案參見:http://www.iana.org/assignments/uri-schemes
在WPF中,用程序(包)可以包含一個(gè)或多個(gè)文件(部件),包括:
- 當(dāng)前程序集內(nèi)的資源文件
- 引用的程序集內(nèi)的資源文件
- 內(nèi)容文件
- 源站點(diǎn)文件
為了訪問這些類型的文件,WPF 支持兩種授權(quán):application:///和siteoforigin:///。 application:/// 授權(quán)標(biāo)識在編譯時(shí)已知的應(yīng)用程序數(shù)據(jù)文件,包括資源文件和內(nèi)容文件。 siteoforigin:/// 授權(quán)標(biāo)識源站點(diǎn)文件。 下圖顯示了每種授權(quán)的范圍。
pack URI語法示例
前邊提到pack URI由授權(quán)和路徑組成,當(dāng)前程序集、引用的程序集內(nèi)的資源文件,以及內(nèi)容文件的授權(quán)都是application:///,源站點(diǎn)文件的授權(quán)是siteoforigin:///(用于XAML瀏覽器應(yīng)用程序)。
當(dāng)前程序集資源文件
當(dāng)前程序集資源文件的路徑是資源文件相對程序集項(xiàng)目文件夾根目錄的路徑。需要注意的是這里所說的相對于程序集項(xiàng)目文件夾根目錄表達(dá)的是從哪里開始作為根目錄進(jìn)行尋址,當(dāng)使用pack://這樣絕對URI表示時(shí),路徑應(yīng)該用根目錄符號/開始。下圖中111.jpg位于項(xiàng)目的根目錄,它的pack URI就是:
pack://application:,,,/111.jpg
BlindsShader.ps位于子目錄中,它的pack URI就是:
pack://application:,,,/Shader/ShaderSource/BlindsShader.ps
引用程序集資源文件
當(dāng)需要引用另一個(gè)程序集中的資源文件時(shí),路徑需要指明程序集的名稱。路徑需符合以下的格式:
pack://application:,,,AssemblyShortName{;Version}{;PublicKey};component/ResourceName
- AssemblyShortName是引用的程序集的短名稱,是必選項(xiàng)
- Version是引用的程序集的版本。此部分在加載兩個(gè)或多個(gè)具有相同短名稱的引用程序集時(shí)使用,是可選項(xiàng)。
- PublicKey是引用的程序集的簽名公鑰。此部分在加載兩個(gè)或多個(gè)具有相同短名稱的引用程序集時(shí)使用,是可選項(xiàng)。
- component指定所引用的程序集是從本地程序集引用的,此處是固定寫法
- ResourceName是資源文件的名稱,包括其相對于所引用程序集的項(xiàng)目文件夾根目錄的路徑。
內(nèi)容文件
前邊提到的資源文件都是生成操作(Build Action)為Resource的文件,是會編譯到程序集中。內(nèi)容文件是生成操作(Build Action)為內(nèi)容(Content)的文件,并不會編譯到程序集中,通常是將文件屬性中復(fù)制到輸出目錄(CopyToOutputDirectory)選為始終復(fù)制(Always)或者如果較新則復(fù)制(PreserveNewest),將文件保存到程序運(yùn)行目錄中。內(nèi)容文件主要可以解決以下問題:
- 改變資源文件時(shí),需要重新編譯應(yīng)用程序;
- 資源文件比較大,導(dǎo)致編譯的程序集也比較大;
- WPF聲音文類不支持程序集資源,無法從資源流中析取音頻文件并播放。
內(nèi)容文件本質(zhì)上也是本地磁盤文件,但生成項(xiàng)目時(shí),會將 AssemblyAssociatedContentFileAttribute 屬性編譯到每個(gè)內(nèi)容文件的程序集的元數(shù)據(jù)內(nèi),AssemblyAssociatedContentFileAttribute 的值表示內(nèi)容文件相對于其在項(xiàng)目中的位置的路徑[^2],可以采用pack URI的方式加載。內(nèi)容文件的路徑是其相對于應(yīng)用程序的主可執(zhí)行程序集的文件系統(tǒng)位置的路徑。其格式如下:
pack://application:,,,/ContentFile.wav
源站點(diǎn)文件
源站點(diǎn)文件主要針對XAML瀏覽器應(yīng)用程序(XBAP)設(shè)計(jì),編譯XAML瀏覽器應(yīng)用程序(XBAP)將資源文件分離出程序集,減少文件大小,在需要請求下周源站點(diǎn)文件時(shí),才下載它們到客戶端計(jì)算機(jī)[^2]。現(xiàn)在基本不適用該技術(shù),本文不再詳細(xì)介紹,感興趣可以查看文末參考資料。
參考
[^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
總結(jié)
以上是生活随笔為你收集整理的[WPF]浅析资源引用(pack URI)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DocTemplateTool - 可根
- 下一篇: 快排优化