Fork me on GitHub

UWP-x:Bind

week 1

本周需要完成的事情比较简单,如下:

  1. checkBox 和 line 的绑定处理

    当 CheckBox 被勾选时 line 出现,取消勾选则 line 消失

  2. 新建Item的逻辑判断

    新建一个 NewPage。点击 create 按钮时,检查 Title、Description 是否为空,DueDate 是否正确(是否大于等于当前日期)。如果不正确,弹出对话框,显示错误信息。

对于第二条,知道一个 DateTimeOffset,就没什么需要讲的了。针对第一条,需要进行控件的状态绑定,可分为初阶操作和进阶操作。现在来看看两种操作。

初阶操作

对于 checkBox 控件,我们在官方文档可以发现,它有针对 checked 和 Unchecked 两个状态(如果是使用VS进行开发,那么控件属性状态栏会更容易看到)。那么,操作就很简单啦, checked 时候,line 显示,Unchecked 时候,line 不显示。于是,在给 checkBox 的两个状态绑定了方法后,可以在当前 page 的 cs 文件中写出如下代码:

1
2
3
4
5
6
7
8
//line is the name of the name of the line control to bind
private void IsChecked(object sender, RoutedEventArgs e) {
line.Visibility = Visibility.Visible;
}

private void IsUnchecked(object sender, RoutedEventArgs e) {
line.Visibility = Visibility.Collapsed;
}

好了,完成了。运行一下,达到预期效果。但是! 如果,我们特别懒,toDoList 中的全部任务都没完成,然后又喜欢每天给它加东西,那么 page 的 cs 文件中就会有特别特别特别多的 checked 和 unchecked 方法(百度无人车,可以了解一下)。

进阶操作

怎么解决这种冗杂问题呢?这种时候,我们可以来学习一下 x:Bind

  1. 基本原理

    在 XAML 加载时,{x:Bind} 将转换为你所需的绑定对象,此对象将从数据源上的某一属性中获取相关值。绑定对象可以配置为观察数据源属性值的更改,并基于这些更改自行刷新。该对象也可以配置为将其自己的值的更改推送回源属性。
    借用一下别人写的比较专业的解说。通俗点来讲,就是它可以将一个对象绑定在一个数据源上,并根据数据源的状态对绑定对象进行状态刷新。

  2. 基本用法

    1
    2
    3
    4
    <object property="{x:Bind}" .../>
    -or- <object property="{x:Bind propertyPath}" .../>
    -or- <object property="{x:Bind bindingProperties}" .../>
    -or- <object property="{x:Bind propertyPath, bindingProperties}" .../>

    |parameter|Value|
    |———|—–|
    |propertyPath|A string that specifies the property path for the binding. More info is in the Property path section below.|
    |bindingProperties|One or more binding properties that are specified using a name/value pair syntax.|

    这是来自官方文档的解说(抽象难理解)。
    阅读官档后,我们再来简单翻译一下上文的用法:我们可以利用 x:Bind 对一个 object 的某个 property 与我们希望的数据源进行绑定。其中,数据源的相关信息在 {x:Bind parameters} 中进行指定。
    这个 parameters 有两个,一个为数据源的值,另一个绑定时的辅助信息,包括转换器(Converter),模式(Mode)等。其中,每一个都不是必要的。下面分别讲讲提到的参数。

    • propertyPath

      很难有贴切的翻译,我个人的理解是数据源的值,这个是 Binding 中的 Path 和 ElementName 的结合体。举例说明一下

      1
      2
      {x:Bind Path=slider1.Value}
      {Binding Path=Value, ElementName=slider1}

      例子中的两个写法是等价的。所以个人认为理解为数据源的值会比较好懂。那么,我们需要的绑定代码就可以写出来了:

      1
      2
      <CheckBox x:Name="checkBox" ... IsChecked="False"/>
      <Line ... Visibility="{x:Bind Path=checkBox.IsChecked}"/>
    • bindingProperties

      • Converter

        按照上面那个代码,进行编译,会直接报错绑定数据类型不匹配。IsChecked 是 bool 值,而 Visibility 是 enum 值。这个问题的解决就需要 Converter 了。

        这时候,又可以说到 x:Bind 和 Binding 的一个区别。上面如果使用 Binding,通常是可以通过编译的,然后你操作的时候,程序就崩溃了。因为 x:Bind 是在编译时进行初始化的对象,而 Binding 是在运行时进行初始化的对象。

        回到正题。Converter 就是转换器对象,使用它可以对不匹配类型进行转换。直接通过我们的新代码来看看怎么使用 Converter:

        • XAML文件
          1
          2
          3
          4
          5
          6
          7
          8
          9
          <!--在page的开始定义资源字典-->
          <Page.Resources>
          <local:CompletedConveter x:Key="Converter"/>
          </Page.Resources>

          ...

          <CheckBox x:Name="checkBox" ... IsChecked="False"/>
          <Line ... Visibility="{x:Bind Path=checkBox.IsChecked, Converter={StaticResource Converter}}
        • CS文件
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          //Add into the cs file for this page
          //<summary>
          //A conveter to help bind the line and checkbox
          //</summary>
          class CompletedConveter : IValueConverter {
          public object Convert(object value, Type targetType, object parameter, string language) {
          bool result = (bool)value;
          if (result) {
          return Visibility.Visible;
          }
          return Visibility.Collapsed;

          }

          public object ConvertBack(object value, Type targetType, object parameter, string language) {
          throw new NotImplementedException();
          }
          }

        一定要在 page 定义资源字典,然后才能在 {x:Bind} 中使用,然后去 code 文件中补充完全转换器的定义和实现。

      • Mode

        写了这么多了,运行起来看看效果。程序跑起来了,但是,为什么不会绑定更新呢?这个涉及到 x:Bind 和 Binding 的另一个区别:Mode。
        在 x:Bind 中,Mode 取值有三个: OneTime, OneWay, TwoWay。默认值为 OneTime。

        • OneTime
          仅在界面初始化时去初始化界面中的绑定。所以运行的时候,x:Bind 就不工作了。
        • OneWay
          绑定初始化时,会创建关联,当绑定源的值更改后,绑定目标( UI )也及时更新,单向的。
        • TwoWay
          绑定初始化时,会创建关联,当绑定源的值更改后,绑定目标( UI )也及时更新,当绑定目标( UI )的值更改后,绑定源也及时更新,双向的。
          在 Binding 中,Mode 默认值为 Default (这个值的意义是对于只读控件它是 OneWay,对于可编辑的控件,它是 TwoWay )。

        所以,加上 Mode 语句,就行啦。

        1
        <Line ... Visibility="{x:Bind Path=checkBox.IsChecked, Converter={StaticResource Converter}, Mode="OneWay"}

终于完工了(背后查资料不知道翻了多少,辛酸泪)。