博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第十一章:可绑定的基础结构(二)
阅读量:6220 次
发布时间:2019-06-21

本文共 7079 字,大约阅读时间需要 23 分钟。

查看BindableObject和BindableProperty

名为BindableObject和BindableProperty的类的存在最初可能有点令人困惑。请记住,BindableObject与Object非常相似,因为它充当了Xamarin.Forms API的一大块基类,特别是Element和VisualElement。

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

public class PropertySettingsPage : ContentPage{    public PropertySettingsPage()    {        Label label1 = new Label();        label1.Text = "Text with CLR properties";        label1.IsVisible = true;        label1.Opacity = 0.75;        label1.HorizontalTextAlignment = TextAlignment.Center;        label1.VerticalOptions = LayoutOptions.CenterAndExpand;        label1.TextColor = Color.Blue;        label1.BackgroundColor = Color.FromRgb(255, 128, 128);        label1.FontSize = Device.GetNamedSize(NamedSize.Medium, new Label());        label1.FontAttributes = FontAttributes.Bold | FontAttributes.Italic;        Label label2 = new Label();        label2.SetValue(Label.TextProperty, "Text with bindable properties");        label2.SetValue(Label.IsVisibleProperty, true);        label2.SetValue(Label.OpacityProperty, 0.75);        label2.SetValue(Label.HorizontalTextAlignmentProperty, TextAlignment.Center);        label2.SetValue(Label.VerticalOptionsProperty, LayoutOptions.CenterAndExpand);        label2.SetValue(Label.TextColorProperty, Color.Blue);        label2.SetValue(Label.BackgroundColorProperty, Color.FromRgb(255, 128, 128));        label2.SetValue(Label.FontSizeProperty,                         Device.GetNamedSize(NamedSize.Medium, new Label()));        label2.SetValue(Label.FontAttributesProperty,                         FontAttributes.Bold | FontAttributes.Italic);        Content = new StackLayout        {            Children =             {                label1,                label2            }        };    }}

这两种设置属性的方法完全一致:

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

label2.SetValue(Label.TextProperty, "Text with bindable properties");

什么是SetValue方法? SetValue由BindableObject定义,每个可视对象都派生自该对象。 BindableObject还定义了一个GetValue方法。

SetValue的第一个参数名称为Label.TextProperty,表示该名称
TextProperty是静态的,但尽管它的名字,它根本不是一个属性。 它是Label类的静态字段。 TextProperty也是只读的,它在Label类中的定义如下:

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对象:

public string Text{    set { SetValue(Label.TextProperty, value); }    get { return (string)GetValue(Label.TextProperty); }}

所以你明白为什么你的应用程序使用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定义的以下公共方法的定义得到了很好的证实:

public void SetDynamicResource(BindableProperty property, string key);

当属性是DynamicResource标记扩展的目标时,这就是字典键与元素的特定属性相关联的方式。

此SetDynamicResource方法还允许您在代码中的属性上设置动态资源链接。这是来自DynamicVsStatic的仅代码版本的页面类,名为DynamicVsStaticCode。排除使用FormattedString和Span对象有点简化,但其他方面它非常准确地模仿了解析前一个XAML文件的方式,特别是如何通过XAML解析器设置Label元素的Text属性:

public class DynamicVsStaticCodePage : ContentPage{    public DynamicVsStaticCodePage()    {        Padding = new Thickness(5, 0);        // Create resource dictionary and add item.        Resources = new ResourceDictionary        {            { "currentDateTime", "Not actually a DateTime" }        };        Content = new StackLayout        {            Children =             {                new Label                {                    Text = "StaticResource on Label.Text:",                    VerticalOptions = LayoutOptions.EndAndExpand,                    FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))                },                new Label                {                    Text = (string)Resources["currentDateTime"],                    VerticalOptions = LayoutOptions.StartAndExpand,                    HorizontalTextAlignment = TextAlignment.Center,                    FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))                },                new Label                {                    Text = "DynamicResource on Label.Text:",                    VerticalOptions = LayoutOptions.EndAndExpand,                    FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))                }            }        };        // Create the final label with the dynamic resource.        Label label = new Label        {            VerticalOptions = LayoutOptions.StartAndExpand,            HorizontalTextAlignment = TextAlignment.Center,            FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label))        };        label.SetDynamicResource(Label.TextProperty, "currentDateTime");        ((StackLayout)Content).Children.Add(label);        // Start the timer going.        Device.StartTimer(TimeSpan.FromSeconds(1),            () =>            {                Resources["currentDateTime"] = DateTime.Now.ToString();                return true;            });    }}

第二个Label的Text属性直接从字典条目设置,并且在此上下文中使用字典似乎有点无意义。 但是,最后一个Label的Text属性通过调用SetDynamicResource绑定到字典键,这允许在字典内容更改时使属性更新:

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

public void SetBinding(BindableProperty targetProperty, BindingBase binding);

再次注意第一个参数的类型。 数据绑定所针对的任何属性都必须由可绑定属性支持。

出于这些原因,无论何时创建自定义视图并需要定义公共属性,您的默认倾向应该是将它们定义为可绑定属性。 只有在经过仔细考虑后,您才会得出结论:如果您撤消并定义普通的CLR属性,则该属性不是必需或适合于由样式或数据绑定作为目标。
所以每当你创建一个派生自BindableObject的类时,你应该在该类中输入的第一段代码之一就是“public static readonly BindableProperty” - 也许是所有Xamarin.Forms编程中最具特色的四个单词序列。

转载地址:http://nplja.baihongyu.com/

你可能感兴趣的文章
国内首例:飞步无人卡车携手中国邮政、德邦投入日常运营
查看>>
深入理解浏览器的缓存机制
查看>>
7道常见的数据分析面试题
查看>>
《反脆弱边缘:反脆弱实践》访谈
查看>>
敏捷世界里中层经理的角色
查看>>
微服务现状综述
查看>>
使用试验和数据创新并构建客户真正使用的产品
查看>>
Kubernetes 1.14重磅来袭,多项关键特性生产可用
查看>>
Google发布Tensor2Tensor for TensorFlow
查看>>
微服务的漫长历史
查看>>
专访黄翀:东方航空到底用MongoDB做了什么,技术选型为何花落MongoDB?
查看>>
Keras之父:比特币网络危机重重
查看>>
深入理解JUnit 5的扩展模型
查看>>
Apache Ignite(四):基于Ignite的分布式ID生成器
查看>>
高效运维最佳实践(02):员工的四大误区及解决之道
查看>>
.NET Core完成向RyuJIT的迁移
查看>>
为何百度、智链、蚂蚁金服,纷纷压注区块链溯源?
查看>>
关于HTTPOXY漏洞的分析说明
查看>>
Visual Studio 2017 15.5预览版添加对F# Core及Standard的支持
查看>>
系统监控:top vs Htop vs Glances
查看>>