开发者

基于WPF实现多选下拉控件的示例代码

wpF 实现多选下拉控件

框架使用.NET40

Visual Studio 2022;

创建控件 MultiSelectComboBox 继承 ListBox 。

  • 依赖属性 IsSelectAllActive 是否支持显示全选,默认 false 。
  • 依赖属性 SelectAllContent 全选控件的 Content,默认显示 全选 。
  • 依赖属性 Delimiter 分隔符,默认显示 ; 。
  • 依赖属性 Text 显示选择的所有 Item 。
  • 其他与ComboBox 依赖属性一致。

基于WPF实现多选下拉控件的示例代码

实现代码

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实现多选下拉控件的示例代码的详细内容,更多关于WPF多选下拉控件的资料请关注我们其它相关文章!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新开发

开发排行榜