ListBox复选框拓展
Toolkit的LongListMutiSelector的复选框功能,想必许多人都需要吧!然而系统本身控件ListBox虽然也有多选功能,可是外观上却缺乏复选框,选择效果只是颜色变化。于是在上一个项目中只好选择LongListMutiSeletor作为列表的控件,项目结束后就有个想法对ListBox进行拓展,使ListBox列表可以拥有复选框。
之前为了修改LongListMutiSelector在白色背景下滚动条无法显示的问题,曾经仔细看了一下LongListMutiSelector相关的一些模版,发现LongListMutiSelector的复选框其实来自LongListMutiSelectorItem模版中的Checkbox。于是心中就有个想法,对ListBox的模版进行修改添加上Checkbox,然后再绑定上ListBox本身IsSelected属性,这样就可以实现复选框了。
说做就做,首先对模版进行拓展,添加Checkbox。
<Style TargetType="control:ListBoxItemEx"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="BorderBrush" Value="Transparent"/> <Setter Property="Padding" Value="0"/> <Setter Property="HorizontalContentAlignment" Value="Left"/> <Setter Property="VerticalContentAlignment" Value="Top"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="control:ListBoxItemEx"> <Border x:Name="LayoutRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/> </ObjectAnimationUsingKeyFrames> <DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ContentContainer"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="SelectionStates"> <VisualState x:Name="Unselected"/> <VisualState x:Name="Selected"> <Storyboard> <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/> </ObjectAnimationUsingKeyFrames>--> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"/> </VisualStateManager.VisualStateGroups> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <CheckBox x:Name="checkBox" Grid.Column="0" IsChecked="{TemplateBinding IsSelected}" Visibility="Collapsed"/> <ContentControl x:Name="ContentContainer" Grid.Column="1" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
其次,再对ListBox进行继承拓展。增加SelectionEable属性,当属性更改显示或隐藏复选框。
public ItemSelectionMode SelectionEable { get { return (ItemSelectionMode)GetValue(SelectionEableProperty); } set { SetValue(SelectionEableProperty, value); } } public static readonly DependencyProperty SelectionEableProperty = DependencyProperty.Register( "SelectionEable", typeof(ItemSelectionMode), typeof(ListBoxItemEx), new PropertyMetadata(ItemSelectionMode.Normal, OnSelectionEableChanged)); private static void OnSelectionEableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ListBoxItemEx item = d as ListBoxItemEx; if (item.checkBox != null) { ItemSelectionMode mode = (ItemSelectionMode)e.NewValue; switch (mode) { case ItemSelectionMode.Normal: item.checkBox.Visibility = Visibility.Collapsed; break; case ItemSelectionMode.Selection: item.checkBox.Visibility = Visibility.Visible; break; } } }
Ok在页面前台写下以下代码,就会发现设计视图中的ListBoxItem有了复选框。
<MyControls:ListBoxItemEx SelectionEable="Selection"> 测试选项 </MyControls:ListBoxItemEx>
拓展完ListBoxItem后事情还没完,这只是ListBoxItem有了复选框,ListBox并没有,还要对ListBox进行拓展才行。
同样拓展一个SlectionEable属性,并且将该属性和它的Item的SelectonEable属性关联起来。其次还得重载ListBox的GetContainerForItemOverride方法,返回一个重载后的ListBoxItemEx对象作为列表生产每一项内容的承载容器。这样就完成了对ListBox复选框的拓展。
ps:实际测试中发现复选框的IsChecked属性和ListBoxItem的IsSelected属性并没有同步,后面仔细查看文档后发现TemplateBinding并不能进行双向绑定,即前台Checkbox的勾选变化不会同步到IsSelected属性,而只有Binding和StaticResource可以进行双向绑定,于是将TemplateBinding改为Binding,Mode为TwoWay,这样就可以双向绑定了。