CheckListBox的实现方式分析

 

  实际项目中常常要实现有CheckBox列表框。但是WPF没有自带这样的一个控件,下面就用Style来实现这样的功能。而对于CheckBox列表框,又常常会有一个Select AllCheckBox来表示当前列表框的选择状态。这个功能也会被包含在下面的示例之中。效果如下图所示。

 

对于单纯的,没有后台数据绑定的情况下,这个功能可以用ItemContainerStyle来实现。代码如下: 

 

CheckListBoxItemContainerStyle 

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><Style x:Key="CheckListBoxItemContainerStyle"
       TargetType="{x:Type ListBoxItem}">
  <!--Set it un-focusable, becaues the CheckBox in it should be focusable and only it.-->
  <Setter Property="Focusable" Value="False"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ListBoxItem}">
        <CheckBox Content="{TemplateBinding Content}"
              ContentTemplate="{TemplateBinding ContentTemplate}"
              ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
              IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
CheckListBoxItemContainerStyle

 

其中要对ContentContentTemplate等属性进行绑定,以方便对其进行扩展,保证其通用性。这个Style一般会放在Application级别的Resource中。

对于有后台数据绑定的情况,一般会有双个属性要绑定,一个是CheckBox里的Content,一个是CheckBoxIsChecked。绑定的路径,只有在用一个StyleListBox那里才知道,所以并不能写在这个Style里,否则会破坏这个Style的通用性。比较合理的方式是基于这个现有的Style进行修改。

 

对于下面的数据类。

DataItem Class
public   class  DataItem : INotifyPropertyChanged {      private   string  name;      private   bool  isEnabled;
    
public   string  Name     {          get  {  return  name; }          set         {             name  =  value;             OnPropertyChanged( " Name " );         }     }
    
public   bool  IsEnabled     {          get  {  return  isEnabled; }          set         {             isEnabled  =  value;             OnPropertyChanged( " IsEnabled " );         }     }
    
#region  INotifyPropertyChanged Members
    
public   event  PropertyChangedEventHandler PropertyChanged;
    
#endregion
    
protected   virtual   void  OnPropertyChanged( string  propertyName)     {         PropertyChangedEventHandler temp  =  PropertyChanged;          if  (temp  !=   null )         {             temp( this new  PropertyChangedEventArgs(propertyName));         }     } }

 

 

我们需要下面这个有针对性的Style来应用数据绑定。

DataItemCheckListBoxStyle 

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><Style x:Key="DataItemCheckListBoxStyle"
       TargetType="{x:Type ListBox}"
       BasedOn="{StaticResource {x:Type ListBox}}">
  <Setter Property="ItemTemplate">
    <Setter.Value>
      <DataTemplate>
        <TextBlock Text="{Binding Name}"/>
      </DataTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="ItemContainerStyle">
    <Setter.Value>
      <Style TargetType="{x:Type ListBoxItem}"
             BasedOn="{StaticResource CheckListBoxItemContainerStyle}">
        <Setter Property="IsSelected"
                Value="{Binding IsEnabled}"/>
        <Setter Property="Margin" Value="2,2,0,0"/>
      </Style>
    </Setter.Value>
  </Setter>
  <Setter Property="SelectionMode" Value="Multiple"/>
</Style>
DataItemCheckListBoxStyle

 

在上面的Style中,使用了ItemTemplate来指定CheckBox里的Content绑定到的属性,并把ListBoxItemIsSelected绑定数据的相应属性上。由于这个Style是针对特定数据写的,所以应当放置在使用这个StyleListBox所在的WindowResource中。

 

当然,也可以为ListBox添加两个绑定类型的Attached Property来实现一个通用的Style。不过这个Property一样要在使用的地方设置,其实没有太大区别。有兴趣的读者可以自己试一下。

 

对于Select All这个CheckBox而言,用Attached Property倒是很方便。给CheckBox添加一个SyncTarget属性指向要同步的ListBox,就可以在Window.xaml.cs之外的地方同步CheckBoxListBox了。代码如下:

ToggleButtonProperty 

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class ToggleButtonProperty
{
    // Using a DependencyProperty as the backing store for SyncTarget.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SyncTargetProperty =
        DependencyProperty.RegisterAttached("SyncTarget", typeof(ListBox), typeof(ToggleButtonProperty), new UIPropertyMetadata(new PropertyChangedCallback(OnSyncTargetChanged)));

    public static ListBox GetSyncTarget(DependencyObject obj)
    {
        return obj.GetValue(SyncTargetProperty) as ListBox;
    }

    public static void SetSyncTarget(DependencyObject obj, ListBox value)
    {
        obj.SetValue(SyncTargetProperty, value);
    }

    private static void OnSyncTargetChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ToggleButton checker = sender as ToggleButton;
        if (checker == null)
        {
            throw new InvalidOperationException("SyncTarget property only works on ToggleButton.");
        }

        ListBox targetList = e.NewValue as ListBox;
        if (targetList == null)
        {
            throw new InvalidOperationException("Sync target must be a ListBox.");
        }

        //TODO: Un-subscribe OldValue's Event.

        checker.Checked += (s, a) =>
        {
            targetList.SelectAll();
        };

        checker.Unchecked += (s, a) =>
        {
            targetList.UnselectAll();
        };

        targetList.SelectionChanged += (s, a) =>
        {
            checker.IsChecked = targetList.SelectedItems.Count == 0 ? false :
                targetList.SelectedItems.Count == targetList.Items.Count ? (bool?)true : null;
        };
    }
}
ToggleButtonProperty

 

使用方式也很简单。如下代码所示。

用法

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><DockPanel Margin="12">
    <CheckBox Content="Select All"
              Margin="0,0,0,5"
              DockPanel.Dock="Top"
              ext:ToggleButtonProperty.SyncTarget="{Binding ElementName=checkListBox}"/>
    <ListBox x:Name="checkListBox"
             Style="{StaticResource DataItemCheckListBoxStyle}"
             ItemsSource="{Binding Path=Items, ElementName=mainWindow}"/>
</DockPanel>
用法

 

完整的项目文件可以从这里下载

 

转载至http://www.cnblogs.com/nankezhishi/archive/2009/12/30/checkablelistbox.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值