WP7有约(三):课堂重点
[2] WP7有约(三):课堂重点
[3] WP7有约(三):课堂重点
[4] WP7有约(三):课堂重点
[5] WP7有约(三):课堂重点
[6] WP7有约(三):课堂重点
没问题,我们可以在计算标签列表的时候加插一个"特殊"的标签:
代码 42
并在筛选的时候进行"特殊"处理:
代码 43
好了,重新运行应用程序,分别为两个课程新建一些笔记:
图 46
图 47
现在,单击Application Bar上的显示标签按钮:
图 48
选择disposition effect:
图 49
现在,切换到sales psychology课程,单击Application Bar上的显示标签按钮,选择sales strategy:
图 50
再次单击Application Bar上的显示标签按钮,选择(全部):
图 51
现在,切换回behavioral finance课程:
图 52
怎么回事?!我们刚才已经做了筛选啊!
原来,当我们切换课程时,ListBox的ItemsSource属性发生改变,导致ListBox的SelectedItem属性被重设为null,而NoteListViewModel对象的SelectedTag属性和ListBox的SelectedItem属性是双向绑定的,因而也被重设为null了。ListBox的SelectedItem属性被重设为null是对的,因为新的数据源不一定包含SelectedItems属性的值,但把NoteListViewModel对象的SelectedTag属性也重设为null就不对了,因为同一个NotelistViewModel对象的Tags属性肯定包含SelectedTags属性的值,因此,SelectedTag属性的set访问器应该忽略这个重设:
代码 44
重新运行应用程序,重新执行一次上面的测试,嗯,这次没问题了。
命令与行为
我们知道,WPF和最新的Silverlight 4都支持命令绑定,比如说,Button控件有一个Command属性和一个CommandParameter属性,前者用于绑定实现ICommand接口的对象,后者用于绑定传给前者的参数,但SL for WP却只有一个ICommand接口,这意味着我们无法为按钮设置命令,而Application Bar上的按钮这种异类就更不用说了。幸亏Prism为我们带来了ApplicationBarButtonCommand(使用之前请先引用Microsoft.Practices.Prism.Interactivity.dll类库),它能让我们为Application Bar上的按钮设置命令。下面,我们拿NewOrEditNotePage页来示范它的用法。
在设置命令之前,我们得先有个命令,而命令通常是由ViewModel类提供的。打开NewOrEditItemViewModel.cs,在NewOrEditItemViewModel类里添加一个SubmitCommand属性:
代码 45
那么,我们应该如何初始化它?一般的做法是创建一个SubmitCommand类,并让它实现ICommand接口,然后在NewOrEditItemViewModel类的构造函数里把SubmitCommand类的实例赋给SubmitCommand属性。如果你不嫌麻烦的话,你可以这样做,不过,由于创建命令对象的需求非常普遍,Prism为我们带来了DelegateCommand泛型类,我们只需把提交数据的代码传给它的构造函数就可以了:
代码 46
接着,把_submit私有字段以及在构造函数里初始化它的代码删除,因为我们不再需要它了。删除之后,把Submit方法改成这样:
代码 47
换句话说,原来的_submit私有字段被现在的SubmitCommand属性取代了。
现在,打开NewOrEditNotePage页,从Assets面板上把ApplicationBarButtonCommand拖到Objects and Timeline面板的PhoneApplicationPage上:
图 53
此时,Objects and Timeline面板将会变成这样:
图 54
接着,在Properties面板上把ButtonText属性的值设为"确定":
图 55
单击CommandBinding右边的小正方形,并选择Custom Expression:
图 56
在弹出的Custom expression对话框里输入"{Binding SubmitCommand}"并按回车:
图 57
用同样的办法把CommandParameterBinding设为"{Binding Item}"。
那么,用户提交数据之后如何返回?这个时候就轮到ApplicationBarButtonNavigation上场了。从Assets面板上把ApplicationBarButtonCommand拖到Objects and Timeline面板的PhoneApplicationPage上,此时,Objects and Timeline面板将会变成这样:
图 58
接着,在Properties面板上把ButtonText和NavigateTo两个属性的值分别设为"确定"和"#GoBack":
图 59
需要说明的是,"#GoBack"是一个硬性规定的特殊值,当我们把NavigateTo属性的值设为"#GoBack"时,ApplicationBarButtonNavigation会调用NavigationService.GoBack方法返回,而当我们把NavigateTo属性设为XXX.xaml时,它会调用NavigationService.Navigate方法导航至对应的页面。
那么,Text属性更新绑定源的问题呢?难道Prism也提供了相应的组件?没有,这次我们得亲自出手了。右击Utils文件夹,然后选择Add New Items,在弹出的New Item对话框里选择Behavior,并把它命名为AppBarButtonUpdateSource:
图 60
我们知道,Application Bar上的按钮并非Silverlight的一部分,因此Behavior无法直接作用于它,而Silverlight里只有PhoneApplicationPage类提供了访问Application Bar的方法,因此我们需要把AppBarButtonUpdateSource的目标类型改为PhoneApplicationPage:
代码 48
这也正是我们把ApplicationBarButtonCommand和ApplicationBarButtonNavigation拖到PhoneApplicationPage上的原因。那么,如何才能找到Application Bar上的按钮?Prism为我们带来了FindButton扩展方法,可以通过按钮的文字来查找,因此,我们需要创建一个ButtonText属性和一个_button私有字段,前者用于指定待查找按钮的文字,后者用于保存找到的按钮:
代码 49
FindButton扩展方法需要一个实现IApplicationBar接口的对象,而能够提供这个对象的只有PhoneApplicationPage对象,后者可以通过Behavior的AssociatedObject属性访问。于是,我们可以在OnAttached方法里初始化_button私有字段:
代码 50
找到按钮之后,我们需要把更新绑定源的代码关联到按钮上,而做到这点的唯一办法就是为按钮创建一个Click事件处理程序:
代码 51
最后,在OnDetaching方法里解除它们之间的关联:
代码 52
现在,重新编译项目,然后从Assets面板上把AppBarButtonUpdateSource拖到Objects and Timeline面板的PhoneApplicationPage上,并把ButtonText属性的值设为"确定"。此时,Objects and Timeline面板将会变成这样:
图 61
不过,这个顺序是不对的,AppBarButtonUpdateSource应该排在其它两个的前面,但这个顺序在Expression Blend里无法调整,因此我们需要手动修改XAML。
至于取消按钮,由于它只是简单地返回,我们只需为它添置一个ApplicationBarButtonNavigation就行了。添置好后,Objects and Timeline面板将会变成这样:
图 62
现在,我们可以把这两个按钮的Click事件处理程序去掉了。
命令绑定是MVVM模式的重要组成部分,它不但可以进一步降低View和ViewModel之间的耦合度,还可以简化单元测试的工作。目前我们通过Behavior来实现命令绑定只是权宜之计,希望微软可以在将来的版本里把这部分功能补完了。还有的就是希望微软能够进一步完善Application Bar,包括处理焦点问题以及提供更丰富的访问方式。
下课了……