WPF Resource資源
來源:程序員人生 發布時間:2015-04-20 08:34:17 閱讀次數:4149次
WPF不但支持程序級的傳統資源,同時還推出了獨具特點的對象級資源,每一個界面元素都可以攜帶自己的資源并可被自己的子級元素同享。比如后面的章節我們會講到模板、程序樣式和主題就常常放在對象資源里面。這樣1來,在WPF程序中數據就分為4個等級存儲了:數據庫里的數據相當于寄存在倉庫里面,資源文件里的數據就相當于放進了旅行箱里,WPF對象資源里面的數據相當于寄存在攜帶的背包里,變量里面的數據相當于拿在手里。
1. WPF對象資源的定義和查找
每一個WPF界面元素都有1個名為Resource的屬性,這個屬性繼承至FrameworkElement類,其類型為ResourceDictionary。ResourceDictionary能夠以鍵值對的情勢存儲資源,當要使用到某個資源的時候,使用鍵值對的情勢獲得資源對象。在保存資源時,ResourceDictionary視資源對象為Object類型,所以再使用資源時先要對資源對象進行類型轉換,XAML編譯器能夠根據Attribute自動辨認資源類型,如果類型不對就會拋出異常,但在C#中檢索到資源對象以后,類型轉換的事情就只能由我們自己來做了。ResourceDictionary可以存儲任意類型的對象。在XAML代碼中向Resource添加資源時需要把正確的命名空間引入到XAML代碼中,讓我們來看1個例子:
<Window x:Class="WpfApplication10.wnd101"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="120" Width="525">
<Window.Resources>
<ResourceDictionary>
<sys:String x:Key="_str">字符串</sys:String>
<sys:Double x:Key="_db">89.7898</sys:Double>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<!--C#中可使用FindResource查找對象資源-->
<TextBlock x:Name="_txtBlock" FontSize="16" Text="{StaticResource ResourceKey=_str}" Height="28"/>
</StackPanel>
</Window>
首先我們將System命名空間引入XAML代碼中并映照為sys名稱空間,然后在Windows.Resource里面添加了兩個資源條目,1個是string類型,1個是double類型。最后我們用textBlock來消費這個資源。程序運行效果以下圖:

查找資源時,先查找控件自己的Resource屬性,如果沒有這個資源程序會沿著邏輯樹向上1級進行查找,如果連最頂端容器都沒有這個資源,程序就會查找Application.Resource(也就是程序的頂級資源)。如果還沒有找到,那末就只能拋出異常了。
這就好比每一個界面元素都有自己的1個背包,里面可能裝有各種各樣的資源,使用的時候打開找1找,如果沒有找到還可以去翻看上1層控件的背包,直至找到這個資源或報告沒有這個資源為止。
你可能會想,如果把資源像CSS或JS1樣放在獨立的文件夾里,使用時成套援用、重用時便于分發豈不更好?WPF的資源固然可以做到這1點;ResourceDictionary具有1個名為Source的屬性,只要把包括資源定義的文件路徑賦值給這個屬性就1切弄定了!例如把皮膚以資源的情勢放在XAML文件中,使用時僅需要將相應的XAML文件添加進項目并使用Source屬性進行援用,你的程序就立刻變的鮮明照人。
<Window.Resources>
<!--用于1鍵換膚-->
<ResourceDictionary Source="ShinyRed.xaml"></ResourceDictionary>
</Window.Resources>
2. 且“動”且“靜”用資源
當資源被存儲進資源詞典以后,我們可使用兩種方式來使用這些資源-----靜態方式和動態方式。靜態資源使用StackResource指的是程序載入內存時對資源的1次性使用,以后就不在去訪問這個資源了;動態資源(DynamicResource)使用指的是在程序運行進程中依然會去訪問資源。明顯如果你肯定某些資源在程序初始化的時候只使用1次、以后不會再改變,就應當使用StaticResource,而程序運行進程中還有可能改變資源應當以DynamicResource情勢使用。拿程序的主題來舉例,如果程序的皮膚在運行進程中始終不變,以Static情勢來使用資源就能夠了。如果在程序運行進程中允許用戶更改皮膚或配色方案則必須使用DynamicResource來使用資源。
請看下面這個例子,我在Windows資源字典里放置了兩個TextBlock類型資源,并分別以StaticResource和DynamicResource方式使用之:
<Window x:Class="WpfApplication10.wnd102"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="wnd102" Height="120" Width="300">
<Window.Resources>
<ResourceDictionary>
<TextBlock x:Key="_txt1" Text="海上生明月"></TextBlock>
<TextBlock x:Key="_txt2" Text="海上生明月"></TextBlock>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button x:Name="_btn1" Content="{StaticResource _txt1}" Height="28" ></Button>
<!--動態資源運行時,才能更新-->
<Button x:Name="_btn2" Content="{DynamicResource _txt2}" Height="28" ></Button>
<Button x:Name="_btn3" Content="Update" Height="28" Click="_btn3_Click" ></Button>
</StackPanel>
</Window>
按鈕負責在程序運行進程中對資源詞典里面的兩個資源進行改變:
private void _btn3_Click(object sender, RoutedEventArgs e)
{
this.Resources["_txt1"] = new TextBlock { Text = "更新成功" };
this.Resources["_txt2"] = new TextBlock { Text = "更新成功" };
}
3. 向程序集中添加2進制資源
常見的利用程序資源有圖標、圖片、文本、音頻、視頻等,各種編程語言的編譯器或資源編譯器都有能力把這些文件編譯進目標文件(終究的.exe文件或.dll文件)。資源文件在目標文件里以2進制數據情勢存在、構成目標文件的資源段(Resource Section),使用時數據會被提取出來。
為了不把資源詞典里的資源和利用程序里面內嵌的資源弄混,我們明確稱呼資源詞典里面的資源為“WPF資源”或“對象資源”,稱呼利用程序內嵌資源為“程序集資源”或“2進制資源”。特別提示1點,WPF中寫在<Application.Resource>...</Application.Resource>標簽內的資源依然是WPF資源而非2進制資源。
下面讓我們看看如何向WPF程序中添加2進制資源并使用它們。

Resources.resx文件內容的組織情勢也是“鍵-值”對,編譯后,Resources.resx會構成Properties名稱空間中的Resource類,使用這個類的方法或屬性就可以獲得資源。為了讓XAML編譯器能夠訪問這個類,1定要把Resources.resx的訪問級別由Internal改成public。利用資源文件編輯器,可以資源文件的字符串里添加兩個條目,然后分別在XAML代碼和C#代碼中訪問他們。
在XAML代碼中使用Resources.resx中的資源,需要把程序的Properties名稱映照為XAML名稱空間,然后使用x:Static標簽擴大來訪問資源。
<Window x:Class="WpfApplication10.wnd103"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prop="clr-namespace:WpfApplication10.Properties"
FontSize="16"
Title="wnd103" Height="130" Width="340">
<StackPanel>
<!--C#中可使用Properties.Resources.訪問-->
<TextBlock x:Name="_txtBlock1" Text="{x:Static prop:Resources.password}"></TextBlock>
<TextBlock x:Name="_txtBlock2" Text="{x:Static prop:Resources.userName}"></TextBlock>
</StackPanel>
</Window>
有1點特別提示大家,如果想讓外部文件編譯進2進制資源,必須在屬性窗口把文件的Build Action屬性值設為Resource。其實不是每種文件都會自動設置為Resource,比如圖片文件會,MP3文件就不會,1般情況下,如果Build Action的值設為Resource,則Copy to Output Directory屬性設置為Do Not Copy;如果不希望以資源的情勢使用外部文件,可以把Build
Action屬性設置為None,而把Copy to Output Directory設置為Copy Always。另外,Build Action屬性的下拉列表里面有1個頗具迷惑性的值Embeded Resource,不要選擇這個值。
4. 使用PACK URI路徑訪問2進制資源
WPF對2進制資源的訪問有自己的1套方法,稱為PACK URI路徑。有時候死記硬背能夠讓讀者快速學習又能幫助作者偷點懶。比如,WPF的PACK URI路徑,你只需要記住這個格式就能夠了:
pack://application,,,[/程序集名稱;][可選版本號;][文件夾名稱/][文件名稱]
而實際上pack://applicationi,,,可以省略、程序集名稱和版本號常使用省略值,所以剩下的就只有這個了:
[文件夾名稱/][文件名稱]
我們看看例子:

<Window x:Class="WpfApplication10.wnd104"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="wnd104" Height="200" Width="300">
<Grid>
<Image x:Name="_image" Source="Resources/Images/Aodi.jpg" Stretch="Fill"></Image>
</Grid>
</Window>
也可以使用C#訪問:
_image.Source = new BitmapImage(new Uri(@"Resources/Images/Aodi.jpg", UriKind.Relative));
參考:《深入淺出WPF》
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈