二十三:采用用DataTemplate实现CheckListBox的CustomControl

(感谢Microsoft公司的Ocean Ju提供本文章的思路)。
  创建CustomControl的步骤我就不再累述,不清楚的请参考综合应用WPF/WCF/WF/LINQ之三:采用用代码创建的方式实现CheckListBox的CustomControl

  为了方便大家学习,请单击此处下载该程序的代码。注意:代码中的GetProperty、GetControl等为扩展方法,具体代码请参考源代码。
  这次Themes\CheckListBox.xaml的内容为:
    1 <ResourceDictionary
    2    xmlns=" [url]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
    3    xmlns:x=" [url]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
    4    xmlns:local="clr-namespace:Eallies.OA.UI.Controls.Common">
    5
    6     <local:CheckListBoxItemConverter x:Key="CheckListBoxItemConverter" />
    7
    8     <Style TargetType="{x:Type local:CheckListBox}" BasedOn="{StaticResource {x:Type ListBox}}">
    9         <Setter Property="ItemTemplate">
   10             <Setter.Value>
   11                 <DataTemplate>
   12                     <CheckBox Name="chkCheckBox">
   13                         <CheckBox.Tag>
   14                             <MultiBinding Converter="{StaticResource CheckListBoxItemConverter}">
   15                                 <MultiBinding.Bindings>
   16                                     <Binding />
   17                                     <Binding Path="ItemValuePath" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CheckListBox}}" />
   18                                 </MultiBinding.Bindings>
   19                             </MultiBinding>
   20                         </CheckBox.Tag>
   21                         <CheckBox.Content>
   22                             <MultiBinding Converter="{StaticResource CheckListBoxItemConverter}">
   23                                 <MultiBinding.Bindings>
   24                                     <Binding />
   25                                     <Binding Path="ItemContentPath" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CheckListBox}}" />
   26                                 </MultiBinding.Bindings>
   27                             </MultiBinding>
   28                         </CheckBox.Content>
   29                     </CheckBox>
   30                 </DataTemplate>
   31             </Setter.Value>
   32         </Setter>
   33     </Style>
   34
   35 </ResourceDictionary>
  我们的思路是:具体Binding哪个字段可以用ItemValuePath和ItemContentPath这两个字段来配置,而根据字段名来取值则采用反射的方法。为了实现这个思路,我们需要使用Binding的Converter技术。这里需要传入两个参数,一个是当前Item,一个是字段名,因此我们采用MultiBinding技术。该Converter类的代码如下:
    1     public class CheckListBoxItemConverter : IMultiValueConverter
    2     {
    3         #region IMultiValueConverter Members
    4
    5         public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    6         {
    7             try
    8             {
    9                 object item = values[0];
   10                 string name = values[1] as string;
   11
   12                 return item.GetProperty(name).GetValue(item, null);
   13             }
   14             catch
   15             {
   16                 throw;
   17             }
   18         }
   19
   20         public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
   21         {
   22             throw new NotSupportedException("Not supported.");
   23         }
   24
   25         #endregion
   26     }
  而这两个字段名,则可以采用DependencyProperty技术来实现:
    1         public string ItemValuePath
    2         {
    3             get { return (string)GetValue(ItemValuePathProperty); }
    4             set { SetValue(ItemValuePathProperty, value); }
    5         }
    6
    7         public static readonly DependencyProperty ItemValuePathProperty =
    8             DependencyProperty.Register("ItemValuePath", typeof(string), typeof(CheckListBox));
    9
   10         public string ItemContentPath
   11         {
   12             get { return (string)GetValue(ItemContentPathProperty); }
   13             set { SetValue(ItemContentPathProperty, value); }
   14         }
   15
   16         public static readonly DependencyProperty ItemContentPathProperty =
   17             DependencyProperty.Register("ItemContentPath", typeof(string), typeof(CheckListBox));
  至此,我们已经能够实现对CheckListBox控件的数据绑定了。
  但还不够,我们需要处理CheckBox的Checked和Unchecked事件。为了处理这个问题,我们采用EventManager.RegisterClassHandler方法来注册CheckBox的CheckedEvent和UncheckedEvent。这里需要注意的是:如果界面上有两个以上的CheckListBox控件,则两个控件中的OnChecked和OnUnchecked事件都会触发,因此,我们需要做一个判断:if (sender.Equals(this) == false) return;
    1         public CheckListBox()
    2         {
    3             EventManager.RegisterClassHandler(typeof(CheckListBox), CheckBox.CheckedEvent, new RoutedEventHandler(OnChecked));
    4             EventManager.RegisterClassHandler(typeof(CheckListBox), CheckBox.UncheckedEvent, new RoutedEventHandler(OnUnchecked));
    5         }
    6
    7         private void OnChecked(object sender, RoutedEventArgs e)
    8         {
    9             try
   10             {
   11                 if (sender.Equals(this) == false) return;
   12
   13                 this._CheckedValues.Add((e.OriginalSource as CheckBox).Tag.ToType<int>());
   14             }
   15             catch
   16             {
   17                 throw;
   18             }
   19         }
   20
   21         private void OnUnchecked(object sender, RoutedEventArgs e)
   22         {
   23             try
   24             {
   25                 if (sender.Equals(this) == false) return;
   26
   27                 this._CheckedValues.Remove((e.OriginalSource as CheckBox).Tag.ToType<int>());
   28             }
   29             catch
   30             {
   31                 throw;
   32             }
   33         }
  至此,剩下的问题就只有解决为CheckBox控件赋值的问题了。
    1         public void SetIsChecked(int index, bool value)
    2         {
    3             try
    4             {
    5                 (this.GetControl("chkCheckBox", this.ItemValuePath, index) as CheckBox).IsChecked = value;
    6             }
    7             catch
    8             {
    9                 throw;
   10             }
   11         }

你可能感兴趣的:(职场,休闲,DataTemplate,CheckListBox,CustomControl)