WPF Resource資源
來(lái)源:程序員人生 發(fā)布時(shí)間:2015-04-20 08:34:17 閱讀次數(shù):4144次
WPF不但支持程序級(jí)的傳統(tǒng)資源,同時(shí)還推出了獨(dú)具特點(diǎn)的對(duì)象級(jí)資源,每一個(gè)界面元素都可以攜帶自己的資源并可被自己的子級(jí)元素同享。比如后面的章節(jié)我們會(huì)講到模板、程序樣式和主題就常常放在對(duì)象資源里面。這樣1來(lái),在WPF程序中數(shù)據(jù)就分為4個(gè)等級(jí)存儲(chǔ)了:數(shù)據(jù)庫(kù)里的數(shù)據(jù)相當(dāng)于寄存在倉(cāng)庫(kù)里面,資源文件里的數(shù)據(jù)就相當(dāng)于放進(jìn)了旅行箱里,WPF對(duì)象資源里面的數(shù)據(jù)相當(dāng)于寄存在攜帶的背包里,變量里面的數(shù)據(jù)相當(dāng)于拿在手里。
1. WPF對(duì)象資源的定義和查找
每一個(gè)WPF界面元素都有1個(gè)名為Resource的屬性,這個(gè)屬性繼承至FrameworkElement類,其類型為ResourceDictionary。ResourceDictionary能夠以鍵值對(duì)的情勢(shì)存儲(chǔ)資源,當(dāng)要使用到某個(gè)資源的時(shí)候,使用鍵值對(duì)的情勢(shì)獲得資源對(duì)象。在保存資源時(shí),ResourceDictionary視資源對(duì)象為Object類型,所以再使用資源時(shí)先要對(duì)資源對(duì)象進(jìn)行類型轉(zhuǎn)換,XAML編譯器能夠根據(jù)Attribute自動(dòng)辨認(rèn)資源類型,如果類型不對(duì)就會(huì)拋出異常,但在C#中檢索到資源對(duì)象以后,類型轉(zhuǎn)換的事情就只能由我們自己來(lái)做了。ResourceDictionary可以存儲(chǔ)任意類型的對(duì)象。在XAML代碼中向Resource添加資源時(shí)需要把正確的命名空間引入到XAML代碼中,讓我們來(lái)看1個(gè)例子:
<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查找對(duì)象資源-->
<TextBlock x:Name="_txtBlock" FontSize="16" Text="{StaticResource ResourceKey=_str}" Height="28"/>
</StackPanel>
</Window>
首先我們將System命名空間引入XAML代碼中并映照為sys名稱空間,然后在Windows.Resource里面添加了兩個(gè)資源條目,1個(gè)是string類型,1個(gè)是double類型。最后我們用textBlock來(lái)消費(fèi)這個(gè)資源。程序運(yùn)行效果以下圖:

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

Resources.resx文件內(nèi)容的組織情勢(shì)也是“鍵-值”對(duì),編譯后,Resources.resx會(huì)構(gòu)成Properties名稱空間中的Resource類,使用這個(gè)類的方法或?qū)傩跃涂梢垣@得資源。為了讓XAML編譯器能夠訪問(wèn)這個(gè)類,1定要把Resources.resx的訪問(wèn)級(jí)別由Internal改成public。利用資源文件編輯器,可以資源文件的字符串里添加兩個(gè)條目,然后分別在XAML代碼和C#代碼中訪問(wèn)他們。
在XAML代碼中使用Resources.resx中的資源,需要把程序的Properties名稱映照為XAML名稱空間,然后使用x:Static標(biāo)簽擴(kuò)大來(lái)訪問(wèn)資源。
<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.訪問(wèn)-->
<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點(diǎn)特別提示大家,如果想讓外部文件編譯進(jìn)2進(jìn)制資源,必須在屬性窗口把文件的Build Action屬性值設(shè)為Resource。其實(shí)不是每種文件都會(huì)自動(dòng)設(shè)置為Resource,比如圖片文件會(huì),MP3文件就不會(huì),1般情況下,如果Build Action的值設(shè)為Resource,則Copy to Output Directory屬性設(shè)置為Do Not Copy;如果不希望以資源的情勢(shì)使用外部文件,可以把Build
Action屬性設(shè)置為None,而把Copy to Output Directory設(shè)置為Copy Always。另外,Build Action屬性的下拉列表里面有1個(gè)頗具迷惑性的值Embeded Resource,不要選擇這個(gè)值。
4. 使用PACK URI路徑訪問(wèn)2進(jìn)制資源
WPF對(duì)2進(jìn)制資源的訪問(wèn)有自己的1套方法,稱為PACK URI路徑。有時(shí)候死記硬背能夠讓讀者快速學(xué)習(xí)又能幫助作者偷點(diǎn)懶。比如,WPF的PACK URI路徑,你只需要記住這個(gè)格式就能夠了:
pack://application,,,[/程序集名稱;][可選版本號(hào);][文件夾名稱/][文件名稱]
而實(shí)際上pack://applicationi,,,可以省略、程序集名稱和版本號(hào)常使用省略值,所以剩下的就只有這個(gè)了:
[文件夾名稱/][文件名稱]
我們看看例子:

<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#訪問(wèn):
_image.Source = new BitmapImage(new Uri(@"Resources/Images/Aodi.jpg", UriKind.Relative));
參考:《深入淺出WPF》
生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)