一、創建Application Bar
Application Bar和WinForm界面中菜單欄、狀態欄等界面組成部分一樣,是移動運用界面的一個組成部分,只是默認情況下是空的不可見的,開發人員可以根據需要創建Application Bar的實例並添加功能按鈕。
為運用添加Application Bar有兩種方式,Xmal方式和后台代碼的方式。
Xmal方式很簡單,創建一個Windows Phone項目后,打開MainPage.xaml文件,能夠發現默認就有<phone:PhoneApplicationPage.ApplicationBar>這一段Xaml,只是被注釋掉了,我們只需要去掉注釋即可。
如果通過代碼的方式來添加方法如下,查看MainPage的基類PhoneApplicationPage,
發現ApplicationBar實際上是界面的一個組成部分,只是在我們不定義的情況下為Null而已。
進一步查看IApplicationBar的基類,發現ApplicationBar實際上由兩部分組成:Buttons和MenuItems。
所以我們只需要給ApplicationBar屬性賦值即可。代碼如下:

ApplicationBar = new ApplicationBar(); ApplicationBar.Buttons.Add(new ApplicationBarIconButton(new Uri("/Images/appbar.feature.email.rest.png", UriKind.Relative)) { Text = "按鈕1" }); ApplicationBar.MenuItems.Add(new ApplicationBarMenuItem("目錄項1"));
需要注意的地方
雖然添加Application Bar的方式很簡單,但是還是有幾個地方是我們容易忽略的。
- Buttons的個數是有限制的,最多為4個,多於4個會編譯出錯。當Buttons不夠用時,可以用MenuItems來擴展,而MenuItems的個數是沒有限制,當大於5個時,會出現滾動條。
- 圖片添加到項目后必須將Build Action設置成Content並且將Copy to Output Directory設置成Copy if newer或者Copy always,否則圖片顯示不了
- 安裝完Windows Phone SDK,系統默認提供了一組最優化的圖標供開發人員使用,在類似如下位置:C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons
- 如果需要自定義圖標,為了達到好的效果,需要滿足一定的條件,具體可查詢MSDN, http://msdn.microsoft.com/en-us/library/ff431806(v=VS.92).aspx
二、本地化和多語言
和.net進行桌面等開發一樣,可以利用資源文件實現本地化的需求。
我們先來實現界面中TextBlock文本的本地化,通用的步驟如下:
1. 項目中添加一個默認的資源文件,取名AppResource.resx,這個文件的名稱是可以自己定義的,接着添加3個字符串資源,注意必須將訪問修飾符設置成public,否則界面綁定的時候編譯會出現異常,如下圖:
為了體現本地化的效果,我們再添加一個資源文件,取名AppResource.en-US.resx,注意這里的文件名形式,AppResource與默認資源文件名稱一樣,en-US代表English (United States),如下圖:
Windows Phone支持的語言表和語言的代碼表可以參考如下資料:
http://msdn.microsoft.com/en-us/library/hh202918(v=vs.92).aspx
2. 創建資源文件的包裝類LocalizedStrings.cs,供界面元素綁定(后面介紹為什么要包裝類以及怎么樣去掉這個包裝類),代碼如下:

public class LocalizedStrings { private static WPDemo.AppResource localizedresources = new WPDemo.AppResource(); public WPDemo.AppResource Localizedresources { get { return localizedresources; } } }
也有類似如下版本的:

public class LocalizedStrings { public string ContentText { get { return AppResource.ContentText; } } public string ButtonText { get { return AppResource.ButtonText; } } public string MenuItemText { get { return AppResource.MenuItemText; } } }
第二種方式相當於將具體的資源包裝成具體的屬性,使用起來更直接,但是資源太多了寫起來比較繁瑣,也有點多此一舉,我推薦第一種方式。
3. 為了界面中能綁定,需要將LocalizedStrings類作為資源加載進來,因為資源多個界面都會使用,所以作為全局資源比較合適,因此打開App.xaml文件,添加如下代碼:

<Application.Resources> <local:LocalizedStrings xmlns:local="clr-namespace:WPDemo" x:Key="LocalizedStrings" /> </Application.Resources>
4. 用文本工具如記事本打開項目文件WPDemo.csproj,在<SupportedCultures>元素中添加要支持的語言,在本實例中,默認的資源文件AppResource.resx實際為中文版資源,在<SupportedCultures>元素中只需要加入en-US;即可,代碼如下:
<SupportedCultures>en-US;</SupportedCultures>
這么設置后實際上准確的說,系統應該支持英語和非英語,聽着大家覺得廢話,我的意思是想說,當我們將我們的設備設置成英語時, AppResource.en-US.resx文件的資源會起作用,當設置成其他一切語言時默認資源文件AppResource.resx會起作用。設置界面如下:
如果在項目文件的<SupportedCultures>節點中,不配置任何內容語言,那么即使在如上界面中配置成English(United States),界面仍然顯示成中文而不會自動讀取AppResource.en-US.resx文件的資源,因為沒配置的情況下說明,說明系統不支持英文,系統只會從默認的資源文件AppResource.resx中讀取資源。我覺得微軟在這個地方也許可以改進一下,記事本打開項目文件再配置的過程是不是可以免了,因為假如用戶語言選的是English(United States),完全可以自動查找有沒有AppResource.en-US.resx這個資源文件,有的話當然就讀這個文件,沒有就讀AppResource.resx完事!大家覺得呢?當然設計者這樣做也可能是基於其他方面的考慮!
5. 最后就是界面中使用綁定的方式加載資源文件中的字符串了,打開默認主界面文件MainPage.xaml,在名為ContentPanel的Grid元素中添加一個TextBlock元素后代碼如下:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock x:Name="txtRes" Text="{Binding Path=Localizedresources.ContentText, Source={StaticResource LocalizedStrings}}"></TextBlock> </Grid>
注意,如果包裝類LocalizedStrings采用的是第二種寫法,代碼就應該是如下形式:
Text="{Binding Path=ContentText, Source={StaticResource LocalizedStrings}}"
好了,如上步驟就是本地化的通用方式,下面運行程序,測試一下,發現已經達到了我們的預期!
上面提到包裝類LocalizedStrings,大家可能會疑惑,這玩意兒有什么用,有點多此一舉的感覺,其實我也這么認為,但去網上一搜,發現基本上本地化的示例全都一成不變的這么搞的!
為什么?
實際操作一下吧,先把LocalizedStrings.cs文件從項目中排除,然后打開App.xaml文件,去掉包裝類的引用,加上如下語句:
<local:AppResource xmlns:local="clr-namespace:WPDemo" x:Key="LocalizedStrings" />
目的很明確,不通過包裝類直接引用資源文件類AppResource,與之對應,界面的元素就應該改成如下:
<TextBlock x:Name="txtRes" Text="{Binding Path=ContentText, Source={StaticResource LocalizedStrings}}"></TextBlock>
如果采用的是包裝類的第二種寫法,這里就不用管了,因為ContentText在包裝類中和類AppResource中一樣,直接是成員屬性。具體可以打開AppResource.Designer.cs文件查看。
到現在,感覺差不多了,編譯,OK,沒有任何錯誤。F5運行程序,卻拋出了異常:
No matching constructor found on type 'WPDemo.AppResource'
提示資源類型中沒有匹配的構造函數,我們打開AppResource.Designer.cs,發現有如下默認構造函數

[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal AppResource() { }
你應該已經發現了,原因就在於構造函數默認的訪問修飾符是internal,資源文件和程序文件編譯后不在同一個程序集,將internal該成public后重新運行,發現和有包裝類時效果一樣了。
三、Application Bar的本地化和多語言
有人肯定會納悶為什么要把Application Bar單獨拿出來,其實原因很簡單,它和界面中其他內容元素的本地化有些不一樣。查看Msdn,明確說明Application Bar不是silverlight控件,其屬性不能像TextBlock等其他控件一樣進行數據綁定,要實現是本地化,只能是編碼的方式了。
先在界面中添加如下代碼

<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton IconUri="/Images/appbar.feature.email.rest.png" Text="btn1"/> <shell:ApplicationBarIconButton IconUri="/Images/appbar.refresh.rest.png" Text="btn2"/> <shell:ApplicationBar.MenuItems> <shell:ApplicationBarMenuItem Text="mi1"/> <shell:ApplicationBarMenuItem Text="mi2"/> </shell:ApplicationBar.MenuItems> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>
按鈕和目錄的Text屬性如果寫成如下形式編譯將無法通過:
Text=Localizedresources.ContentText, Source={StaticResource LocalizedStrings}}"
看來只能在代碼中通過屬性來本地化了,我們拿第一個按鈕來測試一下我們的想法,按常規思維,我們給按鈕加上x:Name屬性,如下:
<shell:ApplicationBarIconButton Text="btn1" IconUri="/Images/appbar.feature.email.rest.png" Text="btn1"/>
在MainPage()函數中添加如下代碼:
btn1.Text = AppResource.ButtonText;
編譯沒有問題,運行后發現拋出NullReferenceException異常,為什么?Google一下,能看的資源有限(就Google能搜點有用的東西,關鍵時候總被和諧,上火!),大概意思就是說ApplicationBar不是派生自FrameworkElement,因而不是頁面visual tree的一部分,代碼中無法通過x:Name來引用。真不知道是不是Bug?反正是不能這樣搞那只能換個思路了,居然我們明明知道ApplicationBar是有兩個按鈕的,那么我們可以嘗試一下如下方式:
((ApplicationBarIconButton)ApplicationBar.Buttons[0]).Text = AppResource.ButtonText;
運行代碼,發現果然可以!
第一小節中我們提到添加ApplicatonBar有兩種方式,剛才本地化是用的只是第一種方式,如果用第二種方式也就是代碼的方式添加ApplicatonBar就不存在上面的問題了,把MainPage.xaml中ApplicationBar部分的代碼注釋掉,在MainPage()函數中添加如下代碼:
ApplicationBar = new ApplicationBar(); ApplicationBar.Buttons.Add(new ApplicationBarIconButton(new Uri("/Images/appbar.feature.email.rest.png", UriKind.Relative)) { Text = AppResource.Button1Text }); ApplicationBar.MenuItems.Add(new ApplicationBarMenuItem(AppResource.MenuItem1Text));
運行后發現滿足我們的預期!
到此,本文的內容就結束了,內容很簡單,但是如果實際動手並動腦了你會發現文中提到的很多意外,而偏偏是這些意外加深了我們的理解,希望對大家有所幫助!