Windows Phone學習系列(一):添加Application Bar及多語言支持


 

一、創建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屬性賦值即可。代碼如下:

View Code
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的方式很簡單,但是還是有幾個地方是我們容易忽略的。

  1. Buttons的個數是有限制的,最多為4個,多於4個會編譯出錯。當Buttons不夠用時,可以用MenuItems來擴展,而MenuItems的個數是沒有限制,當大於5個時,會出現滾動條。
  2. 圖片添加到項目后必須將Build Action設置成Content並且將Copy to Output Directory設置成Copy if newer或者Copy always,否則圖片顯示不了
  3. 安裝完Windows Phone SDK,系統默認提供了一組最優化的圖標供開發人員使用,在類似如下位置:C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons
  4. 如果需要自定義圖標,為了達到好的效果,需要滿足一定的條件,具體可查詢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,供界面元素綁定(后面介紹為什么要包裝類以及怎么樣去掉這個包裝類),代碼如下:

View Code
public class LocalizedStrings

{

private static WPDemo.AppResource localizedresources = new WPDemo.AppResource();

 

      public WPDemo.AppResource Localizedresources

   {

          get

          {

               return localizedresources;

          }

   }

}

 

  也有類似如下版本的:

View Code
    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文件,添加如下代碼:

View Code
<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元素后代碼如下:

View Code
<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,發現有如下默認構造函數

View Code
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]

        internal AppResource() {

        }

 

  你應該已經發現了,原因就在於構造函數默認的訪問修飾符是internal,資源文件和程序文件編譯后不在同一個程序集,將internal該成public后重新運行,發現和有包裝類時效果一樣了。

 

三、Application Bar的本地化和多語言

 

  有人肯定會納悶為什么要把Application Bar單獨拿出來,其實原因很簡單,它和界面中其他內容元素的本地化有些不一樣。查看Msdn,明確說明Application Bar不是silverlight控件,其屬性不能像TextBlock等其他控件一樣進行數據綁定,要實現是本地化,只能是編碼的方式了。

  先在界面中添加如下代碼

View Code
    <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));

 

  運行后發現滿足我們的預期!

 

  到此,本文的內容就結束了,內容很簡單,但是如果實際動手並動腦了你會發現文中提到的很多意外,而偏偏是這些意外加深了我們的理解,希望對大家有所幫助!

 

示例代碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM