WPF Combox实现下拉多选,可选中多个值
自定义多选MultiCombox,可以实现下拉列表多选
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; namespace MES.Plugin.Report.Controls { public class MultiComboBox : ComboBox { static MultiComboBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiComboBox), new FrameworkPropertyMetadata(typeof(MultiComboBox))); } private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { d.SetValue(e.Property, e.NewValue); } /// <summary> /// 选中项列表 /// </summary> public ObservableCollection<MultiCbxBaseData> ChekedItems = new ObservableCollection<MultiCbxBaseData>(); /// <summary> /// ListBox竖向列表 /// </summary> private ListBox _ListBoxV; /// <summary> /// ListBox横向列表 /// </summary> private ListBox _ListBoxH; public override void OnApplyTemplate() { base.OnApplyTemplate(); _ListBoxV = Template.FindName("PART_ListBox", this) as ListBox; _ListBoxH = Template.FindName("PART_ListBoxChk", this) as ListBox; _ListBoxH.ItemsSource = ChekedItems; _ListBoxV.SelectionChanged += _ListBoxV_SelectionChanged; _ListBoxH.SelectionChanged += _ListBoxH_SelectionChanged; if (ItemsSource != null) { foreach (var item in ItemsSource) { MultiCbxBaseData bdc = item as MultiCbxBaseData; if (bdc.IsCheck) { _ListBoxV.SelectedItems.Add(bdc); } } } } private void _ListBoxH_SelectionChanged(object sender, SelectionChangedEventArgs e) { foreach (var item in e.RemovedItems) { MultiCbxBaseData datachk = item as MultiCbxBaseData; for (int i = 0; i < _ListBoxV.SelectedItems.Count; i++) { MultiCbxBaseData datachklist = _ListBoxV.SelectedItems[i] as MultiCbxBaseData; if (datachklist.ID == datachk.ID) { _ListBoxV.SelectedItems.Remove(_ListBoxV.SelectedItems[i]); } } } } void _ListBoxV_SelectionChanged(object sender, SelectionChangedEventArgs e) { foreach (var item in e.AddedItems) { MultiCbxBaseData datachk = item as MultiCbxBaseData; datachk.IsCheck = true; if (ChekedItems.IndexOf(datachk) < 0) { ChekedItems.Add(datachk); } } foreach (var item in e.RemovedItems) { MultiCbxBaseData datachk = item as MultiCbxBaseData; datachk.IsCheck = false; ChekedItems.Remove(datachk); } } public class MultiCbxBaseData { private int _id; public int ID { get { return _id; } set { _id = value; } } private string _viewName; public string ViewName { get { return _viewName; } set { _viewName = value; } } private bool _isCheck; /// <summary> /// 是否选中 /// </summary> public bool IsCheck { get { return _isCheck; } set { _isCheck = value; } } } } }
Style: ComboBox.xmal
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:MES.Plugin.Report" xmlns:controls="clr-namespace:MES.Plugin.Report.Controls"> <!--ComboBox--> <!--ComBoBox项选中背景色--> <SolidColorBrush x:Key="ComboBoxSelectdBackground" Color="#ff8c69"/> <!--ComBoBox项鼠标经过背景色--> <SolidColorBrush x:Key="ComboBoxMouseOverBackground" Color="#ff3030"/> <!--ComBoBox项选中前景色--> <SolidColorBrush x:Key="ComboBoxSelectedForeground" Color="White"/> <!--ComBoBox项鼠标经过前景色--> <SolidColorBrush x:Key="ComboBoxMouseOverForegrond" Color="White"/> <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}"> <Grid Height="25" HorizontalAlignment="Stretch"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="30"/> </Grid.ColumnDefinitions> <Border Background="White" Grid.ColumnSpan="2" Opacity="0"/> <Path x:Name="Arrow" Grid.Column="1" Data="M 0 0 6 6 12 0 Z" VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="None" Fill="#999" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="true"> <Setter TargetName="Arrow" Property="RenderTransform"> <Setter.Value> <RotateTransform CenterX="6" CenterY="3" Angle="180"></RotateTransform> </Setter.Value> </Setter> <Setter TargetName="Arrow" Property="Margin" Value="0 0 0 2"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <!--MultiComboBox普通样式--> <Style TargetType="{x:Type controls:MultiComboBox}"> <Setter Property="Width" Value="200" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="MaxDropDownHeight" Value="400" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type controls:MultiComboBox}"> <Grid> <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderBrush="#eaeaea" BorderThickness="1" > <Grid x:Name="PART_Root"> <Grid x:Name="PART_InnerGrid" Margin="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="0.3*" MaxWidth="30" /> </Grid.ColumnDefinitions> <ListBox x:Name="PART_ListBoxChk" Background="#2d2f3e" SelectionMode="Multiple" BorderThickness="0" ScrollViewer.VerticalScrollBarVisibility="Disabled"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel Orientation="Horizontal" VirtualizingStackPanel.IsVirtualizing="True" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem"> <Setter Property="BorderThickness" Value="0"/> <Setter Property="IsSelected" Value="True"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <CheckBox BorderThickness="0" Background="#2d2f3e" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding ViewName}" IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListBox.ItemContainerStyle> </ListBox> <!--下拉按钮--> <ToggleButton x:Name="PART_DropDownToggle" IsTabStop="False" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="1" Template="{StaticResource ComboBoxToggleButton}" /> </Grid> </Grid> </Border> <!--弹出多选列表--> <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}}" > <ListBox x:Name="PART_ListBox" SelectionMode="Multiple" BorderThickness="1 0 1 1" Background="White" ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{TemplateBinding MaxDropDownHeight}" BorderBrush="#eaeaea" > <ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}" > <Grid Height="22"> <Border x:Name="bg" BorderBrush="#eaeaea" BorderThickness="0"/> <ContentPresenter x:Name="content" /> <Border Background="White" Opacity="0"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="bg" Property="Background" Value="#ADD6FF" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsMouseOver" Value="true" /> <Condition Property="IsSelected" Value="false"/> </MultiTrigger.Conditions> <Setter TargetName="bg" Property="Background" Value="#009BDB" /> <Setter TargetName="bg" Property="Opacity" Value="0.7"/> <Setter Property="Foreground" Value="White" /> </MultiTrigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="bg" Property="Opacity" Value="0.3" /> <Setter Property="Foreground" Value="Gray" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListBox.ItemContainerStyle> <ListBox.ItemTemplate> <DataTemplate> <Grid> <CheckBox x:Name="chk" Visibility="Hidden" IsChecked="{Binding IsCheck,Mode=TwoWay}" VerticalAlignment="Center"/> <CheckBox VerticalAlignment="Center" Foreground="{Binding Foreground,RelativeSource={RelativeSource AncestorType=ListBoxItem}}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected,Mode=TwoWay}" Content="{Binding Path=ViewName}" /> </Grid> <DataTemplate.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="true"> <Setter TargetName="chk" Property="IsChecked" Value="true"/> </DataTrigger> <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="false"> <Setter TargetName="chk" Property="IsChecked" Value="false"/> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Popup> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
前端使用:
1.引用Style资源,在前端引用上面建好的ComboBox.xmal 样式
2.控件使用
<controls:MultiComboBox x:Name="MultiCmb" VerticalAlignment="Center" Margin="10,0,10,0" Grid.Column="6" Grid.Row="0" Width="Auto"/>
3.MutilComboBox 数据源绑定,刷新数据源
ObservableCollection<Controls.MultiComboBox.MultiCbxBaseData> MultiComboBoxListData = new ObservableCollection<Controls.MultiComboBox.MultiCbxBaseData>(); for (int i = 0; i<LstLine.Count; i++) { SFC_WORKCENTER workcenter = LstLine[i]; if (string.IsNullOrEmpty(workcenter.ID)) continue; if (workcenter.WORKCENTER_NAME.Contains("过塑")) { MultiComboBoxListData.Add(new Controls.MultiComboBox.MultiCbxBaseData() { ID = i, ViewName = workcenter.WORKCENTER_CODE, //LineName = workcenter.WORKCENTER_NAME, IsCheck = false }); } else { MultiComboBoxListData.Add(new Controls.MultiComboBox.MultiCbxBaseData() { ID = i, ViewName = workcenter.WORKCENTER_CODE, //LineName = workcenter.WORKCENTER_NAME, IsCheck = true }); } } plugin.MultiCmb.ItemsSource = MultiComboBoxListData;
plugin.MultiCmb.OnApplyTemplate();