添加Application Bar及多语言支持

来源:互联网 发布:windows排名 编辑:程序博客网 时间:2024/06/05 18:42


一、创建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));

 

  运行后发现满足我们的预期!

 

  到此,本文的内容就结束了,内容很简单,但是如果实际动手并动脑了你会发现文中提到的很多意外,而偏偏是这些意外加深了我们的理解,希望对大家有所帮助!

 

示例代码下载


转自:http://www.cnblogs.com/hiyz/archive/2012/07/19/2599324.html

0 0
原创粉丝点击