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

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

只读可绑定属性

假设您正在使用一个应用程序,在该应用程序中,可以方便地知道Label元素显示的文本中的单词数。 也许您希望将该工具直接构建到源自Label的类中。 我们称这个新类为CountedLabel。
到目前为止,您首先想到的是定义一个名为WordCount?属性的BindableProperty对象和一个名为WordCount的相应CLR属性。
但是等一下:只有从CountedLabel类中设置这个WordCount属性才有意义。 这意味着WordCount CLR属性不应具有公共集访问器。 它应该这样定义:

public int WordCount{    private set { SetValue(WordCountProperty, value); }    get { return (double)GetValue(WordCountProperty); }}

get访问器仍然是公共的,但set访问器是私有的。 那够了吗?

不完全是。 尽管CLR属性中有私有set访问器,但CountedLabel外部的代码仍然可以使用CountedLabel.WordCountProperty可绑定属性对象调用SetValue。 这种类型的财产设置也应该被禁止。 但是,如果WordCountProp?erty对象是公共的,那怎么能工作呢?
解决方案是使用BindableProperty.Create?ReadOnly方法创建只读的可绑定属性。 Xamarin.Forms API本身定义了几个只读的可绑定属性 - 例如,Width和
由VisualElement定义的高度属性。
以下是如何制作自己的:
第一步是使用与BindableProperty.Create相同的参数调用BindableProperty.CreateReadOnly。 但是,CreateReadOnly方法返回Binda?blePropertyKey的对象而不是BindableProperty。 将此对象定义为static和readonly,与BindableProperty一样,但将其设置为类的私有:

public class CountedLabel : Label{    static readonly BindablePropertyKey WordCountKey =        BindableProperty.CreateReadOnly("WordCount", //propertyName                                        typeof(int), // returnType                                        typeof(CountedLabel), // declaringType                                        0); // defaultValue }

不要将此BindablePropertyKey对象视为加密密钥或类似的东西。 它更简单 - 实际上只是一个私有的对象。

第二步是使用BindablePropertyKey的BindableProperty属性创建一个公共BindableProperty对象:

public class CountedLabel : Label{     public static readonly BindableProperty WordCountProperty = WordCountKey.BindableProperty;}

这个BindableProperty对象是公共的,但它是一种特殊的BindableProperty:它不能用于SetValue调用。 尝试这样做会引发InvalidOperationException。

但是,SetValue方法有一个重载,它接受一个BindablePropertyKey对象。 CLR set访问器可以使用此对象调用SetValue,但是此set访问器必须是私有的,以防止在类外部设置属性:

public class CountedLabel : Label{     public int WordCount    {        private set { SetValue(WordCountKey, value); }        get { return (int)GetValue(WordCountProperty); }    } }

现在可以在CountedLabel类中设置WordCount属性。 但课程什么时候应该设定呢? 此CountedLabel类派生自Label,但它需要检测Text prop?erty何时更改,以便它可以对单词进行计数。

Label有TextChanged事件吗? 不,不是的。 但是,BindableObject实现了INotifyPropertyChanged接口。 这是一个非常重要的.NET接口,特别是对于实现Model-View-ViewModel(MVVM)体系结构的应用程序。 在第18章中,您将了解如何在自己的数据类中使用它。
INotifyPropertyChanged接口在System.ComponentModel命名空间中定义,如下所示:

public interface INotifyPropertyChanged{    event PropertyChangedEventHandler PropertyChanged;}

每当由BindableProperty支持的任何属性发生更改时,从BindableObject派生的每个类都会自动触发此PropertyChanged事件。 此事件附带的PropertyChangedEventArgs对象包含一个名为PropertyName的属性,其属性为string,用于标识已更改的属性。

因此,所有必要的是,CountedLabel为PropertyChanged事件附加处理程序并检查属性名称“Text”。 从那里它可以使用它想要的任何技术来计算字数。 完整的CountedLabel类在PropertyChanged事件上使用lambda函数。 处理程序调用Split将字符串分解为单词,并查看有多少部分结果。 Split方法基于空格,短划线和短划线(Unicode u2014)拆分文本:

public class CountedLabel : Label{    static readonly BindablePropertyKey WordCountKey =        BindableProperty.CreateReadOnly("WordCount", // propertyName                                        typeof(int), // returnType                                        typeof(CountedLabel), // declaringType                                        0); // defaultValue    public static readonly BindableProperty WordCountProperty = WordCountKey.BindableProperty;    public CountedLabel()    {        // Set the WordCount property when the Text property changes.        PropertyChanged += (object sender, PropertyChangedEventArgs args) =>        {            if (args.PropertyName == "Text")            {                if (String.IsNullOrEmpty(Text))                {                    WordCount = 0;                }                else                {                    WordCount = Text.Split(' ', '-', '\u2014').Length;                }            }        };    }    public int WordCount    {        private set { SetValue(WordCountKey, value); }        get { return (int)GetValue(WordCountProperty); }    }}

该类包含System.ComponentModel命名空间的using指令,用于处理程序的Property?ChangedEventArgs参数。 注意:Xamarin.Forms定义了一个名为Prop?ertyChangingEventArgs(现在时)的类。 这不是你想要的PropertyChanged han?dler。 你想要PropertyChangedEventArgs(过去时)。

因为Split方法的这个调用将文本分成空白字符,破折号和破折号,所以您可能会认为将使用包含一些破折号和破折号的文本演示CountedLabel。 这是真的。 BaskervillesCount程序是第3章中Baskervilles程序的变体,但是这里的文本段落用CountedLabel显示,并且包含常规Label以显示单词count:

常规Label在代码隐藏文件中设置:

public partial class BaskervillesCountPage : ContentPage{    public BaskervillesCountPage()    {        InitializeComponent();        int wordCount = countedLabel.WordCount;        wordCountLabel.Text = wordCount + " words";    }}

它计算的单词计数是基于这样的假设:文本中的所有连字符分开两个单词,并且“hearth-rug”和“bulbous-headed”应该被计为每个单词两个单词。 当然,这并不总是正确的,但字数不像算法那么简单,因为这个代码可能意味着:

201808051437220362
如果文本在程序运行时动态更改,程序将如何构建? 在这种情况下,每当CountedLabel对象的WordCount属性发生更改时,都需要更新单词计数。 您可以在Count?edLabel对象上附加PropertyChanged处理程序,并检查名为“WordCount”的属性。
但是,如果您尝试从XAML设置此类事件处理程序,请务必谨慎 - 例如,如下所示:

您可能希望在代码隐藏文件中编码事件处理程序,如下所示:

void OnCountedLabelPropertyChanged(object sender,                                    PropertyChangedEventArgs args){    wordCountLabel.Text = countedLabel.WordCount + " words";}

当XAML解析器设置Text属性时,该处理程序将触发,但事件处理程序正在尝试设置尚未实例化的第二个Label的Text属性,这意味着wordCountLabel字段仍设置为null。 这是第15章在使用交互式控件时会再次出现的问题,但在第16章中处理数据绑定时,它将会得到很好的解决。

在AbsoluteLay的第14章中还有另一种可绑定属性的变体吗?out:这是附加的可绑定属性,它在实现某些类型的布局时非常有用,你将在第26章中发现, “自定义布局。”
同时,让我们看一下可绑定属性最重要的应用之一:样式。

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

你可能感兴趣的文章
一个两年Java的面试总结
查看>>
转:React Native之旅01-创建项目
查看>>
软件工程项目组Z.XML会议记录 2013/11/27
查看>>
科学计算库学习报告
查看>>
软件测试 -- 软件测试的风险主要体现在哪里
查看>>
修改App.config中的appSettings
查看>>
JQuery选择器总结
查看>>
Ubuntu中无法update的解决办法
查看>>
仿射变换
查看>>
decltype类型指示符
查看>>
虹软ArcFace人脸识别 与 Dlib 人脸识别对比
查看>>
laravel 验证码使用示例
查看>>
IE开发人员工具无法使用
查看>>
shiro 认证问题
查看>>
分页器(自定制)
查看>>
Docker系列一:Docker的介绍和安装
查看>>
java中添加定时任务
查看>>
mysql innodb研究中一直不懂的东西(不断更新)
查看>>
洛谷 P1803 凌乱的yyy Label:Water 贪心
查看>>
3.4 函数式编程
查看>>