c# wpf如何更好的使用Application程序集資源
這一篇單獨(dú)拿出來(lái)分析這個(gè)程序集資源,為的就是不想讓大家把程序集資源和exe程序強(qiáng)關(guān)聯(lián),因?yàn)槌绦蚣Y源實(shí)際上是二進(jìn)制資源,后續(xù)編譯過(guò)程中會(huì)被嵌入到程序集中,而為了更方便的使用資源,我們要好好梳理一下程序集資源相關(guān)的知識(shí)。(例如多語(yǔ)言資源,多工程、多項(xiàng)目使用的公共資源文件)。
1)在程序集中添加資源
我們通過(guò)向項(xiàng)目添加文件并嘗試修改資源文件屬性看有什么不同的結(jié)果。
在工程上右鍵=》添加=》新建文件夾=》改名為Images=》回車=》在Images文件夾上右鍵=》添加=》現(xiàn)有項(xiàng)=》右下角文件類別選擇所有文件=》找到你想導(dǎo)入的圖片=》點(diǎn)擊添加,結(jié)果如下圖.
這樣就添加好了一個(gè)文件,我們?cè)谔砑拥膱D片上右鍵屬性看到生成操作為Resource,我們添加代碼如下:
<Window x:Class="ApplicationResources.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ApplicationResources" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Image Source="/Images/takenotes.png" Width="230" Height="130"/> </Grid> </Window>
我們?cè)诠こ躺宵c(diǎn)擊編譯,生成成功后我們?nèi)タ淳幾g結(jié)果,發(fā)現(xiàn)文件夾下沒有這個(gè)image,我們使用反編譯ILSpy工具查看生成的這個(gè)exe,我們看到Png文件作為資源被放在了resources里,(這里有一個(gè)小插曲,不知道為什么,我的PNG圖片在最開始反編譯的時(shí)候沒有。直到我添加了上面Image的代碼反編譯才出來(lái)。以后會(huì)分析這個(gè)問題。這里記錄一下)
而修改圖片的屬性為Content并修改復(fù)制到輸出目錄為始終復(fù)制。重新編譯工程。
我們看到了Debug文件夾下多了一個(gè)Images文件夾,里面包含了我們的圖片。而反編譯程序集集中就沒有這個(gè)資源文件了,它從資源里更換到目錄下了。這樣的話,程序集因?yàn)闆]有包含了資源文件大小就發(fā)生了變化。
通過(guò)修改資源的屬性,資源在編譯過(guò)程中會(huì)放置在不同的地方,這是其中2種比較常用的設(shè)置屬性。通過(guò)這種設(shè)置程序集資源的方式易于更新,只需要在桌面資源管理器種替換掉文件并重新編譯程序就能完成資源文件的替換,非常方便。資源文件可以放在主工程文件下,也可以選擇放在單獨(dú)的DLL下,具體看你的設(shè)計(jì)需要啦。因?yàn)榻酉聛?lái)我們會(huì)詳細(xì)講如何讀取這些資源。即使跨了DLL。
2)在程序集中查找資源
因?yàn)槭窃谥vApplication的資源所以我們先看Application下對(duì)資源的查找方法,在App.xaml的Application上按下F12:
我們看到了返回StreamResourceInfo類型的方法又3個(gè)。GetContentStream()、GetRemoteStream()、GetResourceStream()。這里只講GetResourceStream()其他的可以自己在對(duì)應(yīng)的方法上按F1查看文檔。(記得把資源屬性設(shè)置成Resouce)
我們使用這種在程序集管理所有資源的方式,我們可以自己實(shí)現(xiàn)很多種自己管理資源的想法??梢园汛a添加到自己的工程里調(diào)試一下看看自己感興趣的內(nèi)容,代碼如下:
using System; using System.Collections; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Resources; using System.Windows; using System.Windows.Resources; namespace ApplicationResources { /// <summary> /// MainWindow.xaml 的交互邏輯 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); //方法1使用StreamResourceInfo接收GetResourceStream()讀取到的內(nèi)容。 StreamResourceInfo sri = Application.GetResourceStream(new Uri("Images/takenotes.png", UriKind.Relative)); string type = sri.ContentType; var stream = sri.Stream; //方法2,還記得我們反編譯時(shí)候看到的資源嗎?從Assembly取我們要的資源。 Assembly assembly = Assembly.GetAssembly(this.GetType()); string resourceName = assembly.GetName().Name + ".g"; //單個(gè)資源 ResourceManager rm = new ResourceManager(resourceName, assembly); using (ResourceSet set = rm.GetResourceSet(CultureInfo.CurrentCulture, true, true)) { UnmanagedMemoryStream s = (UnmanagedMemoryStream)set.GetObject("Images/takenotes.png", true); } //遍歷所有資源 ResourceManager rmResources = new ResourceManager(resourceName, assembly); using (ResourceSet set = rmResources.GetResourceSet(CultureInfo.CurrentCulture, true, true)) { foreach (DictionaryEntry item in set) { Debug.WriteLine($"ResourceSet DictionaryEntry as {item.Key.ToString()}"); } } } } }
WPF目前給我們封裝了一些訪問資源的方法,我們使用XAML和CS下傳入相對(duì)和絕對(duì)路徑來(lái)演示:
<Window x:Class="ApplicationResources.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ApplicationResources" mc:Ignorable="d" Loaded="Window_Loaded" Title="MainWindow" Height="450" Width="800"> <Grid> <StackPanel> <Image Source="Images/takenotes.png" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/> <Image Source="d:\Image\takenotes.png" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/> <Image x:Name="imgAbsolutePath" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/> <Image x:Name="imgRelativePath" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/> </StackPanel> </Grid> </Window>
private void Window_Loaded(object sender, RoutedEventArgs e) { imgAbsolutePath.Source = new BitmapImage(new Uri(@"d:\Image\takenotes.png", UriKind.Absolute)); imgRelativePath.Source = new BitmapImage(new Uri("Images/takenotes.png",UriKind.Relative)); }
在這個(gè)基礎(chǔ)上WPF支持pack URI。pack URI語(yǔ)法可以尋址包含在編譯過(guò)的程序中的資源,(從名字上理解package URI?)使用pack URI可以讓我們更加規(guī)范的使用資源文件,也更加方便。
如下這2段代碼是等效的因?yàn)闆]有跨程序集。
<Image Source="Images/takenotes.png" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/> <Image Source="pack://application:,,,/Images/takenotes.png" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/>
我新建了一個(gè)程序集,放置在ImageLibrary程序集下同樣目錄的資源。
Xaml寫法:
<Image Source="Images/takenotes.png" Width="120" VerticalAlignment="Top" HorizontalAlignment="Left"/> <Image Source="pack://application:,,,/Images/takenotes.png" Width="120" VerticalAlignment="Top" HorizontalAlignment="Left"/> <Image Source="pack://application:,,,/ImageLibrary;component/Images/takenotes.png" Width="120" VerticalAlignment="Top" HorizontalAlignment="Left"/>
CS寫法:
private void Window_Loaded(object sender, RoutedEventArgs e) { //絕對(duì)路徑 imgAbsolutePath.Source = new BitmapImage(new Uri(@"d:\Image\takenotes.png", UriKind.Absolute)); //相對(duì)路徑 imgRelativePath.Source = new BitmapImage(new Uri("Images/takenotes.png",UriKind.Relative)); //當(dāng)前程序集pack URI 語(yǔ)法 imgRelativePath.Source = new BitmapImage(new Uri("pack://application:,,,/Images/takenotes.png")); //跨程序集使用資源 pack URI 語(yǔ)法 imgCrossAssemblyPath.Source = new BitmapImage(new Uri("pack://application:,,,/ImageLibrary;component/Images/takenotes.png")); }
這樣就可以把資源單獨(dú)存放在一個(gè)DLL里。然后剩下的就看自己怎么使用拉。
我們主工程下一般會(huì)保持當(dāng)前App.xaml的當(dāng)前資源結(jié)構(gòu)。我們把資源都放在 Application.Current.Resources.MergedDictionaries內(nèi)。通過(guò)MergedDictionaries更好的動(dòng)態(tài)替換同類型的資源(比如多語(yǔ)言的一種實(shí)現(xiàn)方式)。
var targetResource = Application.Current.Resources.MergedDictionaries.FirstOrDefault(x => x.Source != null && x.Source.OriginalString.Contains(uri)); if (targetResource != null) { Application.Current.Resources.MergedDictionaries.Remove(targetResource); } //添加與系統(tǒng)語(yǔ)言對(duì)應(yīng)的語(yǔ)言包 Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri($"pack://application:,,,/ApplicationResources;component/Lang/{rcName}.xaml", UriKind.RelativeOrAbsolute) });
這樣的話,就能輔助我們更好的使用資源拉,是不是發(fā)現(xiàn)寫代碼如果保持正確的解耦,寫代碼會(huì)就越來(lái)越簡(jiǎn)單?
以上就是c# wpf如何更好的使用Application程序集資源的詳細(xì)內(nèi)容,更多關(guān)于wpf使用Application程序集資源的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#處理類型和二進(jìn)制數(shù)據(jù)轉(zhuǎn)換并提高程序性能
這篇文章介紹了C#處理類型和二進(jìn)制數(shù)據(jù)轉(zhuǎn)換并提高程序性能的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04在winform下實(shí)現(xiàn)左右布局多窗口界面的方法之續(xù)篇
這篇文章主要介紹了在winform下實(shí)現(xiàn)左右布局多窗口界面的方法之續(xù)篇 的相關(guān)資料,需要的朋友可以參考下2016-02-02C#?實(shí)現(xiàn)Ping遠(yuǎn)程主機(jī)功能及代碼演示
這篇文章主要介紹了C#?實(shí)現(xiàn)Ping遠(yuǎn)程主機(jī)功能,本教程將演示1.0.2版本更新功能,以及實(shí)現(xiàn)的具體代碼演示,需要的朋友可以參考下2024-05-05c#?使用線程對(duì)串口serialPort進(jìn)行收發(fā)數(shù)據(jù)(四種)
本文主要介紹了c#?使用線程對(duì)串口serialPort進(jìn)行收發(fā)數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07基于C#實(shí)現(xiàn)12306的動(dòng)態(tài)驗(yàn)證碼變成靜態(tài)驗(yàn)證碼的方法
這篇文章主要介紹了基于C#實(shí)現(xiàn)12306的動(dòng)態(tài)驗(yàn)證碼變成靜態(tài)驗(yàn)證碼的方法的相關(guān)資料,需要的朋友可以參考下2015-12-12C#在Entity Framework中實(shí)現(xiàn)事務(wù)回滾
這篇文章介紹了C#在Entity Framework中實(shí)現(xiàn)事務(wù)回滾的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08C#使用checkedListBox1控件鏈接數(shù)據(jù)庫(kù)的方法示例
這篇文章主要介紹了C#使用checkedListBox1控件鏈接數(shù)據(jù)庫(kù)的方法,結(jié)合具體實(shí)例形式分析了數(shù)據(jù)庫(kù)的創(chuàng)建及checkedListBox1控件連接數(shù)據(jù)庫(kù)的相關(guān)操作技巧,需要的朋友可以參考下2017-06-06