Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4112305
  • 博文数量: 855
  • 博客积分: 17977
  • 博客等级: 上将
  • 技术积分: 8236
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-26 09:59
  • 认证徽章:
个人简介

一个好老好老的老程序员了。

文章分类

全部博文(855)

文章存档

2019年(12)

2018年(88)

2017年(130)

2015年(5)

2014年(12)

2013年(41)

2012年(36)

2011年(272)

2010年(1)

2009年(53)

2008年(65)

2007年(47)

2006年(81)

2005年(12)

分类: Android平台

2018-07-08 15:43:39

x:Name属性

在大多数实际应用程序中,代码隐藏文件需要引用XAML文件中定义的元素。 您在上一章的CodePlusXaml程序中看到了一种方法:如果代码隐藏文件知道XAML文件中定义的可视树的布局,它可以从根元素(页面本身)开始, 找到树中的特定元素。 此过程称为“在树上行走”,可用于定位页面上的特定元素。
通常,更好的方法是为XAML文件中的元素赋予类似于变量名的名称。 要执行此操作,请使用XAML固有的属性,称为Name。 因为前缀x几乎单独用于XAML固有的属性,所以此Name属性通常称为x:Name。
XamlClock项目演示了x:Name的使用。 这是包含两个Label控件的XamlClockPage.xaml文件,名为timeLabel和dateLabel:

点击(此处)折叠或打开

  1. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  2.              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  3.              x:Class="XamlClock.XamlClockPage">
  4.     <StackLayout>
  5.         <Label x:Name="timeLabel"
  6.                FontSize="Large"
  7.                HorizontalOptions="Center"
  8.                VerticalOptions="EndAndExpand" />
  9.         <Label x:Name="dateLabel"
  10.                HorizontalOptions="Center"
  11.                VerticalOptions="StartAndExpand" />
  12.     



x:Name的规则与C#变量名称的规则相同。 (你很快就会明白为什么。)名称必须以字母或下划线开头,并且只能包含字母,下划线和数字。

与第5章中的时钟程序一样,XamlClock使用Device.StartTimer来触发定期事件以更新时间和日期。 这是XamlClockPage代码隐藏文件:

点击(此处)折叠或打开

  1. namespace XamlClock
  2. {
  3.     public partial class XamlClockPage
  4.     {
  5.         public XamlClockPage()
  6.         {
  7.             InitializeComponent();
  8.             Device.StartTimer(TimeSpan.FromSeconds(1), OnTimerTick);
  9.         }
  10.         bool OnTimerTick()
  11.         {
  12.             DateTime dt = DateTime.Now;
  13.             timeLabel.Text = dt.ToString("T");
  14.             dateLabel.Text = dt.ToString("D");
  15.             return true;
  16.         }
  17.     }
  18. }

此计时器回调方法每秒调用一次。 该方法必须返回true才能继续计时器。 如果返回false,则计时器停止,必须通过另一次调用Device.Start?Timer重新启动。
回调方法引用timeLabel和dateLabel,就像它们是普通变量一样,并设置每个变量的Text属性:
201807052108200346
这不是一个视觉上令人印象深刻的时钟,但它绝对是功能性的。
如何使用代码隐藏文件引用用x:Name标识的元素? 这很神奇吗? 当然不是。 当您检查XAML解析器在构建项目时从XAML文件生成的XamlClockPage.xaml.g.cs文件时,该机制非常明显:

点击(此处)折叠或打开

  1. namespace XamlClock {
  2.     using System;
  3.     using Xamarin.Forms;
  4.     using Xamarin.Forms.Xaml;
  5.     public partial class XamlClockPage : global::Xamarin.Forms.ContentPage {
  6.         [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG",
  7.                                                         "0.0.0.0")]
  8.         private global::Xamarin.Forms.Label timeLabel;
  9.         [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG",
  10.                                                         "0.0.0.0")]
  11.         private global::Xamarin.Forms.Label dateLabel;
  12.         [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG",
                                                             "0.0.0.0")]
            private void InitializeComponent() {
                this.LoadFromXaml(typeof(XamlClockPage));
                timeLabel = this.FindByName("timeLabel");
                dateLabel = this.FindByName("dateLabel");
            }
        }
    }

由于属性和完全限定类型,可能有点难以看到,但是当构建时XAML解析器咀嚼XAML文件时,每个x:Name属性都成为此生成的代码文件中的私有字段。这允许代码隐藏文件中的代码引用这些名称,就像它们是正常字段一样 - 它们肯定是。但是,字段最初为空。仅在运行时调用InitializeComponent时,才会通过FindByName方法设置两个字段,该方法在NameScopeExtensions类中定义。如果代码隐藏文件的构造函数尝试在InitializeComponent调用之前引用这两个字段,则它们将具有空值。
这个生成的代码文件还暗示了x的另一个规则:名称值现在非常明显但很少明确说明:名称不能复制代码后面文件中定义的字段或属性的名称。
因为这些是私有字段,所以只能从代码隐藏文件而不是其他类访问它们。如果ContentPage衍生产品需要将公共字段或属性公开给其他类,则必须自己定义它们。
显然,x:Name值在XAML页面中必须是唯一的。如果您在XAML文件中使用OnPlatform作为特定于平台的元素,这有时会成为问题。例如,这是一个XAML文件,它将OnPlatform的iOS,Android和WinPhone属性表示为属性元素,以选择三个Label视图之一:

点击(此处)折叠或打开

  1. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  2.              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  3.              x:Class="PlatformSpecificLabels.PlatformSpecificLabelsPage">
  4.     <OnPlatform x:TypeArguments="View">
  5.         <OnPlatform.iOS>
  6.             <Label Text="This is an iOS device"
  7.                    HorizontalOptions="Center"
  8.                    VerticalOptions="Center" />
  9.         </OnPlatform.iOS>
  10.         <OnPlatform.Android>
  11.             <Label Text="This is an Android device"
  12.                    HorizontalOptions="Center"
  13.                    VerticalOptions="Center" />
  14.         </OnPlatform.Android>
  15.         <OnPlatform.WinPhone>
  16.             <Label Text="This is an Windows device"
  17.                    HorizontalOptions="Center"
  18.                    VerticalOptions="Center" />
  19.         </OnPlatform.WinPhone>
  20.     </OnPlatform>
  21. </ContentPage>

OnPlatform的x:TypeArguments属性必须与目标属性的类型完全匹配。 此OnPlatform元素隐式设置为ContentPage的Content属性,此Content属性的类型为View,因此OnPlatform的x:TypeArguments属性必须指定View。 但是,OnPlatform的属性可以设置为从该类型派生的任何类。 设置为iOS,Android和WinPhone属性的对象实际上可以是不同的类型,只要它们都来自View。
尽管该XAML文件有效,但它并不完全是最佳的。 实例化并初始化所有三个Label视图,但只有一个设置为ContentPage的Content属性。 如果您需要从代码隐藏文件中引用Label并且为每个文件指定相同的名称,则会出现此方法的问题,如下所示:
以下XAML文件不起作用!

点击(此处)折叠或打开

  1. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  2.              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  3.              x:Class="PlatformSpecificLabels.PlatformSpecificLabelsPage">
  4.     <OnPlatform x:TypeArguments="View">
  5.         <OnPlatform.iOS>
  6.             <Label x:Name="deviceLabel"
  7.                    Text="This is an iOS device"
  8.                    HorizontalOptions="Center"
  9.                    VerticalOptions="Center" />
  10.         </OnPlatform.iOS>
  11.         <OnPlatform.Android>
  12.             <Label x:Name="deviceLabel"
  13.                    Text="This is an Android device"
  14.                    HorizontalOptions="Center"
  15.                    VerticalOptions="Center" />
  16.         </OnPlatform.Android>
  17.         <OnPlatform.WinPhone>
  18.             <Label x:Name="deviceLabel"
  19.                    Text="This is a Windows device"
  20.                    HorizontalOptions="Center"
  21.                    VerticalOptions="Center" />
  22.         </OnPlatform.WinPhone>
  23.     </OnPlatform>
  24. </ContentPage>

这不起作用,因为多个元素不能具有相同的名称。
您可以使用Device.OnPlatform为它们提供不同的名称并处理代码隐藏文件中的三个名称,但更好的解决方案是使特定于平台的标记保持尽可能小。 在此示例中,除Text外,所有Label属性都相同,因此只有Text属性需要特定于平台。 这是PlatformSpecificLabels程序的版本,它包含在本章的示例代码中。 它有一个Label,除了Text属性外,一切都是平台独立的:


点击(此处)折叠或打开

  1. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  2.              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  3.              x:Class="PlatformSpecificLabels.PlatformSpecificLabelsPage">
  4.     <Label x:Name="deviceLabel"
  5.            HorizontalOptions="Center"
  6.            VerticalOptions="Center">
  7.         <Label.Text>
  8.            <OnPlatform x:TypeArguments="x:String"
  9.                        iOS="This is an iOS device"
  10.                        Android="This is an Android device"
  11.                        WinPhone="This is a Windows device" />
  12.         </Label.Text>
  13.     </Label>
  14. </ContentPage>

这是它的样子:

Text属性是Label的content属性,因此您不需要上一个示例中的Label.Text标记。 这也有效:

点击(此处)折叠或打开

  1. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  2.              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  3.              x:Class="PlatformSpecificLabels.PlatformSpecificLabelsPage">
  4.     <Label x:Name="deviceLabel"
  5.            HorizontalOptions="Center"
  6.            VerticalOptions="Center">
  7.         <OnPlatform x:TypeArguments="x:String"
  8.                     iOS="This is an iOS device"
  9.                     Android="This is an Android device"
  10.                     WinPhone="This is a Windows device" />
  11.     </Label>
  12. </ContentPage>

阅读(1052) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册