包氏波动思想
有了前面介绍的AttachedBehavior,所有控件的任意方法都可以转换为Command了。
但是,对于列表控件而言,还有一条解决方案,这包括DataGrid、ListBox、ComboBox等等,而对于CheckBox、RadioButton而言,也可以将其视为由多个选项组成的控件,所以,也在本文涉及的范围之内。
先来看一个例子:
(一)DataGrid
一个DataGrid,选择其中的任意一行,都会在GroupBox中显示这一行的详细信息。对,这是Master-Detail技术:
在传统窗体编程模型中,使用DataGrid的SelectionChanged事件,可以轻松实现这一功能:
{
var selectStudent = e.AddedItems[0] as Student;
tbUserName.Text = selectStudent.UserName;
tbScore.Text = selectStudent.Score.ToString();
}
但如今,我们要使用MVP来实现这个小例子,所以像SelectionChanged这样的事件是不能使用的,怎么办呢?
仔细观察GridView控件,会发现它有一个SelectedItem属性,当SelectionChanged事件触发后,这个属性会被设置为当前选中的那一行。于是,我们在数据(Model)中,可以建立同名的一个属性,将它们进行绑定。那么,选中不同的行,GridView的SelectedItem就会改变,这一“波动”会导致数据(Model)中的相应属性(这里是SelectedStudent)也跟着变动,我们可以在数据(Model)中捕获到这一“波动”,从而执行一些自己的逻辑。
{
public ScoreListViewModel()
{
this.StudentList = StudentService.RetrieveStudentList();
this.SelectedStudent = this.StudentList[0];
}
public ScoreListView View { get; set; }
private Student selectedStudent;
public Student SelectedStudent
{
get
{
return this.selectedStudent;
}
set
{
if (this.selectedStudent != value)
{
this.selectedStudent = value;
OnPropertyChanged("SelectedStudent");
}
}
}
}
这种设计思想是我在实际编程中自己琢磨出来的,事后在Prism的codeplex论坛上发现之前就已经有人这么实现了。真是英雄所见略同啊!因为这种设计的适用性是很广的,所以我将其总结为——
包氏波动思想定义:对于列表性控件(DataGrid、ListBox、ComboBox等等),以及像CheckBox、RadioButton这样的带有选项集合的控件,它们都具有类似SelectedItem这样的属性,我们可以在MVP模式中绑定这些属性,以监视选择项的变化。
接下来的章节我将分别展示这些控件的另类绑定方式,以证实包氏波动思想的伟大价值。
(二)ListBox
将上面例子中的DataGrid换为ListBox就可以了,其它地方无需任何改变。
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=UserName}" Width="40" />
<TextBlock Text="{Binding Path=Score}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
代码下载: WpfApplication7_3.zip
(三)CheckBox
CheckBox中有一个属性IsChecked,我们只要监视着该属性的波动,就可以了。
代码下载: WpfApplication7_4.zip
(四)RadioButton
这个实现起来比较费事,细节请参见Clingingboy的文章:《WPF and SL RadioButtonList Tip》。
这个土人居然没给出个Demo,我只好自己动手丰衣足食,代码下载: WpfTestRadioButton.zip
但是我们发现,这个例子太简单了,只是2个性别“男”和“女”的选择,如果用CheckBox也是可以模拟出来的。
于是,在此基础上,我试着添加了第3性“女博士”,来扩展RadionButton的应用。
代码下载: WpfTestRadioButton_extension.zip
(五)ComboBox
这个控件的波动思想,在WPF中实现起来比较简单。
代码下载: WpfTestComboBox.zip
注:这个控件玩起来有时候比较烦,就是当下拉列表中有一行默认空白选项时,我们会在《最复杂的MVVM模式》一文中遇到这一场景。
(六)总结
最常用的就是这几种了,也是最典型的几种。其它列表控件的绑定方式均可依样画葫芦,我这里就不多讲了。
对于列表控件,究竟是使用AttachedBehavior,还是使用“包氏波动思想”(继续陶醉中),我的取舍是后者,只有在不能用波动思想的时候,才会考虑AttachedBehavior。波动思想俨然是基于数据的,这和MVP模式将数据从UI中剥离不谋而合;而AttachedBehavior则是传统Event编程模型的变形,我一直认为它是Event和Command妥协的产物,尤其在描述数据上,是远远不如包氏波动思想的。
哈哈,老包卖瓜,自卖自夸,不管这种思想是不是姓包,我们都要养成“基于数据编程”的习惯,而不再是“基于控件编程”。
这是一种境界的提升。