虽然CodePlex上的WPF扩展的XXX ToolKit源码中有一个CheckListBox控件,但是,就看它那源代码,也过于复杂了。并且,我也希望自己来编写一个CheckListBox控件。
所谓CheckListBox控件嘛,就是既可以Select又可以Check的ListBox控件。有人会说,不用写控件,自定义一个ListBoxItem的模板就行了,也确实可以这样做,不过,还是有些问题的,如果只是重定义ListBoxItem的模板,那仅仅是为其UI上加了个可以显示一个“勾”的东东而已,而对于逻辑是没有任何变化。
既然要可以Select又能Check,那显然只是重定义模板是不行的。ListBoxItem类本身有一个IsSelected属性,指示列表项是否被选中,而且,人家在ListBox中也有一个SelectedItems属性,可以获得ListBox控件的当前选中的所有项。
很明显,我们的CheckableListBoxItem要有一个IsChecked属性来指示列表项是否被Check,而在CheckListBox控件上应当有一个CheckedItems属性,可以获取当前所有被Checked的项。
刚开始,我是计划让CheckableListBoxItem从ContentControl类派生,CheckListBox从ItemsControl派生。但是,转念一想,其实这所谓的可以Check的ListBox就是ListBox和CheckBox控件的结合体,而大多数功能与ListBox控件相似,是没有必要自己重新来写ListBox的功能,所以,后来我决定:CheckableListBoxItem从ListBoxItem类派生,CheckListBox则从ListBox派生,但其中的项目的容器已经不是ListBox了,而是我继承的CheckableListBoxItem类。
有一点我们要明确的,熟悉WPF的朋友都知道,在WPF/SL/WP/Store App这一堆使用XAML布局UI的开发框架中,列表控件所获出来的项并不是项的容器,除非你在ListBox中直接用ListBoxItem作为对象加进列表控件的集合中,不然会根据你添加的项返回对应的内容,如果你放进去的是String,那么拿出来也是String;你放进去的是int,拿出来的也是int。
至于说为什么要这样做嘛,很多人不解了,ListBox里面明明是放ListBoxItem的,怎么直接返回其对象了?WPF说的是啥?MVVM,既然要MVVM,当然是你在绑定了哪个对象,取出来还是那个对象好了,这样就方便了。
好了,理论的扯完了,就上代码吧。
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
namespace MyListBox
{
[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(CheckableListBoxItem))]
public class CheckListBox : ListBox
{
ObservableCollection<object> m_checkedItems = null;
Type m_itemContainerType = typeof(FrameworkElement);//项容器的类型
public CheckListBox()
{
m_checkedItems = new ObservableCollection<object>();
// 从CheckListBox类附加的特性中获取项目容器的类型
var attr = this.GetType().GetCustomAttributes(typeof(StyleTypedPropertyAttribute), false);
if (attr != null && attr.Length != 0)
{
StyleTypedPropertyAttribute sty = attr[0] as StyleTypedPropertyAttribute;
if (sty != null)
{
this.m_itemContainerType = sty.StyleTargetType;
}
}
}
public static DependencyProperty CheckedItemsProperty = DependencyProperty.Register("CheckedItems", typeof(IList), typeof(CheckListBo