c# wpf如何更好的使用Application程序集資源
這一篇單獨拿出來分析這個程序集資源,為的就是不想讓大家把程序集資源和exe程序強關(guān)聯(lián),因為程序集資源實際上是二進制資源,后續(xù)編譯過程中會被嵌入到程序集中,而為了更方便的使用資源,我們要好好梳理一下程序集資源相關(guān)的知識。(例如多語言資源,多工程、多項目使用的公共資源文件)。
1)在程序集中添加資源
我們通過向項目添加文件并嘗試修改資源文件屬性看有什么不同的結(jié)果。
在工程上右鍵=》添加=》新建文件夾=》改名為Images=》回車=》在Images文件夾上右鍵=》添加=》現(xiàn)有項=》右下角文件類別選擇所有文件=》找到你想導入的圖片=》點擊添加,結(jié)果如下圖.

這樣就添加好了一個文件,我們在添加的圖片上右鍵屬性看到生成操作為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>
我們在工程上點擊編譯,生成成功后我們?nèi)タ淳幾g結(jié)果,發(fā)現(xiàn)文件夾下沒有這個image,我們使用反編譯ILSpy工具查看生成的這個exe,我們看到Png文件作為資源被放在了resources里,(這里有一個小插曲,不知道為什么,我的PNG圖片在最開始反編譯的時候沒有。直到我添加了上面Image的代碼反編譯才出來。以后會分析這個問題。這里記錄一下)

而修改圖片的屬性為Content并修改復制到輸出目錄為始終復制。重新編譯工程。

我們看到了Debug文件夾下多了一個Images文件夾,里面包含了我們的圖片。而反編譯程序集集中就沒有這個資源文件了,它從資源里更換到目錄下了。這樣的話,程序集因為沒有包含了資源文件大小就發(fā)生了變化。

通過修改資源的屬性,資源在編譯過程中會放置在不同的地方,這是其中2種比較常用的設置屬性。通過這種設置程序集資源的方式易于更新,只需要在桌面資源管理器種替換掉文件并重新編譯程序就能完成資源文件的替換,非常方便。資源文件可以放在主工程文件下,也可以選擇放在單獨的DLL下,具體看你的設計需要啦。因為接下來我們會詳細講如何讀取這些資源。即使跨了DLL。
2)在程序集中查找資源
因為是在講Application的資源所以我們先看Application下對資源的查找方法,在App.xaml的Application上按下F12:
我們看到了返回StreamResourceInfo類型的方法又3個。GetContentStream()、GetRemoteStream()、GetResourceStream()。這里只講GetResourceStream()其他的可以自己在對應的方法上按F1查看文檔。(記得把資源屬性設置成Resouce)
我們使用這種在程序集管理所有資源的方式,我們可以自己實現(xiàn)很多種自己管理資源的想法。可以把代碼添加到自己的工程里調(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,還記得我們反編譯時候看到的資源嗎?從Assembly取我們要的資源。
Assembly assembly = Assembly.GetAssembly(this.GetType());
string resourceName = assembly.GetName().Name + ".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下傳入相對和絕對路徑來演示:
<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));
}
在這個基礎上WPF支持pack URI。pack URI語法可以尋址包含在編譯過的程序中的資源,(從名字上理解package URI?)使用pack URI可以讓我們更加規(guī)范的使用資源文件,也更加方便。
如下這2段代碼是等效的因為沒有跨程序集。
<Image Source="Images/takenotes.png" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/> <Image Source="pack://application:,,,/Images/takenotes.png" Width="220" VerticalAlignment="Top" HorizontalAlignment="Left"/>
我新建了一個程序集,放置在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)
{
//絕對路徑
imgAbsolutePath.Source = new BitmapImage(new Uri(@"d:\Image\takenotes.png", UriKind.Absolute));
//相對路徑
imgRelativePath.Source = new BitmapImage(new Uri("Images/takenotes.png",UriKind.Relative));
//當前程序集pack URI 語法
imgRelativePath.Source = new BitmapImage(new Uri("pack://application:,,,/Images/takenotes.png"));
//跨程序集使用資源 pack URI 語法
imgCrossAssemblyPath.Source = new BitmapImage(new Uri("pack://application:,,,/ImageLibrary;component/Images/takenotes.png"));
}
這樣就可以把資源單獨存放在一個DLL里。然后剩下的就看自己怎么使用拉。
我們主工程下一般會保持當前App.xaml的當前資源結(jié)構(gòu)。我們把資源都放在 Application.Current.Resources.MergedDictionaries內(nèi)。通過MergedDictionaries更好的動態(tài)替換同類型的資源(比如多語言的一種實現(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)語言對應的語言包
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri($"pack://application:,,,/ApplicationResources;component/Lang/{rcName}.xaml", UriKind.RelativeOrAbsolute)
});
這樣的話,就能輔助我們更好的使用資源拉,是不是發(fā)現(xiàn)寫代碼如果保持正確的解耦,寫代碼會就越來越簡單?
以上就是c# wpf如何更好的使用Application程序集資源的詳細內(nèi)容,更多關(guān)于wpf使用Application程序集資源的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#處理類型和二進制數(shù)據(jù)轉(zhuǎn)換并提高程序性能
這篇文章介紹了C#處理類型和二進制數(shù)據(jù)轉(zhuǎn)換并提高程序性能的方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04
在winform下實現(xiàn)左右布局多窗口界面的方法之續(xù)篇
這篇文章主要介紹了在winform下實現(xiàn)左右布局多窗口界面的方法之續(xù)篇 的相關(guān)資料,需要的朋友可以參考下2016-02-02
c#?使用線程對串口serialPort進行收發(fā)數(shù)據(jù)(四種)
本文主要介紹了c#?使用線程對串口serialPort進行收發(fā)數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07
基于C#實現(xiàn)12306的動態(tài)驗證碼變成靜態(tài)驗證碼的方法
這篇文章主要介紹了基于C#實現(xiàn)12306的動態(tài)驗證碼變成靜態(tài)驗證碼的方法的相關(guān)資料,需要的朋友可以參考下2015-12-12
C#在Entity Framework中實現(xiàn)事務回滾
這篇文章介紹了C#在Entity Framework中實現(xiàn)事務回滾的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08
C#使用checkedListBox1控件鏈接數(shù)據(jù)庫的方法示例
這篇文章主要介紹了C#使用checkedListBox1控件鏈接數(shù)據(jù)庫的方法,結(jié)合具體實例形式分析了數(shù)據(jù)庫的創(chuàng)建及checkedListBox1控件連接數(shù)據(jù)庫的相關(guān)操作技巧,需要的朋友可以參考下2017-06-06

