• 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));
  • 相关阅读:
    再见 2020, 愿“山河无恙,人间皆安”| 年终总结
    Oracle
    Linux安装
    线程池
    AutoJS
    VSCode
    c++ 解析yaml文件
    管道: 哪些命令能直接从管道的输出中读取?
    K8S 集群部署
    Android项目实战(六十一):pdf文件用图片方式预览
  • 原文地址:https://www.cnblogs.com/zhangxin1989/p/2623024.html
Copyright © 2020-2023  润新知