实现CheckListBox的方法很多。我们可以直接在XAML文件中的ListBox控件中,嵌入CheckBox控件。但更多的时候,我们还是希望能把它编写成一个CustomControl以方便直接使用。
  以我们的Eallies OA系统为例,实现CheckListBox的CustomControl的方法如下:
  1、在Eallies.OA.UI.Controls.Common项目中添加一个CustomControl的项目,并让其继承于System.Windows.Controls.ListBox类。
    1  using System;
    2  using System.Collections;
    3  using System.Collections.Generic;
    4  using System.Linq;
    5  using System.Text;
    6  using System.Windows;
    7  using System.Windows.Controls;
    8  using System.Windows.Data;
    9  using System.Windows.Documents;
   10  using System.Windows.Input;
   11  using System.Windows.Media;
   12  using System.Windows.Media.Imaging;
   13  using System.Windows.Navigation;
   14  using System.Windows.Shapes;
   15 
   16  namespace Eallies.OA.UI.Controls.Common
   17 {
   18     public class CheckListBox : ListBox
   19     {
   20         static CheckListBox()
   21         {
   22             DefaultStyleKeyProperty.OverrideMetadata( typeof( CheckListBox), new FrameworkPropertyMetadata( typeof( CheckListBox)));
   23         }
   24     }
   25 }
  2、Themes目录下会自动生成Generic.xaml文件。为了不致于这个文件太过复杂,我们将关于CheckListBox的内容独立出来。在Themes目录下加入一个Resource Dictionary的项目,并更改其内容。
    1  < ResourceDictionary
    2    xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3    xmlns : x ="http://schemas.microsoft.com/winfx/2006/xaml"
    4    xmlns : local ="clr-namespace:Eallies.OA.UI.Controls.Common">
    5 
    6      < Style TargetType ="{ x : Type local : CheckListBox }" BasedOn ="{ StaticResource { x : Type ListBox }}" />
    7 
    8  </ ResourceDictionary >
  3、Themes目录下的Generic.xaml文件也需要做一些修改。
    1  < ResourceDictionary
    2    xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3    xmlns : x ="http://schemas.microsoft.com/winfx/2006/xaml"
    4    xmlns : local ="clr-namespace:Eallies.OA.UI.Controls.Common">
    5 
    6      < ResourceDictionary.MergedDictionaries >
    7          < ResourceDictionary Source ="/Eallies.OA.UI.Controls.Common;component/Themes/CheckListBox.xaml" />
    8      </ ResourceDictionary.MergedDictionaries >
    9 
   10  </ ResourceDictionary >
  4、之后,我们就可以为这个CustomControl添加自定义的内容了。CheckListBox控件需要一个用于保存列表项的属性,幸运的是,DataContext属性可以完成这点;它还需要一个用于保存已选择的列表项的属性,因此我们添加一个CheckedItems属性;为了支持通过DataContext属性或者直接AddItem的方法添加列表项,我们增加了OnPropertyChanged、AddItem、AddCheckedItem等方法。
    1  using System;
    2  using System.Collections;
    3  using System.Collections.Generic;
    4  using System.Linq;
    5  using System.Text;
    6  using System.Windows;
    7  using System.Windows.Controls;
    8  using System.Windows.Data;
    9  using System.Windows.Documents;
   10  using System.Windows.Input;
   11  using System.Windows.Media;
   12  using System.Windows.Media.Imaging;
   13  using System.Windows.Navigation;
   14  using System.Windows.Shapes;
   15  using Eallies.OA.Utility;
   16 
   17  namespace Eallies.OA.UI.Controls.Common
   18 {
   19     public class CheckListBox : ListBox
   20     {
   21         private Dictionary< int, CheckListItem> _Items = new Dictionary< int, CheckListItem>();
   22         private Dictionary< int, CheckListItem> _CheckedItems = new Dictionary< int, CheckListItem>();
   23 
   24         static CheckListBox()
   25         {
   26             DefaultStyleKeyProperty.OverrideMetadata( typeof( CheckListBox), new FrameworkPropertyMetadata( typeof( CheckListBox)));
   27         }
   28 
   29          #region Public Properties
   30 
   31         public Dictionary< int, CheckListItem> CheckedItems
   32         {
   33             get { return this._CheckedItems; }
   34             set { this._CheckedItems = value; }
   35         }
   36 
   37          #endregion
   38 
   39         protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e)
   40         {
   41             try
   42             {
   43                 if (e.Property.Name != "ItemsSource" && e.Property.Name != "DataContext")
   44                 {
   45                     base.OnPropertyChanged(e);
   46                 }
   47 
   48                 if (e.Property.Name == "DataContext")
   49                 {
   50                     this._Items = e.NewValue as Dictionary< int, CheckListItem>;
   51                 }
   52             }
   53             catch
   54             {
   55                 throw;
   56             }
   57         }
   58 
   59         public void AddItem( bool ischecked, string content, int value)
   60         {
   61             try
   62             {
   63                 this._Items.Add(value, new CheckListItem(ischecked, content, value));
   64 
   65                 if (ischecked == true)
   66                 {
   67                     this._CheckedItems.Add(value, new CheckListItem( true, content, value));
   68                 }
   69             }
   70             catch
   71             {
   72                 throw;
   73             }
   74         }
   75 
   76         public void AddCheckedItem( string content, int value)
   77         {
   78             try
   79             {
   80                 if ( this._CheckedItems.ContainsKey(value) == false)
   81                 {
   82                     this._CheckedItems.Add(value, new CheckListItem( true, content, value));
   83                 }
   84             }
   85             catch
   86             {
   87                 throw;
   88             }
   89         }
   90 
   91         public void Refresh()
   92         {
   93             try
   94             {
   95                 this.Items.Clear();
   96 
   97                 foreach ( CheckListItem item in this._Items.Values)
   98                 {
   99                     CheckBox checkbox = new CheckBox();
  100 
  101                     if ( this._CheckedItems.ContainsKey(item.Value) == true) checkbox.IsChecked = true;
  102                     if ( this._CheckedItems.ContainsKey(item.Value) != true) checkbox.IsChecked = false;
  103                     checkbox.Content = item.Content;
  104                     checkbox.Tag = item.Value;
  105                     checkbox.Checked += new RoutedEventHandler(CheckBox_Checked);
  106                     checkbox.Unchecked += new RoutedEventHandler(CheckBox_Unchecked);
  107 
  108                     this.Items.Add(checkbox);
  109                 }
  110             }
  111             catch
  112             {
  113                 throw;
  114             }
  115         }
  116 
  117         private void CheckBox_Checked( object sender, RoutedEventArgs e)
  118         {
  119             try
  120             {
  121                 CheckBox checkbox = sender as CheckBox;
  122                 int key = checkbox.Tag.ToType< int>();
  123 
  124                 this._CheckedItems.Add(key, this._Items[key]);
  125             }
  126             catch
  127             {
  128                 throw;
  129             }
  130         }
  131 
  132         private void CheckBox_Unchecked( object sender, RoutedEventArgs e)
  133         {
  134             try
  135             {
  136                 CheckBox checkbox = sender as CheckBox;
  137                 int key = checkbox.Tag.ToType< int>();
  138 
  139                 this._CheckedItems.Remove(key);
  140             }
  141             catch
  142             {
  143                 throw;
  144             }
  145         }
  146 
  147          #region CheckListItem
  148 
  149         public class CheckListItem
  150         {
  151             private bool _IsChecked = false;
  152             private string _Content = string.Empty;
  153             private int _Value = -1;
  154 
  155             public CheckListItem( bool ischecked, string content, int value)
  156             {
  157                 this._IsChecked = ischecked;
  158                 this._Content = content;
  159                 this._Value = value;
  160             }
  161 
  162             public bool IsChecked
  163             {
  164                 get { return this._IsChecked; }
  165                 set { this._IsChecked = value; }
  166             }
  167 
  168             public string Content
  169             {
  170                 get { return this._Content; }
  171                 set { this._Content = value; }
  172             }
  173 
  174             public int Value
  175             {
  176                 get { return this._Value; }
  177                 set { this._Value = value; }
  178             }
  179         }
  180 
  181          #endregion
  182     }
  183 }
  5、现在我们可以在自己的项目中使用这个CustomControl了。首先需要更改XAML文件,添加引用:xmlns:common="clr-namespace:Eallies.OA.UI.Controls.Common;assembly=Eallies.OA.UI.Controls.Common",然后我们就可以使用这个控件了。
    1  < logical : PageBase
    2    xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3    xmlns : x ="http://schemas.microsoft.com/winfx/2006/xaml"
    4    xmlns : logical ="clr-namespace:Eallies.OA.UI.Controls.Logical;assembly=Eallies.OA.UI.Controls.Logical"
    5    xmlns : common ="clr-namespace:Eallies.OA.UI.Controls.Common;assembly=Eallies.OA.UI.Controls.Common"
    6    x : Class ="Eallies.OA.UI.User.Detail">
    7      < Grid >
    8          < Grid VerticalAlignment ="Top">
    9              < common : CheckListBox Margin ="0,0,0,0" Name ="lstRoles" Width ="180" Height ="180" HorizontalAlignment ="Left" VerticalAlignment ="Top" />
   10          </ Grid >
   11      </ Grid >
   12  </ logical : PageBase >
  6、后台操纵这个控件的代码就很简单了。注意如果采用AddItem的方式添加列表项,则添加完毕后需要调用Refresh方法。
    1         private void GetRoles()
    2         {
    3             RoleContractClient client = new RoleContractClient();
    4 
    5             try
    6             {
    7                 IList list = client.GetRoles();
    8 
    9                 if (list != null)
   10                 {
   11                     for ( int i = 0; i < list.Count; i++)
   12                     {
   13                         RoleInfo functionInfo = list[i] as RoleInfo;
   14 
   15                         this.lstRoles.AddItem( false, functionInfo.RoleName, functionInfo.RoleId);
   16                     }
   17                 }
   18 
   19                 this.lstRoles.Refresh();
   20             }
   21             catch
   22             {
   23                 throw;
   24             }
   25             finally
   26             {
   27                 client.Close();
   28             }
   29         }