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

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

文章分类

全部博文(915)

文章存档

2022年(9)

2021年(13)

2020年(10)

2019年(40)

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-08-01 22:23:24

查看BindableObject和BindableProperty

名为BindableObject和BindableProperty的类的存在最初可能有点令人困惑。请记住,BindableObject与Object非常相似,因为它充当了Xamarin.Forms API的一大块基类,特别是Element和VisualElement。
BindableObject为BindableProperty类型的对象提供支持。 BindableProperty对象扩展CLR属性。关于可绑定属性的最佳见解来自于您创建自己的一些内容 - 正如您将在本章结束之前所做的那样 - 但您也可以通过探索现有的可绑定属性来收集一些内容。
在第7章“XAML与代码”的开头,创建了两个具有许多相同属性设置的按钮,只是使用C#3.0对象初始化语法和另一个按钮在代码中设置了一个按钮的属性。在XAML中实例化并初始化。
这是一个名为PropertySettings的类似(但仅限代码)程序,它还以两种不同的方式创建和初始化两个按钮。第一个Label的属性以旧式方式设置,而第二个Label的属性使用更详细的技术设置:

点击(此处)折叠或打开

  1. public class PropertySettingsPage : ContentPage
  2. {
  3.     public PropertySettingsPage()
  4.     {
  5.         Label label1 = new Label();
  6.         label1.Text = "Text with CLR properties";
  7.         label1.IsVisible = true;
  8.         label1.Opacity = 0.75;
  9.         label1.HorizontalTextAlignment = TextAlignment.Center;
  10.         label1.VerticalOptions = LayoutOptions.CenterAndExpand;
  11.         label1.TextColor = Color.Blue;
  12.         label1.BackgroundColor = Color.FromRgb(255, 128, 128);
  13.         label1.FontSize = Device.GetNamedSize(NamedSize.Medium, new Label());
  14.         label1.FontAttributes = FontAttributes.Bold | FontAttributes.Italic;
  15.         Label label2 = new Label();
  16.         label2.SetValue(Label.TextProperty, "Text with bindable properties");
  17.         label2.SetValue(Label.IsVisibleProperty, true);
  18.         label2.SetValue(Label.OpacityProperty, 0.75);
  19.         label2.SetValue(Label.HorizontalTextAlignmentProperty, TextAlignment.Center);
  20.         label2.SetValue(Label.VerticalOptionsProperty, LayoutOptions.CenterAndExpand);
  21.         label2.SetValue(Label.TextColorProperty, Color.Blue);
  22.         label2.SetValue(Label.BackgroundColorProperty, Color.FromRgb(255, 128, 128));
  23.         label2.SetValue(Label.FontSizeProperty,
  24.                         Device.GetNamedSize(NamedSize.Medium, new Label()));
  25.         label2.SetValue(Label.FontAttributesProperty,
  26.                         FontAttributes.Bold | FontAttributes.Italic);
  27.         Content = new StackLayout
  28.         {
  29.             Children =
  30.             {
  31.                 label1,
  32.                 label2
  33.             }
  34.         };
  35.     }
  36. }
这两种设置属性的方法完全一致:

然而,替代语法似乎很奇怪。 例如:

点击(此处)折叠或打开

  1. label2.SetValue(Label.TextProperty, "Text with bindable properties");
什么是SetValue方法? SetValue由BindableObject定义,每个可视对象都派生自该对象。 BindableObject还定义了一个GetValue方法。
SetValue的第一个参数名称为Label.TextProperty,表示该名称
TextProperty是静态的,但尽管它的名字,它根本不是一个属性。 它是Label类的静态字段。 TextProperty也是只读的,它在Label类中的定义如下:

点击(此处)折叠或打开

  1. public static readonly BindableProperty TextProperty;
这是BindableProperty类型的对象。 当然,将一个字段命名为TextProperty似乎有点令人不安,但确实如此。 但是,因为它是静态的,所以它独立于任何可能存在或可能不存在的Label对象。
如果查看Label类的文档,您将看到它定义了10个属性,包括Text,TextColor,FontSize,FontAttributes等。 您还将看到10个具有名称TextProperty,TextCol?orProperty,FontSizeProperty,FontAttributesProperty等名称的BindableProperty类型的公共静态只读字段。
这些属性和字段密切相关。 实际上,在Label类的内部,Text CLR属性被定义为这样引用相应的TextProperty对象:

点击(此处)折叠或打开

  1. public string Text
  2. {
  3.     set { SetValue(Label.TextProperty, value); }
  4.     get { return (string)GetValue(Label.TextProperty); }
  5. }

所以你明白为什么你的应用程序使用Label.TextProperty参数调用SetValue完全等同于直接设置Text属性,并且可能只是更快一点!
Label中Text属性的内部定义不是机密信息。 这是标准代码。虽然任何类都可以定义BindableProperty对象,但只有从Binda?bleObject派生的类才能调用实际实现类中属性的SetValue和GetValue方法。 GetValue方法需要进行强制转换,因为它被定义为返回对象。
维护Text属性所涉及的所有实际工作都在那些SetValue和GetValue调用中进行。 BindableObject和BindableProperty对象有效地扩展了标准CLR属性的功能,以提供系统化的方法:

  • 定义属性
  • 为属性提供默认值
  • 存储其当前值
  • 提供验证属性值的机制
  • 在单个班级中保持相关属性之间的一致性
  • 回应财产变化
  • 当属性即将更改并已更改时触发通知
  • 支持数据绑定
  • 支持样式
  • 支持动态资源

名为Text的属性与名为TextProp的BindableProperty的紧密关系反映在程序员谈论这些属性的方式中:有时程序员说Text属性由名为TextProperty的BindableProperty“支持”,因为TextProperty提供基础结构支持 文本。 但一个常见的捷径就是说Text本身就是一个“可绑定的属性”,通常没有人会被混淆。
并非每个Xamarin.Forms属性都是可绑定属性。 ContentPage的Content属性和Layout 的Children属性都不是可绑定属性。在VisualElement定义的28个属性中,26个由可绑定属性支持,但Bounds属性和Resources属性不支持。
与FormattedString结合使用的Span类不是从BindableOb?ject派生的。因此,Span不会继承SetValue和GetValue方法,也无法实现BindableProperty对象。
这意味着Label的Text属性由可绑定属性支持,但Span的Text prop不是。这有什么不同吗?
当然它有所作为!如果您回忆上一章中的DynamicVsStatic程序,您会发现DynamicResource处理Label的Text属性,但不处理Span的Text属性。是不是DynamicResource只能使用可绑定属性?
这个假设通过Element定义的以下公共方法的定义得到了很好的证实:

点击(此处)折叠或打开

  1. public void SetDynamicResource(BindableProperty property, string key);
当属性是DynamicResource标记扩展的目标时,这就是字典键与元素的特定属性相关联的方式。
此SetDynamicResource方法还允许您在代码中的属性上设置动态资源链接。这是来自DynamicVsStatic的仅代码版本的页面类,名为DynamicVsStaticCode。排除使用FormattedString和Span对象有点简化,但其他方面它非常准确地模仿了解析前一个XAML文件的方式,特别是如何通过XAML解析器设置Label元素的Text属性:

点击(此处)折叠或打开

  1. public class DynamicVsStaticCodePage : ContentPage
  2. {
  3.     public DynamicVsStaticCodePage()
  4.     {
  5.         Padding = new Thickness(5, 0);
  6.         // Create resource dictionary and add item.
  7.         Resources = new ResourceDictionary
  8.         {
  9.             { "currentDateTime", "Not actually a DateTime" }
  10.         };
  11.         Content = new StackLayout
  12.         {
  13.             Children =
  14.             {
  15.                 new Label
  16.                 {
  17.                     Text = "StaticResource on Label.Text:",
  18.                     VerticalOptions = LayoutOptions.EndAndExpand,
  19.                     FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
  20.                 },
  21.                 new Label
  22.                 {
  23.                     Text = (string)Resources["currentDateTime"],
  24.                     VerticalOptions = LayoutOptions.StartAndExpand,
  25.                     HorizontalTextAlignment = TextAlignment.Center,
  26.                     FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
  27.                 },
  28.                 new Label
  29.                 {
  30.                     Text = "DynamicResource on Label.Text:",
  31.                     VerticalOptions = LayoutOptions.EndAndExpand,
  32.                     FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
  33.                 }
  34.             }
  35.         };
  36.         // Create the final label with the dynamic resource.
  37.         Label label = new Label
  38.         {
  39.             VerticalOptions = LayoutOptions.StartAndExpand,
  40.             HorizontalTextAlignment = TextAlignment.Center,
  41.             FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))
  42.         };
  43.         label.SetDynamicResource(Label.TextProperty, "currentDateTime");
  44.         ((StackLayout)Content).Children.Add(label);
  45.         // Start the timer going.
  46.         Device.StartTimer(TimeSpan.FromSeconds(1),
  47.             () =>
  48.             {
  49.                 Resources["currentDateTime"] = DateTime.Now.ToString();
  50.                 return true;
  51.             });
  52.     }
  53. }
第二个Label的Text属性直接从字典条目设置,并且在此上下文中使用字典似乎有点无意义。 但是,最后一个Label的Text属性通过调用SetDynamicResource绑定到字典键,这允许在字典内容更改时使属性更新:

考虑一下:如果它不能使用BindableProperty对象引用属性,那么这个SetDynamicResource方法的签名是什么?在方法调用中引用属性值很容易,但不是属性本身。有两种方法,例如System.Reflection命名空间中的PropertyInfo类或LINQ Expression对象。但是BindableProperty对象是专门为此目的而设计的,以及处理属性和字典键之间的底层链接的基本工作。
类似地,当我们在下一章中探索样式时,您将遇到一个用于与样式连接的Setter类。 Setter定义了一个名为Property的类型为BindableProperty的属性,该属性要求样式所针对的任何属性必须由可绑定属性支持。这允许在样式所针对的元素之前定义样式。
同样,对于数据绑定。 BindableObject类定义一个SetBinding方法,该方法与Element上定义的SetDynamicResource方法非常相似:

点击(此处)折叠或打开

  1. public void SetBinding(BindableProperty targetProperty, BindingBase binding);
再次注意第一个参数的类型。 数据绑定所针对的任何属性都必须由可绑定属性支持。
出于这些原因,无论何时创建自定义视图并需要定义公共属性,您的默认倾向应该是将它们定义为可绑定属性。 只有在经过仔细考虑后,您才会得出结论:如果您撤消并定义普通的CLR属性,则该属性不是必需或适合于由样式或数据绑定作为目标。
所以每当你创建一个派生自BindableObject的类时,你应该在该类中输入的第一段代码之一就是“public static readonly BindableProperty” - 也许是所有Xamarin.Forms编程中最具特色的四个单词序列。
阅读(2193) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~