WPF 实现筛选下拉多选控件
- 框架使用
.NET4 至 .NET6
; Visual Studio 2022
;
创建 MultiSelectionSearchComboBox
继承 Control
.
模板中创建两个 ListBox
PART_Selector
用来显示所有Item
PART_SearchSelector
用于记录筛选到的Item
Item
继承 ListBoxItem
并将样式模板修改为 CheckBox
解决 Popup
中 IME
不跟随 TextBox
问题
private static extern IntPtr SetFocus(IntPtr hWnd);
当 TextBox
中 Text
发生改变时通过循环 Item
中的 GetProperty
获取特定 DisplayMemberPath
属性,判断是否包含输入的 SearchText
值,如果包含则添加PART_SearchSelector
中,当 SelectionChanged
事件更改时将修改 PART_Selector
中的内容。
实现代码
1)创建 MultiSelectionSearchComboBox.cs
代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
namespace WPFDevelopers.Controls
{
[TemplatePart(Name = "PART_TextBox", Type = typeof(TextBox))]
[TemplatePart(Name = "PART_Popup", Type = typeof(Popup))]
[TemplatePart(Name = "PART_Selector", Type = typeof(ListBox))]
[TemplatePart(Name = "PART_SelectAll", Type = typeof(CheckBox))]
[TemplatePart(Name = "PART_SearchSelector", Type = typeof(ListBox))]
public class MultiSelectionSearchComboBox : Control
{
private const string TextBoxTemplateName = "PART_TextBox";
private const string PopupTemplateName = "PART_Popup";
private const string ListBoxTemplateName = "PART_Selector";
private const string CheckBoxTemplateName = "PART_SelectAll";
private const string ListBoxTemplateNameSearch = "PART_SearchSelector";
public static readonly RoutedEvent ClosedEvent =
EventManager.RegisterRoutedEvent("Closed",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(MultiSelectionSearchComboBox));
public static readonly DependencyProperty DisplayMemberPathProperty =
DependencyProperty.Register("DisplayMemberPath",
typeof(string),
typeof(MultiSelectionSearchComboBox),
new PropertyMetadata(string.Empty));
public static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath",
typeof(string),
typeof(MultiSelectionSearchComboBox),
new PropertyMetadata(string.Empty));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text",
typeof(string),
typeof(MultiSelectionSearchComboBox),
new PropertyMetadata(string.Empty));
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(MultiSelectionSearchComboBox),
new PropertyMetadata());
public static readonly DependencyProperty ItemsSourceSearchProperty =
DependencyProperty.Register("ItemsSourceSearch", typeof(IEnumerable), typeof(MultiSelectionSearchComboBox),
new PropertyMetadata());
public static readonly DependencyProperty SelectAllContentProperty =
DependencyProperty.Register("SelectAllContent", typeof(object), typeof(MultiSelectionSearchComboBox),
new PropertyMetadata("全选"));
public static readonly DependencyProperty IsSelectAllActiveProperty =
DependencyProperty.Register("IsSelectAllActive", typeof(bool), typeof(MultiSelectionSearchComboBox),
new PropertyMetadata(false));
public static readonly DependencyProperty DelimiterProperty =
DependencyProperty.Register("Delimiter", typeof(string), typeof(MultiSelectionSearchComboBox),
new PropertyMetadata(";"));
public static readonly DependencyProperty IsDropDownOpenProperty =
DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(MultiSelectionSearchComboBox),
new PropertyMetadata(false, OnIsDropDownOpenChanged));
public static readonly DependencyProperty MaxDropDownHeightProperty =
DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(MultiSelectionSearchComboBox),
new UIPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0, OnMaxDropDownHeightChanged));
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectionSearchComboBox),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
OnSelectedItemsChanged));
public static readonly DependencyProperty SearchWatermarkProperty =
DependencyProperty.Register("SearchWatermark",
typeof(string),
typeof(MultiSelectionSearchComboBox),
new PropertyMetadata(string.Empty));
private CheckBox _checkBox;
private ListBox _listBox;
private ListBox _listBoxSearch;
private Popup _popup;
private TextBox _textBox;
private List<object> selectedItems;
private List<object> selectedList;
private List<object> selectedSearchList;
private string theLastText;
static MultiSelectionSearchComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiSelectionSearchComboBox),
new FrameworkPropertyMetadata(typeof(MultiSelectionSearchComboBox)));
}
public string Delimiter
{
get => (string)GetValue(DelimiterProperty);
set => SetValue(DelimiterProperty, value);
}
public string SelectedValuePath
{
get => (string)GetValue(SelectedValuePathProperty);
set => SetValue(SelectedValuePathProperty, value);
}
public string DisplayMemberPath
{
get => (string)GetValue(DisplayMemberPathProperty);
set => SetValue(DisplayMemberPathProperty, value);
}
public string Text
{
get => (string) GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public IEnumerable ItemsSourceSearch
{
get => (IEnumerable) GetValue(ItemsSourceSearchProperty);
set => SetValue(ItemsSourceSearchProperty, value);
}
public object SelectAllContent
{
get => GetValue(SelectAllContentProperty);
set => SetValue(SelectAllContentProperty, value);
}
public bool IsSelectAllActive
{
get => (bool) GetValue(IsSelectAllActiveProperty);
set => SetValue(IsSelectAllActiveProperty, value);
}
public bool IsDropDownOpen
{
get => (bool) GetValue(IsDropDownOpenProperty);
set => SetValue(IsDropDownOpenProperty, value);
}
public double MaxDropDownHeight
{
get => (double) GetValue(MaxDropDownHeightProperty);
set => SetValue(MaxDropDownHeightProperty, value);
}
public IList SelectedItems
{
get => (IList) GetValue(SelectedItemsProperty);
set => SetValue(SelectedItemsProperty, value);
}
public string SearchWatermark
{
get => (string)GetValue(SearchWatermarkProperty);
set => SetValue(SearchWatermarkProperty, value);
}
[DllImport("User32.dll")]
private static extern IntPtr SetFocus(IntPtr hWnd);
public event RoutedEventHandler Closed
{
add => AddHandler(ClosedEvent, value);
remove => RemoveHandler(ClosedEvent, value);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
selectedList = new List<object>();
selectedSearchList = new List<object>();
selectedItems = new List<object>();
_textBox = GetTemplateChild(TextBoxTemplateName) as TextBox;
_popup = GetTemplateChild(PopupTemplateName) as Popup;
if (_popup != null)
_popup.GotFocus += _popup_GotFocus;
_listBox = GetTemplateChild(ListBoxTemplateName) as ListBox;
_checkBox = GetTemplateChild(CheckBoxTemplateName) as CheckBox;
_listBoxSearch = GetTemplateChild(ListBoxTemplateNameSearch) as ListBox;
if (_textBox != null)
{
_textBox.TextChanged -= _textbox_TextChanged;
_textBox.TextChanged += _textbox_TextChanged;
}
if (_checkBox != null)
{
_checkBox.Checked -= _checkBox_Checked;
_checkBox.Unchecked -= _checkBox_Unchecked;
_checkBox.Checked += _checkBox_Checked;
_checkBox.Unchecked += _checkBox_Unchecked;
}
if (_listBox != null)
{
_listBox.IsVisibleChanged -= _listBox_IsVisibleChanged;
_listBox.IsVisibleChanged += _listBox_IsVisibleChanged;
_listBox.SelectionChanged -= _listBox_SelectionChanged;
_listBox.SelectionChanged += _listBox_SelectionChanged;
}
if (_listBoxSearch != null)
{
_listBoxSearch.IsVisibleChanged -= _listBoxSearch_IsVisibleChanged;
_listBoxSearch.IsVisibleChanged += _listBoxSearch_IsVisibleChanged;
_listBoxSearch.SelectionChanged -= _listBoxSearch_SelectionChanged;
_listBoxSearch.SelectionChanged += _listBoxSearch_SelectionChanged;
}
}
private void _listBoxSearch_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool) e.NewValue)
UpdateIsChecked(_listBoxSearch);
}
private void _listBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool) e.NewValue)
{
foreach (var item in selectedSearchList)
if (!_listBox.SelectedItems.Contains(item))
_listBox.SelectedItems.Add(item);
UpdateIsChecked(_listBox);
}
}
private void UpdateIsChecked(ListBox listBox)
{
_checkBox.Checked -= _checkBox_Checked;
if (listBox.Items.Count > 0 && listBox.Items.Count == listBox.SelectedItems.Count)
{
if (_checkBox.IsChecked != true)
_checkBox.IsChecked = true;
}
else
{
if (listBox.SelectedItems.Count == 0)
_checkBox.IsChecked = false;
else
_checkBox.IsChecked = null;
}
_checkBox.Checked += _checkBox_Checked;
}
private void _popup_GotFocus(object sender, RoutedEventArgs e)
{
var source = (HwndSource) PresentationSource.FromVisual(_popup.Child);
if (source != null)
{
SetFocus(source.Handle);
_textBox.Focus();
}
}
private void _checkBox_Unchecked(object sender, RoutedEventArgs e)
{
if (_listBoxSearch.Visibility == Visibility.Visible)
_listBoxSearch.UnselectAll();
else
_listBox.UnselectAll();
}
private void _checkBox_Checked(object sender, RoutedEventArgs e)
{
if (_listBoxSearch.Visibility == Visibility.Visible)
_listBoxSearch.SelectAll();
else
_listBox.SelectAll();
}
private void Combination()
{
var seletedName = new List<string>();
foreach (var item in _listBox.SelectedItems)
{
var name = GetDisplayText(item);
seletedName.Add(name);
}
foreach (var item in _listBoxSearch.SelectedItems)
{
if (_listBox.SelectedItems.Contains(item))
continue;
var name = GetDisplayText(item);
seletedName.Add(name);
}
Text = string.Join(Delimiter, seletedName.ToArray());
}
private void _listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.RemovedItems.Count > 0)
foreach (var item in e.RemovedItems)
if (_checkBox.IsChecked == true)
{
_checkBox.Unchecked -= _checkBox_Unchecked;
if (_listBox.Items.Count == 1)
_checkBox.IsChecked = false;
else
_checkBox.IsChecked = null;
_checkBox.Unchecked += _checkBox_Unchecked;
}
if (e.AddedItems.Count > 0)
SelectionChecked(_listBox);
Combination();
SelectedItems = _listBox.SelectedItems;
}
private void _listBoxSearch_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_listBoxSearch.IsVisible) return;
if (e.RemovedItems.Count > 0)
{
foreach (var item in e.RemovedItems)
if (selectedSearchList.Contains(item))
selectedSearchList.Remove(item);
Combination();
SelectionChecked(_listBoxSearch);
}
if (e.AddedItems.Count > 0)
{
foreach (var item in e.AddedItems)
if (!selectedSearchList.Contains(item))
selectedSearchList.Add(item);
Combination();
SelectionChecked(_listBoxSearch);
}
}
private void SelectionChecked(ListBox listbox)
{
if (listbox.SelectedItems.Count > 0
&&
listbox.Items.Count == listbox.SelectedItems.Count)
{
_checkBox.Checked -= _checkBox_Checked;
_checkBox.IsChecked = true;
_checkBox.Checked += _checkBox_Checked;
}
else
{
_checkBox.Checked -= _checkBox_Checked;
if (listbox.SelectedItems.Count > 0
&&
listbox.Items.Count == listbox.SelectedItems.Count)
{
if (_checkBox.IsChecked != true)
_checkBox.IsChecked = true;
}
else
{
if (listbox.SelectedItems.Count == 0)
_checkBox.IsChecked = false;
else
_checkBox.IsChecked = null;
}
_checkBox.Checked += _checkBox_Checked;
}
}
private string GetDisplayText(object dataItem, string path = null)
{
if (dataItem == null) return string.Empty;
return GetPropertyValue(dataItem);
}
private void _textbox_TextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrWhiteSpace(theLastText)) theLastText = _textBox.Text;
SearchText(_textBox.Text);
}
private void SearchText(string _text)
{
var text = _text;
if (string.IsNullOrWhiteSpace(text))
{
if (_listBoxSearch.Visibility != Visibility.Collapsed)
_listBoxSearch.Visibility = Visibility.Collapsed;
if (_listBox.Visibility != Visibility.Visible)
_listBox.Visibility = Visibility.Visible;
}
else
{
if(_listBoxSearch.Visibility != Visibility.Visible)
_listBoxSearch.Visibility = Visibility.Visible;
if(_listBox.Visibility != Visibility.Collapsed)
_listBox.Visibility = Visibility.Collapsed;
var listSearch = new List<object>();
foreach (var item in _listBox.Items)
{
var str = GetPropertyValue(item);
if (!string.IsNullOrWhiteSpace(str))
if (str.Contains(text.ToUpperInvariant()))
listSearch.Add(item);
}
foreach (var item in selectedList)
if (!listSearch.Contains(item))
listSearch.Add(item);
var lastItem = ItemsSourceSearch;
ItemsSourceSearch = listSearch;
SelectionChecked(_listBoxSearch);
selectedItems.Clear();
foreach (var item in _listBoxSearch.Items)
if (_listBox.SelectedItems.Contains(item))
if (!_listBoxSearch.SelectedItems.Contains(item))
_listBoxSearch.SelectedItems.Add(item);
}
}
private string GetPropertyValue(object item)
{
var result = string.Empty;
var nameParts = DisplayMemberPath.Split('.');
if (nameParts.Length == 1)
{
var property = item.GetType().GetProperty(DisplayMemberPath);
if (property != null)
return (property.GetValue(item, null) ?? string.Empty).ToString();
}
return result.ToUpperInvariant();
}
private static void OnIsDropDownOpenChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var multiSelectionSearchComboBox = o as MultiSelectionSearchComboBox;
if (multiSelectionSearchComboBox != null)
multiSelectionSearchComboBox.OnIsOpenChanged((bool) e.OldValue, (bool) e.NewValue);
}
protected virtual void OnIsOpenChanged(bool oldValue, bool newValue)
{
if (!newValue)
RaiseRoutedEvent(ClosedEvent);
}
private void RaiseRoutedEvent(RoutedEvent routedEvent)
{
var args = new RoutedEventArgs(routedEvent, this);
RaiseEvent(args);
}
private static void OnMaxDropDownHeightChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var comboBox = o as MultiSelectionSearchComboBox;
if (comboBox != null)
comboBox.OnMaxDropDownHeightChanged((double) e.OldValue, (double) e.NewValue);
}
protected virtual void OnMaxDropDownHeightChanged(double oldValue, double newValue)
{
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var mltiSelectionSearchComboBox = d as MultiSelectionSearchComboBox;
if (e.NewValue != null)
{
var collection = e.NewValue as IList;
if (collection.Count <= 0) return;
if (e.OldValue != null && mltiSelectionSearchComboBox._listBox != null)
{
mltiSelectionSearchComboBox._listBox.SelectionChanged -=
mltiSelectionSearchComboBox._listBox_SelectionChanged;
mltiSelectionSearchComboBox._listBox.SelectedItems.Clear();
}
foreach (var item in collection)
{
var name = mltiSelectionSearchComboBox.GetPropertyValue(item);
var model = mltiSelectionSearchComboBox._listBox.ItemsSource.OfType<object>().FirstOrDefault(h =>
mltiSelectionSearchComboBox.GetPropertyValue(h).ToUpperInvariant()
.Equals(name));
if (model != null && !mltiSelectionSearchComboBox._listBox.SelectedItems.Contains(item))
mltiSelectionSearchComboBox._listBox.SelectedItems.Add(model);
if (e.OldValue != null && mltiSelectionSearchComboBox._listBox != null)
mltiSelectionSearchComboBox._listBox.SelectionChanged +=
mltiSelectionSearchComboBox._listBox_SelectionChanged;
mltiSelectionSearchComboBox.Combination();
}
}
}
}
}
2)创建 MultiSelectionListBox.xaml
代码如下:
using System.Windows;
using System.Windows.Controls;
namespace WPFDevelopers.Controls
{
public class MultiSelectionListBox:ListBox
{
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is MultiSelectComboBoxItem;
}
protected override DependencyObject GetContainerForItemOverride()
{
return new MultiSelectComboBoxItem();
}
}
}
3)创建 MultiSelectionSearchComboBox.xaml
代码如下:
<ResourceDictionary xmlns="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>
<ResourceDictionary Source="Basic/ControlBasic.xaml"/>
<ResourceDictionary Source="MultiSelectionComboBox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type controls:MultiSelectionSearchComboBox}">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="MinWidth" Value="120" />
<Setter Property="MinHeight" Value="{StaticResource MinHeight}" />
<Setter Property="Height" Value="{StaticResource MinHeight}" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="BorderBrush" Value="{DynamicResource BaseSolidColorBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Background" Value="{DynamicResource BackgroundSolidColorBrush}"/>
<Setter Property="Padding" Value="14.5,3,30,3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:MultiSelectionSearchComboBox}">
<ControlTemplate.Resources>
<Storyboard x:Key="OpenStoryboard">
<DoubleAnimation Storyboard.TargetName="PART_DropDown"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)"
To="1" Duration="00:00:.2"
EasingFunction="{StaticResource ExponentialEaseOut}"/>
</Storyboard>
<Storyboard x:Key="CloseStoryboard">
<DoubleAnimation Storyboard.TargetName="PART_DropDown"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)"
To="0" Duration="00:00:.2"
EasingFunction="{StaticResource ExponentialEaseOut}"/>
</Storyboard>
</ControlTemplate.Resources>
<controls:SmallPanel SnapsToDevicePixels="True">
<Border Name="PART_Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
CornerRadius="{Binding Path=(helpers:ElementHelper.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}" />
<ToggleButton x:Name="PART_ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Style="{x:Null}"
Focusable="False"
ClickMode="Release"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
<TextBox Name="PART_EditableTextBox"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
Focusable="True"
Foreground="{DynamicResource PrimaryTextSolidColorBrush}"
Text="{Binding Text,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
Background="{TemplateBinding Background}"
SelectionBrush="{DynamicResource WindowBorderBrushSolidColorBrush}"
IsReadOnly="True" Style="{x:Null}" />
<TextBlock x:Name="PART_Watermark"
Text="{Binding Path=(helpers:ElementHelper.Watermark),RelativeSource={RelativeSource TemplatedParent}}"
Foreground="{DynamicResource RegularTextSolidColorBrush}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontSize="{StaticResource NormalFontSize}"
Margin="{TemplateBinding Padding}"
Background="Transparent"
TextTrimming="CharacterEllipsis"
IsHitTestVisible="False"
Padding="1,0"
Visibility="Collapsed"/>
<Popup x:Name="PART_Popup"
AllowsTransparency="True"
PlacementTarget="{Binding ElementName=PART_ToggleButton}"
IsOpen="{Binding IsDropDownOpen,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
Placement="Bottom" StaysOpen="False">
<controls:SmallPanel x:Name="PART_DropDown"
MinWidth="{TemplateBinding FrameworkElement.ActualWidth}"
Margin="24,2,24,24"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
RenderTransformOrigin=".5,0"
SnapsToDevicePixels="True">
<controls:SmallPanel.RenderTransform>
<ScaleTransform ScaleY="0"/>
</controls:SmallPanel.RenderTransform>
<Border
Name="PART_DropDownBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
CornerRadius="{Binding Path=(helpers:ElementHelper.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}"
UseLayoutRounding="True"
Effect="{StaticResource PopupShadowDepth}"/>
<Grid ClipToBounds="False"
Margin="0,8" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="PART_TextBox"
Margin="6,0"
helpers:ElementHelper.Watermark="{Binding SearchWatermark,RelativeSource={RelativeSource TemplatedParent}}"/>
<CheckBox x:Name="PART_SelectAll"
Grid.Row="1"
Margin="5,4"
Visibility="{TemplateBinding IsSelectAllActive,Converter={StaticResource bool2VisibilityConverter}}"
Content="{TemplateBinding SelectAllContent}"/>
<controls:MultiSelectListBox x:Name="PART_Selector"
Grid.Row="2"
BorderThickness="1,0,1,0"
DisplayMemberPath="{TemplateBinding DisplayMemberPath}"
SelectedValuePath="{TemplateBinding SelectedValuePath}"
MinHeight="{TemplateBinding MinHeight}"
ItemsSource="{TemplateBinding ItemsSource}"
SelectionMode="Multiple"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
ItemContainerStyle="{StaticResource DefaultMultiSelectComboBoxItem}"
ScrollViewer.HorizontalScrollBarVisibility="{Binding ScrollViewer.HorizontalScrollBarVisibility, RelativeSource={RelativeSource TemplatedParent}}"
ScrollViewer.CanContentScroll="{Binding ScrollViewer.CanContentScroll, RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{TemplateBinding BorderBrush}">
</controls:MultiSelectListBox>
<controls:MultiSelectListBox x:Name="PART_SearchSelector"
Grid.Row="2"
BorderThickness="1,0,1,0"
BorderBrush="{TemplateBinding BorderBrush}"
DisplayMemberPath="{TemplateBinding DisplayMemberPath}"
SelectedValuePath="{TemplateBinding SelectedValuePath}"
MinHeight="{TemplateBinding MinHeight}"
ItemsSource="{TemplateBinding ItemsSourceSearch}"
SelectionMode="Multiple"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
ItemContainerStyle="{StaticResource DefaultMultiSelectComboBoxItem}"
ScrollViewer.HorizontalScrollBarVisibility="{Binding ScrollViewer.HorizontalScrollBarVisibility, RelativeSource={RelativeSource TemplatedParent}}"
ScrollViewer.CanContentScroll="{Binding ScrollViewer.CanContentScroll, RelativeSource={RelativeSource TemplatedParent}}"
Visibility="Collapsed">
</controls:MultiSelectListBox>
</Grid>
</controls:SmallPanel>
</Popup>
</controls:SmallPanel>
<ControlTemplate.Triggers>
<Trigger SourceName="PART_ToggleButton" Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard x:Name="BeginStoryboardOpenStoryboard" Storyboard="{StaticResource OpenStoryboard}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="BeginStoryboardOpenStoryboard" />
</Trigger.ExitActions>
</Trigger>
<Trigger SourceName="PART_ToggleButton" Property="IsChecked" Value="False">
<Trigger.EnterActions>
<BeginStoryboard x:Name="BeginStoryboardCloseStoryboard" Storyboard="{StaticResource CloseStoryboard}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="BeginStoryboardCloseStoryboard" />
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" TargetName="PART_Border" Value="{DynamicResource PrimaryNormalSolidColorBrush}"/>
</Trigger>
<Trigger SourceName="PART_Popup" Property="AllowsTransparency" Value="True">
<Setter TargetName="PART_DropDownBorder" Property="Margin" Value="0,2,0,0" />
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Visibility" TargetName="PART_Watermark" Value="Visible"/>
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Visibility" TargetName="PART_Watermark" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
4)创建 MultiSelectSearchComboBoxExample.xaml
代码如下:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Content="获取选中"
VerticalAlignment="Bottom"
HorizontalAlignment="Center"
Click="Button_Click"
Margin="0,20,0,0"
Style="{StaticResource SuccessPrimaryButton}"/>
<UniformGrid Columns="2" Rows="2" Grid.Row="1">
<wd:MultiSelectionSearchComboBox
VerticalContentAlignment="Center"
HorizontalAlignment="Center"
ItemsSource="{Binding Drawings}"
DisplayMemberPath="Number"
SelectedValuePath="Index"
Width="200" Delimiter=","
IsSelectAllActive="True">
<wd:MultiSelectionSearchComboBox.DataContext>
<vm:DrawingExampleVM/>
</wd:MultiSelectionSearchComboBox.DataContext>
</wd:MultiSelectionSearchComboBox>
<wd:MultiSelectionSearchComboBox
Name="MyMultiSelectionSearchComboBox2"
VerticalContentAlignment="Center"
HorizontalAlignment="Center"
ItemsSource="{Binding Drawings}"
DisplayMemberPath="Number"
SelectedValuePath="Index"
Width="200" Delimiter="^"
IsSelectAllActive="True"
wd:ElementHelper.Watermark="MultiSelectionSearchComboBox"
SearchWatermark="请输入搜索内容">
<wd:MultiSelectionSearchComboBox.DataContext>
<vm:DrawingExampleVM/>
</wd:MultiSelectionSearchComboBox.DataContext>
</wd:MultiSelectionSearchComboBox>
</UniformGrid>
</Grid>
5)创建 MultiSelectSearchComboBoxExample.xaml.cs
代码如下:
using System.Windows;
using System.Windows.Controls;
namespace WPFDevelopers.Samples.ExampleViews
{
/// <summary>
/// MultiSelectComboBoxExample.xaml 的交互逻辑
/// </summary>
public partial class MultiSelectSearchComboBoxExample : UserControl
{
public MultiSelectSearchComboBoxExample()
{
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
WPFDevelopers.Controls.MessageBox.Show($"{MyMultiSelectionSearchComboBox2.Text} \r\n总共选中:{MyMultiSelectionSearchComboBox2.SelectedItems.Count} 条","选中内容",MessageBoxButton.OK,MessageBoxImage.Information);
}
}
}
效果图
以上就是基于WPF实现筛选下拉多选控件的详细内容,更多关于WPF筛选下拉多选控件的资料请关注编程网其它相关文章!