基于WPF实现多选下拉控件的示例代码
wpF 实现多选下拉控件
框架使用.NET40
;
Visual Studio 2022
;
创建控件 MultiSelectComboBox
继承 ListBox
。
- 依赖属性
IsSelectAllActive
是否支持显示全选,默认false
。 - 依赖属性
SelectAllContent
全选控件的Content
,默认显示全选
。 - 依赖属性
Delimiter
分隔符,默认显示;
。 - 依赖属性
Text
显示选择的所有Item
。 - 其他与
ComboBox
依赖属性一致。
实现代码
1) MultiSelectComboBox.xaml
代码如下:
usingSystem; usingSystem.ComponentModel; usingSystem.Linq; usingSystem.Windows; usingSystem.Windows.Controls; usingSystem.W编程indows.Controls.Primitives; usingSystem.Windows.Input; usingSystem.Windows.Threading; namespaceWPFDevelopers.Controls { publicclassMultiSelectComboBox:ListBox { privateconststringPART_Popup="PART_Popup"; privateconststringPART_CheckBoxAll="PART_CheckBoxAll"; publicstaticreadonlyDependencyPropertyIsDropDownOpenProperty= DependencyProperty.Register("IsDropDownOpen",typeof(bool),typeof(MultiSelectComboBox), newPropertyMetadata(false)); publicstaticreadonlyDependencyPropertyMaxDropDownHeightProperty =DependencyProperty.Register("MaxDropDownHeight",typeof(double),typeof(MultiSelectComboBox), newPropertyMetadata(SystemParameters.PrimaryScreenHeight/3)); publicstaticreadonlyDependencyPropertySelectAllContentProperty= DependencyProperty.Register("SelectAllContent",typeof(object),typeof(MultiSelectComboBox), newPropertyMetadata("全选")); publicstaticreadonlyDependencyPropertyIsSelectAllActiveProperty= DependencyProperty.Register("IsSelectAllActive",typeof(bool),typeof(MultiSelectComboBox), newPropertyMetadata(false)); publicstaticreadonlyDependencyPropertyDelimiterProperty= DependencyProperty.Register("Delimiter",typeof(string),typeof(MultiSelectComboBox), newPropertyMetadata(";")); publicstaticreadonlyDependencyPropertyTextProperty= DependencyProperty.Register("Text",typeof(string),typeof(MultiSelectComboBox), newPropertyMetadata(string.Empty,OnTextChanged)); privatebool_ignoreTextValueChanged; privateMultiSelectComboBoxItem_multiSelectComboBoxItem; privatePopup_popup; publicboolIsDropDownOpen { get=>(bool)GetValue(IsDropDownOpenProperty); set=>SetValue(IsDropDownOpenProperty,value); } [Bindable(true)] [Category("Layout")] [TypeConverter(typeof(LengthConverter))] publicdoubleMaxDropDownHeight { get=>(double)GetValue(MaxDropDownHeightProperty); set=>SetValue(MaxDropDownHeightProperty,value); } publicobjectSelectAllContent { get=>GetValue(SelectAllContentProperty); set=>SetValue(SelectAllContentProperty,value); } publicboolIsSelectAllActive { get=>(bool)GetValue(IsSelectAllActiveProperty); set=>SetValue(IsSelectAllActiveProperty,value); } publicstringDelimiter { get=>(string)GetValue(DelimiterProperty); set=>SetValue(DelimiterProperty,value); } publicstringText { get=>(string)GetValue(TextProperty); set=>SetValue(TextProperty,value); } privatestaticvoidOnIsDropDownOpenChanged(DependencyObjectd,DependencyPropertyChangedEventArgse) { varMultiSelectComboBox=(MultiSelectComboBox)d; if(!(bool)e.NewValue) MultiSelectComboBox.Dispatcher.BeginInvoke(newAction(()=>{Mouse.Capture(null);}), DispatcherPriority.Send); } privatestaticvoidOnTextChanged(DependencyObjectd,DependencyPropertyChangedEventArgse) { } protectedoverrideboolIsItemItsOwnContainerOverride(objectitem) { returnitemisMultiSelectComboBoxItem; } protectedoverrideDependencyObjectGetContainerForItemOverride() { returnnewMultiSelectComboBoxItem(); } protectedoverridevoidOnSelectionChanged(SelectionChangedEventArgse) { UpdateText(); base.OnSelectionChanged(e); } publicoverridevoidOnApplyTemplate() { base.OnApplyTemplate(); _popup=GetTemplateChild(PART_Popup)ASPopup; _multiSelectComboBoxItem=GetTemplateChild(PART_CheckBoxAll)asMultiSelectComboBoxItem; _multiSelectComboBoxItem.Selected+=_MultiSelectComboBoxItem_Selected; _multiSelectComboBoxItem.Unselected+=_MultiSelectComboBoxItem_Unselected; } privatevoid_MultiSelectComboBoxItem_Unselected(objectsender,RoutedEventArgse) { if(_ignoreTextValueChanged)return; _ignoreTextValueChanged=true; UnselectAll(); _ignoreTextValueChanged=false; UpdateText(); } privatevoid_MultiSelectComboBoxItem_Selected(objectsender,RoutedEventArgse) { if(_ignoreTextValueChanged)return; _ignoreTextValueChanged=true; SelectAll(); _ignoreTextValueChanged=false; UpdateText(); } protectedvirtualvoidUpdateText() { if(_ignoreTextValueChanged)return; varnewValue=string.Join(Delimiter,SelectedItems.Cast<object>().Select(x=>GetItemDisplayValue(x))); if(string.IsNullOrWhiteSpace(Text)||!Text.Equals(newValue)) { _ignoreTextValueChanged=true; if(_multiSelectComboBoxItem!=null) _multiSelectComboBoxItem.SetCurrentValue(IsSelectedProperty,SelectedItems.Count==Items.Count); SetCurrentValue(TextProperty,newValue); _ignoreTextValueChanged=false; } } protectedobjectGetItemDisplayValue(objectitem) { if(string.IsNullOrWhiteSpace(DisplayMemberPath)) { varproperty=item.GetType().GetProperty("Content"); if(property!=null) returnproperty.GetValue(item,null); } varnameParts=DisplayMemberPath.Split('.'); if(nameParts.Length==1) { varproperty=item.GetType().GetProperty(DisplayMemberPath); if(property!=null) returnproperty.GetValue(item,null); } returnitem; } } }
2) MultiSelectComboBoxItem.cs
代码如下:
usingSystem.Windows.Controls; namespaceWPFDevelopers.Controls { publicclassMultiSelectComboBoxItem:ListBoxItem { } }
3) MultiSelectComboBox.xaml
代码如下:
<ResourceDictionaryXMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:WPFDevelopers.Controls" xmlns:helpers="clr-namespace:WPFDevelopers.Helpers"> <ResourceDictionary.MergedDictionaries> <ResourceDictionarySource="Basic/ControlBasic.xaml"/> </ResourceDictionary.MergedDictionaries> <BooleanToVisibilityConverterx:Key="bool2VisibilityConverter"/> <Stylex:Key="DefaultMultiSelectComboBoxItem"TargetType="{x:Typecontrols:MultiSelectComboBoxItem}"> <SetterProperty="HorizontalContentAlignment"Value="{BindingHorizontalContentAlignment,RelativeSource={RelativeSourceAncestorType={x:TypeItemsControl}}}"/> <SetterProperty="VerticalContentAlignment"Value="{BindingVerticalContentAlignment,RelativeSource={RelativeSourceAncestorType={x:TypeItemsControl}}}"/> <SetterProperty="SnapsToDevicePixels"Value="True"/> <SetterProperty="Background"Value="Transparent"/> <SetterProperty="BorderBrush"Value="Transparent"/> <SetterProperty="Foreground"Value="{DynamicResourceRegularTextSolidColorBrush}"/> <SetterProperty="BorderThickness"Value="0"/> <SetterProperty="Height"Value="34"/> <SetterProperty="Margin"Value="1,0"/> <SetterProperty="Padding"Value="6,0"/> <SetterProperty="Cursor"Value="Hand"/> <SetterProperty="Template"> <Setter.Value> <ControlTemplateTargetType="{x:Typecontrols:MultiSelect编程客栈ComboBoxItem}"> <Borderx:Name="PART_Border" BorderBrush="{TemplateBindingBorderBrush}" BorderThickness="{TemplateBindingBorderThickness}" Background="{TemplateBindingBackground}" SnapsToDevicePixels="true" Padding="{TemplateBindingPadding}"> <CheckBoxForegrowww.devze.comund="{TemplateBindingForeground}" HorizontalAlignment="Stretch" VerticalAlignment="{TemplateBindingVerticalContentAlignment}" MinHeight="{TemplateBindingMinHeight}" Padding="{TemplateBindingPadding}" IsChecked="{BindingIsSelected,RelativeSource={RelativeSourceTemplatedParent},Mode=TwoWay}"> <ContentPresenterHorizontalAlignment="{TemplateBindingHorizontalContentAlignment}" VerticalAlignment="{TemplateBindingVerticalContentAlignment}" x:Name="PART_ContentPresenter" SnapsToDevicePixels="{TemplateBindingSnapsToDevicePixels}" TextElement.Foreground="{TemplateBindingForeground}"/> </CheckBox> </Border> <ControlTemplate.Triggers> <TriggerProperty="IsMouseover"Value="True"> <SetterProperty="Background"Value="{DynamicResourceDefaultBackgroundSolidColorBrush}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <StyleTargetType="{x:Typecontrols:MultiSelectComboBox}"> <SetterProperty="ScrollViewer.HorizontalScrollBarVisibility"Value="Auto"/> <SetterProperty="ScrollViewer.VerticalScrollBarVisibility"Value="Auto"/> <SetterProperty="ScrollViewer.CanContentScroll"Value="True"/> <SetterProperty="SelectionMode"Value="Multiple"/> <SetterProperty="MinWidth"Value="120"/> <SetterProperty="MinHeight"Value="{StaticResourceMinHeight}"/> <SetterProperty="Height"Value="{StaticResourceMinHeight}"/> <SetterProperty="ItemContainerStyle"Value="{StaticResourceDefaultMultiSelectComboBoxItem}"/> <SetterProperty="HorizontalContentAlignment"Value="Left"/> <SetterProperty="VerticalContentAlignment"Value="Center"/> <SetterProperty="BorderBrush"Value="{DynamicResourceBaseSolidColorBrush}"/> <SetterProperty="BorderThickness"Value="1"/> <SetterProperty="Background"Value="{DynamicResourceBackgroundSolidColorBrush}"/> <SetterProperty="Padding"Value="14.5,3,30,3"/> <SetterProperty="Template"> <Setter.Value> <ControlTemplateTargetType="{x:Typecontrols:MultiSelectComboBox}"> <ControlTemplate.Resources> <Storyboardx:Key="OpenStoryboard"> <DoubleAnimationStoryboard.TargetName="PART_DropDown" Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)" To="1"Duration="00:00:.2" EasingFunction="{StaticResourceExponentialEaseOut}"/> </Storyboard> <Storyboardx:Key="CloseStoryboard"> <DoubleAnimationStoryboard.TargetName="PART_DropDown" Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)" To="0"Duration="00:00:.2" EasingFunction="{StaticResourceExponentialEaseOut}"/> </Storyboard> </ControlTemplate.Resources> <controls:SmallPanelSnapsToDevicePixels="True"> <BorderName="PART_Border" Background="{TemplateBindingBackground}" BorderBrush="{TemplateBindingBorderBrush}" BorderThickness="{TemplateBindingBorderThickness}" SnapsToDevicePixels="True" CornerRadius="{BindingPath=(helpers:ElementHelper.CornerRadius),RelativeSource={RelativeSourceTemplatedParent}}"/> <ToggleButtonx:Name="PART_ToggleButton" Template="{StaticResourceComboBoxToggleButton}" Style="{x:Null}" Focusable="False" ClickMode="Release" IsChecked="{BindingIsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSourceTemplatedParent}}"/> <TextBoxName="PART_EditableTextBox" Template="{StaticResourceComboBoxTextBox}" HorizontalAlignment="{TemplateBindingHorizontalContentAlignment}" VerticalAlignment="{TemplateBindingVerticalContentAlignment}" Margin="{TemplateBindingPadding}" Focusable="True" Text="{BindingText,RelativeSource={RelativeSourceTemplatedParent},Mode=TwoWay}" Background="{TemplateBindingBackground}" SelectionBrush="{DynamicResourceWindowBorderBrushSolidColorBrush}" IsReadOnly="True"Style="{x:Null}"/> <Popupx:Name="PART_Popup" AllowsTransparency="True" PlacementTarget="{BindingElementName=PART_ToggleButton}" IsOpen="{BindingIsDropDownOpen,RelativeSource={RelativeSourceTemplatedParent},Mode=TwoWay}" Placement="Bottom"StaysOpen="False"> <controls:SmallPanelx:Name="PART_DropDown" MinWidth="{TemplateBindingFrameworkElement.ActualWidth}" Margin="24,2,24,24" MaxHeight="{TemplateBindingMaxDropDownHeight}" RenderTransformOrigin=".5,0" SnapsToDevicePixels="True"> <controls:SmallPanel.RenderTransform> <ScaleTransformScaleY="0"/> </controls:SmallPanel.RenderTransform> <Border Name="PART_DropDownBorder" Background="{TemplateBindingBackground}" BorderBrush="{TemplateBindingBorderBrush}" BorderThickness="{TemplateBindingBorderThickness}" SnapsToDevicePixels="True" CornerRadius="{BindingPath=(helpers:ElementHelper.CornerRadius),RelativeSource={RelativeSourceTemplatedParent}}" UseLayoutRounding="True" Effect="{StaticResourcePopupShadowDepth}"/> <GridClipToBounds="False" Margin="0,8"> <Grid.RowDefinitions> <RowDefinitionHeight="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <controls:MultiSelectComboBoxItemx:Name="PART_CheckBoxAll" Visibility="{TemplateBindingIsSelectAllActive,Converterandroid={StaticResourcebool2VisibilityConverter}}" Style="{TemplateBindingItemContainerStyle}" Content="{TemplateBindingSelectAllContent}"/> <ScrollViewerx:Name="DropDownScrollViewer"Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Auto"> <ItemsPresenterx:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigat编程客栈ion="Contained" SnapsToDevicePixels="{TemplateBindingSnapsToDevicePixels}"/> </ScrollViewer> </Grid> </controls:SmallPanel> </Popup> </controls:SmallPanel> <ControlTemplate.Triggers> <TriggerSourceName="PART_ToggleButton"Property="IsChecked"Value="True"> <Trigger.EnterActions> <BeginStoryboardx:Name="BeginStoryboardOpenStoryboard"Storyboard="{StaticResourceOpenStoryboard}"/> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboardBeginStoryboardName="BeginStoryboardOpenStoryboard"/> </Trigger.ExitActions> </Trigger> <TriggerSourceName="PART_ToggleButton"Property="IsChecked"Value="False"> <Trigger.EnterActions> <BeginStoryboardx:Name="BeginStoryboardCloseStoryboard"Storyboard="{StaticResourceCloseStoryboard}"/> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboardBeginStoryboardName="BeginStoryboardCloseStoryboard"/> </Trigger.ExitActions> </Trigger> <TriggerProperty="IsMouseOver"Value="True"> <SetterProperty="BorderBrush"TargetName="PART_Border"Value="{DynamicResourcePrimaryNormalSolidColorBrush}"/> </Trigger> <TriggerSourceName="PART_Popup"Property="AllowsTransparency"Value="True"> <SetterTargetName="PART_DropDownBorder"Property="Margin"Value="0,2,0,0"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
4) MultiSelectComboBoxExample.xaml
代码如下:
<UserControlx:Class="WPFDevelopers.Samples.ExampleViews.MultiSelectComboBoxExample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews" xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers" xmlns:controls="clr-namespace:WPFDevelopers.Samples.Controls" xmlns:model="clr-namespace:WPFDevelopers.Sample.Models" mc:Ignorable="d" d:DesignHeight="450"d:DesignWidth="800"> <UserControl.Resources> <model:HospitalListx:Key="myHospitalList"/> </UserControl.Resources> <开发者_开发培训;controls:CodeViewer> <UniformGridColumns="2"> <wpfdev:MultiSelectComboBox VerticalContentAlignment="Center" HorizontalAlignment="Center" Delimiter="^"Width="200"> <wpfdev:MultiSelectComboBoxItem>Option1</wpfdev:MultiSelectComboBoxItem> <wpfdev:MultiSelectComboBoxItem>Option2</wpfdev:MultiSelectComboBoxItem> <wpfdev:MultiSelectComboBoxItem>Option3</wpfdev:MultiSelectComboBoxItem> <wpfdev:MultiSelectComboBoxItem>Option4</wpfdev:MultiSelectComboBoxItem> <wpfdev:MultiSelectComboBoxItem>Option5</wpfdev:MultiSelectComboBoxItem> </wpfdev:MultiSelectComboBox> <wpfdev:MultiSelectComboBoxVerticalContentAlignment="Center" HorizontalAlignment="Center" IsSelectAllActive="True" ItemsSource="{BindingSource={StaticResourcemyHospitalList}}" DisplayMemberPath="DoctorName" SelectedValuePath="ID"Width="200"> </wpfdev:MultiSelectComboBox> </UniformGrid> <controls:CodeViewer.SourceCodes> <controls:SourceCodeModel CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/MultiSelectComboBoxExample.xaml" CodeType="Xaml"/> <controls:SourceCodeModel CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/MultiSelectComboBoxExample.xaml.cs" CodeType="CSharp"/> </controls:CodeViewer.SourceCodes> </controls:CodeViewer> </UserControl>
效果图
以上就是基于WPF实现多选下拉控件的示例代码的详细内容,更多关于WPF多选下拉控件的资料请关注我们其它相关文章!
精彩评论