WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox
一.前言
申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接。
本文主要内容:
- 下拉选择控件ComboBox的自定义样式及扩展;
- 自定义多选控件MultiComboBox;
二.下拉选择控件ComboBox的自定义样式及扩展
2.1基本样式
先看看基础效果图:
从功能上ComboBox有两种状态:
-
- 可编辑文本;
- 不可编辑文本。
从XAML的逻辑树结构上看,分为几个部分:
- 显示当前内容的区域;
- 下拉按钮,一般使用ToggleButton;
- 弹出的下拉选项列表,使用Popup作为容器;
样式定义代码:
<!--下拉条目样式--> <Style TargetType="ComboBoxItem" x:Key="ComboBoxItemStyle"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" /> <Setter Property="BorderThickness" Value="0" /> <Setter Property="Height" Value="28" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ComboBoxItem"> <Grid Background="{TemplateBinding Background}" Margin="0,0.5"> <Border x:Name="ItemBackground" IsHitTestVisible="False" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" /> <ContentPresenter x:Name="contentPresenter" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="ItemBackground" Property="Background" Value="{StaticResource ItemSelectedBackground}" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="ItemBackground" Property="Background" Value="{StaticResource ItemMouseOverBackground}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--水印:local:ControlAttachProperty.Watermark--> <!--Label区域:local:ControlAttachProperty.LabelTemplate ,local:ControlAttachProperty.Label--> <!--附加内容区域:local:ControlAttachProperty.AttachContent--> <!--圆角:local:ControlAttachProperty.CornerRadius--> <!--local:ControlAttachProperty.MouseOverBorderBrush--> <!--local:ControlAttachProperty.FocusBorderBrush--> <!--local:ControlAttachProperty.FocusBackground--> <Style TargetType="{x:Type ComboBox}" x:Key="DefaultComboBox"> <Setter Property="Height" Value="30" /> <Setter Property="Width" Value="200" /> <Setter Property="Foreground" Value="{StaticResource TextForeground}" /> <Setter Property="Background" Value="{StaticResource TextBackground}" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" /> <Setter Property="local:ControlAttachProperty.FocusBackground" Value="{StaticResource FocusBackground}" /> <Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" /> <Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" /> <Setter Property="FontFamily" Value="{StaticResource FontFamily}" /> <Setter Property="FontSize" Value="{StaticResource FontSize}" /> <Setter Property="ItemContainerStyle" Value="{StaticResource ComboBoxItemStyle}" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="MaxDropDownHeight" Value="400" /> <Setter Property="ScrollViewer.CanContentScroll" Value="False" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ComboBox}"> <Grid x:Name="PART_Root"> <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" /> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="21" /> </Grid.ColumnDefinitions> <!--Label区域--> <ContentControl x:Name="Label" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}" IsTabStop="False" IsHitTestVisible="False" Content="{TemplateBinding local:ControlAttachProperty.Label}" Margin="1,1,0,1"/> <!--附加内容区域--> <Border x:Name="PART_AttachContent" Panel.ZIndex="2" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" > <ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" /> </Border> <!--下拉按钮--> <ToggleButton x:Name="PART_DropDownToggle" IsTabStop="False" Style="{StaticResource ComboToggleButton}" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="1" Grid.ColumnSpan="3" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}" Background="{TemplateBinding local:ControlAttachProperty.FocusBackground}"/> <!--水印--> <Border Grid.Column="1"> <TextBlock x:Name="Message" Padding="0" Visibility="Collapsed" Text="{TemplateBinding local:ControlAttachProperty.Watermark}" Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="{StaticResource WatermarkOpacity}" HorizontalAlignment="Left" TextAlignment="Center" VerticalAlignment="Center" Margin="5,2,5,2" /> </Border> <!--主内容区域--> <Grid Grid.Column="1" x:Name="ContentSite" Margin="2 0 0 0" > <ContentPresenter x:Name="PART_SelectedItem" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="Stretch" Margin="2,0,2,0" IsHitTestVisible="False" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> <!--文本编辑--> <TextBox x:Name="PART_EditableTextBox" Style="{StaticResource EditableTextBoxStyle}" Visibility="Collapsed" HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="True" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" IsReadOnly="{TemplateBinding IsReadOnly}" FontFamily="{TemplateBinding FontFamily}" Foreground="{TemplateBinding Foreground}" Text="{TemplateBinding Text}" FontSize="{TemplateBinding FontSize}" /> </Grid> </Grid> <!--弹出下拉控件--> <Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom"> <Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}"> <Border x:Name="PopupBorder" BorderThickness="{TemplateBinding BorderThickness}" HorizontalAlignment="Stretch" Height="Auto" BorderBrush="{TemplateBinding BorderBrush}" Background="{StaticResource PopupBackground}"> </Border> <ScrollViewer x:Name="DropDownScrollViewer" BorderThickness="0" Margin="1"> <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" /> </ScrollViewer> </Grid> </Popup> </Grid> <!--触发器--> <ControlTemplate.Triggers> <!--1.显示水印--> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value=""> <Setter TargetName="Message" Property="Visibility" Value="Visible" /> </DataTrigger> <!--编辑模式--> <Trigger Property="IsEditable" Value="True"> <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" /> <Setter TargetName="PART_SelectedItem" Property="Visibility" Value="Collapsed" /> <Setter TargetName="PART_DropDownToggle" Property="Grid.Column" Value="3" /> <Setter TargetName="PART_DropDownToggle" Property="Grid.ColumnSpan" Value="1" /> <Setter TargetName="PART_DropDownToggle" Property="Background" Value="Transparent" /> <Setter Property="IsTabStop" Value="false" /> <Setter TargetName="PART_DropDownToggle" Property="Focusable" Value="False" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsFocused" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsKeyboardFocusWithin" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
如果看过本系列前面的文章,对上面的代码就更容易理解了,为了方便支持水印、Label标签、清除内容功能扩展,在基础样式里加了额外的部分,在xaml中有注释说明。
2.2 Label标签样式
效果图:
在2.1的基础样式上扩展即可:
<!--ComboBox包含附加属性Label的样式 LabelComboBox --> <Style TargetType="{x:Type ComboBox}" x:Key="LabelComboBox" BasedOn="{StaticResource DefaultComboBox}"> <Setter Property="Width" Value="260"></Setter> <Setter Property="local:ControlAttachProperty.LabelTemplate" > <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Border Width="60" Background="{StaticResource TextLabelBackground}"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
使用示例:
<ComboBox Margin="5" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="选择性别" Style="{StaticResource LabelComboBox}" core:ControlAttachProperty.Watermark="水印" /> <ComboBox Margin="5" IsEditable="True" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="选择性别" Style="{StaticResource LabelComboBox}" core:ControlAttachProperty.Watermark="我收水3333333333333333333333印" /> <ComboBox Margin="5" IsEnabled="False" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="选择性别" Style="{StaticResource LabelComboBox}" SelectedIndex="3" />
2.3 扩展清除选中项/文本按钮样式
效果图:
同样,也是在2.1的基础样式上扩展:
<!--ComboBox包含清除Text按钮的样式 ClearButtonComboBox --> <Style TargetType="{x:Type ComboBox}" x:Key="ClearButtonComboBox" BasedOn="{StaticResource DefaultComboBox}"> <Setter Property="local:ControlAttachProperty.AttachContent"> <Setter.Value> <ControlTemplate> <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0" local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}}}" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}}, Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}" Margin="1,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--ComboBox包含附加属性Label,以及ClearText按钮的样式 LabelClearButtonComboBox --> <Style TargetType="{x:Type ComboBox}" x:Key="LabelClearButtonComboBox" BasedOn="{StaticResource DefaultComboBox}"> <Setter Property="Width" Value="280"></Setter> <Setter Property="local:ControlAttachProperty.LabelTemplate" > <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Border Width="60" Background="{StaticResource TextLabelBackground}"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock> </Border> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="local:ControlAttachProperty.AttachContent"> <Setter.Value> <ControlTemplate> <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0" local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}}}" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}}, Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}" Margin="0,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/> </ControlTemplate> </Setter.Value> </Setter> </Style>
使用示例:
<ComboBox Margin="5" IsEnabled="False" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="选择性别" Style="{StaticResource LabelClearButtonComboBox}" SelectedIndex="3" /> <ComboBox Margin="5" ItemsSource="{StaticResource items}" core:ControlAttachProperty.Label="选择性别" Style="{StaticResource ClearButtonComboBox}" core:ControlAttachProperty.Watermark="水印" />
三.自定义多选控件MultiComboBox
实际需求中,经常有多选的要求,基于ComboBox简单的实现了一个多选控件MultiComboBox。效果图:
在功能上,可以满足基本需求,实际功能还不完整的,可以根据自己的需求完善,后台C#代码:
/// <summary> /// MultiComboBox.xaml 的交互逻辑 /// </summary> [TemplatePart(Name = "PART_ListBox", Type = typeof(ListBox))] public partial class MultiComboBox : ComboBox { /// <summary> /// 获取选择项集合 /// </summary> public IList SelectedItems { get { return this._ListBox.SelectedItems; } } /// <summary> /// 设置或获取选择项 /// </summary> public new int SelectedIndex { get { return this._ListBox.SelectedIndex; } set { this._ListBox.SelectedIndex = value; } } private ListBox _ListBox; public override void OnApplyTemplate() { base.OnApplyTemplate(); this._ListBox = Template.FindName("PART_ListBox", this) as ListBox; this._ListBox.SelectionChanged += _ListBox_SelectionChanged; } void _ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { StringBuilder sb = new StringBuilder(); foreach (var item in this.SelectedItems) { sb.Append(item.ToString()).Append(";"); } this.Text = sb.ToString().TrimEnd(';'); } static MultiComboBox() { //OverridesDefaultStyleProperty.OverrideMetadata(typeof(MultiComboBox), new FrameworkPropertyMetadata(typeof(MultiComboBox))); } public MultiComboBox() { ListBox ls = new ListBox(); //ls.SelectedItems } public void SelectAll() { this._ListBox.SelectAll(); } public void UnselectAll() { this._ListBox.UnselectAll(); } }
样式上,也实现了同第二节一样的扩展,包括支持水印、Label标签、清除内容功能扩展,就不做具体介绍了,基础样式代码:
<!--多选项样式--> <Style x:Key="CheckItemStyle" TargetType="{x:Type ListBoxItem}" > <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}" > <Border x:Name="Border" Background="{TemplateBinding Background}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> <StackPanel Orientation="Horizontal" VerticalAlignment="Center"> <CheckBox IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"> <ContentPresenter Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> </CheckBox> </StackPanel> </Border> <ControlTemplate.Triggers> <!--<Trigger Property="IsSelected" Value="True"> <Setter TargetName="Border" Property="Background" Value="{StaticResource ItemSelectedBackground}" /> <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}" /> </Trigger>--> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Border" Property="Background" Value="{StaticResource ItemMouseOverBackground}" /> <Setter Property="Foreground" Value="{StaticResource ItemMouseOverForeground}" /> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="Border" Property="Opacity" Value="{StaticResource DisableOpacity}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--MultiComboBox普通样式--> <Style x:Key="DefaultMultiComboBox" TargetType="{x:Type local:MultiComboBox}"> <Setter Property="Height" Value="30" /> <Setter Property="Width" Value="200" /> <Setter Property="Foreground" Value="{StaticResource TextForeground}" /> <Setter Property="Background" Value="{StaticResource TextBackground}" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" /> <Setter Property="local:ControlAttachProperty.FocusBackground" Value="{StaticResource FocusBackground}" /> <Setter Property="local:ControlAttachProperty.FocusBorderBrush" Value="{StaticResource FocusBorderBrush}" /> <Setter Property="local:ControlAttachProperty.MouseOverBorderBrush" Value="{StaticResource MouseOverBorderBrush}" /> <Setter Property="FontFamily" Value="{StaticResource FontFamily}" /> <Setter Property="FontSize" Value="{StaticResource FontSize}" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="MaxDropDownHeight" Value="400" /> <Setter Property="ScrollViewer.CanContentScroll" Value="False" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:MultiComboBox}"> <Grid x:Name="PART_Root"> <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" /> <Grid x:Name="PART_InnerGrid" Margin="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="21" /> </Grid.ColumnDefinitions> <!--Label区域--> <ContentControl x:Name="Label" Template="{TemplateBinding local:ControlAttachProperty.LabelTemplate}" IsTabStop="False" IsHitTestVisible="False" Content="{TemplateBinding local:ControlAttachProperty.Label}" Margin="1,1,0,1"/> <!--附加内容区域--> <Border x:Name="PART_AttachContent" Panel.ZIndex="2" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" > <ContentControl VerticalAlignment="Center" VerticalContentAlignment="Center" Template="{TemplateBinding local:ControlAttachProperty.AttachContent}" /> </Border> <!--下拉按钮--> <ToggleButton x:Name="PART_DropDownToggle" Panel.ZIndex="1" IsTabStop="False" Style="{StaticResource ComboToggleButton}" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="1" Grid.ColumnSpan="3" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}" Background="{TemplateBinding local:ControlAttachProperty.FocusBackground}"/> <!--水印--> <Border Grid.Column="1"> <TextBlock x:Name="Message" Padding="0" Visibility="Collapsed" Text="{TemplateBinding local:ControlAttachProperty.Watermark}" Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="0.6" HorizontalAlignment="Left" TextAlignment="Center" VerticalAlignment="Center" Margin="5,2,5,2" /> </Border> <!--内容区--> <Grid Grid.Column="1" Margin="2 0 0 0"> <!--文本编辑--> <TextBox x:Name="PART_EditableTextBox" Style="{StaticResource EditableTextBoxStyle}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="True" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" IsReadOnly="{TemplateBinding IsReadOnly}" FontFamily="{TemplateBinding FontFamily}" Foreground="{TemplateBinding Foreground}" Text="{Binding Path=Text,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" /> </Grid> <!--弹出多选列表--> <Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" StaysOpen="False" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom"> <Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}"> <Border x:Name="PopupBorder" BorderThickness="{TemplateBinding BorderThickness}" HorizontalAlignment="Stretch" Height="Auto" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}"/> <ListBox x:Name="PART_ListBox" SelectionMode="Multiple" ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}" ItemTemplate="{TemplateBinding ItemTemplate}" MaxHeight="{TemplateBinding MaxDropDownHeight}" ItemContainerStyle="{StaticResource CheckItemStyle}"/> </Grid> </Popup> </Grid> </Grid> <!--触发器--> <ControlTemplate.Triggers> <!--1.显示水印--> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value=""> <Setter TargetName="Message" Property="Visibility" Value="Visible" /> </DataTrigger> <!--编辑模式--> <Trigger Property="IsEditable" Value="True"> <Setter TargetName="PART_DropDownToggle" Property="Grid.Column" Value="3" /> <Setter TargetName="PART_DropDownToggle" Property="Grid.ColumnSpan" Value="1" /> <Setter TargetName="PART_DropDownToggle" Property="Background" Value="Transparent" /> <Setter Property="IsTabStop" Value="false" /> <Setter TargetName="PART_DropDownToggle" Property="Focusable" Value="False" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.MouseOverBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsFocused" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsKeyboardFocusWithin" Value="True"> <Setter Property="BorderBrush" Value="{Binding Path=(local:ControlAttachProperty.FocusBorderBrush),RelativeSource={RelativeSource Self}}"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="PART_Root" Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--MultiComboBox包含清除Text按钮的样式 ClearButtonMultiComboBox --> <Style TargetType="{x:Type local:MultiComboBox}" x:Key="ClearButtonMultiComboBox" BasedOn="{StaticResource DefaultMultiComboBox}"> <Setter Property="local:ControlAttachProperty.AttachContent"> <Setter.Value> <ControlTemplate> <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0" local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}}}" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}}, Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}" Margin="1,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--MultiComboBox包含附加属性Label的样式 LabelMultiComboBox --> <Style TargetType="{x:Type local:MultiComboBox}" x:Key="LabelMultiComboBox" BasedOn="{StaticResource DefaultMultiComboBox}"> <Setter Property="Width" Value="260"></Setter> <Setter Property="local:ControlAttachProperty.LabelTemplate" > <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Border Width="60" Background="{StaticResource TextLabelBackground}"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--MultiComboBox包含附加属性Label,以及ClearText按钮的样式 LabelClearButtonMultiComboBox --> <Style TargetType="{x:Type local:MultiComboBox}" x:Key="LabelClearButtonMultiComboBox" BasedOn="{StaticResource DefaultMultiComboBox}"> <Setter Property="Width" Value="280"></Setter> <Setter Property="local:ControlAttachProperty.LabelTemplate" > <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Border Width="60" Background="{StaticResource TextLabelBackground}"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock> </Border> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="local:ControlAttachProperty.AttachContent"> <Setter.Value> <ControlTemplate> <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0" local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}}}" IsEnabled="{Binding Path=IsReadOnly,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MultiComboBox}}, Converter={x:Static local:XConverter.TrueToFalseConverter},Mode=OneWay}" Margin="0,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--默认样式--> <Style TargetType="{x:Type local:MultiComboBox}" BasedOn="{StaticResource DefaultMultiComboBox}"></Style>
使用实例:
<core:MultiComboBox Width="420" Margin="3" IsEditable="True" ItemsSource="{StaticResource itmes}" core:ControlAttachProperty.Label="分类:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource ClearButtonMultiComboBox}"/> <core:MultiComboBox Width="420" Margin="3" IsEditable="True" ItemsSource="{StaticResource itmes}" core:ControlAttachProperty.Label="分类:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelMultiComboBox}"/> <core:MultiComboBox Width="420" Margin="3" IsEditable="False" ItemsSource="{StaticResource itmes}" core:ControlAttachProperty.Label="分类:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelClearButtonMultiComboBox}"/> <core:MultiComboBox Width="420" Margin="3" IsEditable="True" ItemsSource="{StaticResource itmes}" IsReadOnly="True" SelectedIndex="3" core:ControlAttachProperty.Label="分类:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelClearButtonMultiComboBox}"/> <core:MultiComboBox Width="420" Margin="3" IsEditable="False" ItemsSource="{StaticResource itmes}" IsEnabled="False" core:ControlAttachProperty.Label="分类:" core:ControlAttachProperty.Watermark="...哈哈" Style="{StaticResource LabelClearButtonMultiComboBox}"/>
补充:EditableTextBoxStyle及ComboToggleButton样式代码:
<Style TargetType="{x:Type ToggleButton}" x:Key="ComboToggleButton"> <Setter Property="Foreground" Value="{StaticResource TextForeground}" /> <Setter Property="local:ControlAttachProperty.FIconSize" Value="18"/> <Setter Property="local:ControlAttachProperty.FIconMargin" Value="0,1,3,1"/> <Setter Property="local:ControlAttachProperty.FIcon" Value=""/> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ToggleButton}"> <Grid x:Name="Grid"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Border Background="{TemplateBinding Background}" x:Name="Bg" Grid.ColumnSpan="2" Margin="0,1,1,1" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Opacity="0.3"/> <TextBlock Grid.Column="1" x:Name="FIcon" FontSize="{Binding Path=(local:ControlAttachProperty.FIconSize),RelativeSource={RelativeSource TemplatedParent}}" Text="{TemplateBinding local:ControlAttachProperty.FIcon}" local:ControlAttachProperty.AllowsAnimation="{TemplateBinding IsChecked}" Foreground="{TemplateBinding Foreground}" Style="{StaticResource FIcon}" Margin="{TemplateBinding local:ControlAttachProperty.FIconMargin}"/> </Grid> <!--z触发器--> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Foreground" Value="{StaticResource MouseOverForeground}" /> <Setter Property="Opacity" TargetName="Bg" Value="0.55" /> </Trigger> <Trigger Property="IsPressed" Value="True"> <Setter Property="Foreground" Value="{StaticResource PressedForeground}" /> <Setter Property="Opacity" TargetName="Bg" Value="0.6" /> </Trigger> <Trigger Property="IsChecked" Value="True"> <Setter Property="Foreground" Value="{StaticResource PressedForeground}" /> <Setter Property="Opacity" TargetName="Bg" Value="0.6" /> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="Grid"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--编辑状态文本框样式--> <Style TargetType="{x:Type TextBox}" x:Key="EditableTextBoxStyle"> <Setter Property="Margin" Value="1"/> <Setter Property="Padding" Value="0"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Background" Value="{x:Null}"/> <Setter Property="MaxLength" Value="2048"/> <Setter Property="Foreground" Value="{StaticResource TextForeground}"/> <Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" /> <Setter Property="SelectionBrush" Value="{StaticResource TextSelectionBrush}" /> <Setter Property="FontSize" Value="{StaticResource FontSize}"></Setter> <Setter Property="FontFamily" Value="{StaticResource FontFamily}"></Setter> <Setter Property="Focusable" Value="True"/> <Setter Property="CaretBrush" Value="{StaticResource TextForeground}" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="SnapsToDevicePixels" Value="True"></Setter> <Style.Triggers> <Trigger Property="IsReadOnly" Value="True"> <Setter Property="Opacity" Value="{StaticResource ReadonlyOpacity}"></Setter> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Opacity" Value="{StaticResource DisableOpacity}"></Setter> </Trigger> </Style.Triggers> </Style>
附录:参考引用
WPF自定义控件与样式(1)-矢量字体图标(iconfont)
WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展
WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式
WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展
WPF自定义控件与样式(6)-ScrollViewer与ListBox自定义样式
WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式
版权所有,文章来源:http://www.cnblogs.com/anding
个人能力有限,本文内容仅供学习、探讨,欢迎指正、交流。