week 1
本周需要完成的事情比较简单,如下:
- checkBox 和 line 的绑定处理
当 CheckBox 被勾选时 line 出现,取消勾选则 line 消失
- 新建Item的逻辑判断
新建一个 NewPage。点击 create 按钮时,检查 Title、Description 是否为空,DueDate 是否正确(是否大于等于当前日期)。如果不正确,弹出对话框,显示错误信息。
对于第二条,知道一个 DateTimeOffset,就没什么需要讲的了。针对第一条,需要进行控件的状态绑定,可分为初阶操作和进阶操作。现在来看看两种操作。
初阶操作
对于 checkBox 控件,我们在官方文档可以发现,它有针对 checked 和 Unchecked 两个状态(如果是使用VS进行开发,那么控件属性状态栏会更容易看到)。那么,操作就很简单啦, checked 时候,line 显示,Unchecked 时候,line 不显示。于是,在给 checkBox 的两个状态绑定了方法后,可以在当前 page 的 cs 文件中写出如下代码:
1 | //line is the name of the name of the line control to bind |
好了,完成了。运行一下,达到预期效果。但是! 如果,我们特别懒,toDoList 中的全部任务都没完成,然后又喜欢每天给它加东西,那么 page 的 cs 文件中就会有特别特别特别多的 checked 和 unchecked 方法(百度无人车,可以了解一下)。
进阶操作
怎么解决这种冗杂问题呢?这种时候,我们可以来学习一下 x:Bind。
- 基本原理
在 XAML 加载时,{x:Bind} 将转换为你所需的绑定对象,此对象将从数据源上的某一属性中获取相关值。绑定对象可以配置为观察数据源属性值的更改,并基于这些更改自行刷新。该对象也可以配置为将其自己的值的更改推送回源属性。
借用一下别人写的比较专业的解说。通俗点来讲,就是它可以将一个对象绑定在一个数据源上,并根据数据源的状态对绑定对象进行状态刷新。 基本用法
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 文件中补充完全转换器的定义和实现。
- XAML文件
- 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"}
- OneTime
终于完工了(背后查资料不知道翻了多少,辛酸泪)。