using BPA.UIControl.Commons.KnownBoxes; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; namespace BPA.UIControl { /// /// ComboBox 帮助类 /// public class ComboBoxHelper { /// /// 是否多选 /// public static readonly DependencyProperty IsMultiSelectProperty = DependencyProperty.RegisterAttached( "IsMultiSelect", typeof(bool), typeof(ComboBoxHelper), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsMultiSelectChanged)); public static void SetIsMultiSelect(DependencyObject element, bool value) { element.SetValue(IsMultiSelectProperty, BooleanBoxes.Box(value)); } public static bool GetIsMultiSelect(DependencyObject element) { return (bool)element.GetValue(IsMultiSelectProperty); } /// /// 子项是否选中 /// internal static readonly DependencyProperty IsSelectedProperty = DependencyProperty.RegisterAttached( "IsSelected", typeof(bool), typeof(ComboBoxHelper), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsSelectedChanged)); internal static void SetIsSelected(DependencyObject element, bool value) { element.SetValue(IsSelectedProperty, BooleanBoxes.Box(value)); } internal static bool GetIsSelected(DependencyObject element) { return (bool)element.GetValue(IsSelectedProperty); } /// /// 多选时显示文本 /// public static readonly DependencyProperty MultiSelectTextProperty = DependencyProperty.RegisterAttached( "MultiSelectText", typeof(string), typeof(ComboBoxHelper), new PropertyMetadata(null)); public static void SetMultiSelectText(DependencyObject element, string value) { element.SetValue(MultiSelectTextProperty, value); } public static string GetMultiSelectText(DependencyObject element) { return (string)element.GetValue(MultiSelectTextProperty); } /// /// 多选时文本分隔符 /// public static readonly DependencyProperty MultiSelectSeparatorProperty = DependencyProperty.RegisterAttached( "MultiSelectSeparator", typeof(string), typeof(ComboBoxHelper), new PropertyMetadata(", ", OnMultiSelectSeparatorChanged)); public static void SetMultiSelectSeparator(DependencyObject element, string value) { element.SetValue(MultiSelectSeparatorProperty, value); } public static string GetMultiSelectSeparator(DependencyObject element) { return (string)element.GetValue(MultiSelectSeparatorProperty); } /// /// 选中项集合 /// public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.RegisterAttached( "SelectedItems", typeof(IList), typeof(ComboBoxHelper), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChanged)); public static void SetSelectedItems(DependencyObject element, IList value) { element.SetValue(SelectedItemsProperty, value); } public static IList GetSelectedItems(DependencyObject element) { return (IList)element.GetValue(SelectedItemsProperty); } private static void OnIsMultiSelectChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var comboBox = d as ComboBox; if ((bool)e.NewValue) { comboBox.DropDownOpened += ComboBox_DropDownOpened; } else { comboBox.DropDownOpened -= ComboBox_DropDownOpened; } } private static async void ComboBox_DropDownOpened(object sender, System.EventArgs e) { await Task.Delay(100); var comboBox = sender as ComboBox; var selectedItems = GetSelectedItems(comboBox); foreach (var item in comboBox.Items) { if (comboBox.ItemContainerGenerator.ContainerFromItem(item) is not ComboBoxItem comboBoxItem) { continue; } if (selectedItems.Contains(item)) { SetIsSelected(comboBoxItem, true); } else { SetIsSelected(comboBoxItem, false); } } } private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var comboBox = d as ComboBox; void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { UpdateMultiSelectText(comboBox); } if (e.NewValue is INotifyCollectionChanged newCollection) { newCollection.CollectionChanged += OnCollectionChanged; } UpdateMultiSelectText(comboBox); } private static void UpdateMultiSelectText(ComboBox comboBox) { var selectedItems = GetSelectedItems(comboBox); if (selectedItems is null) { SetMultiSelectText(comboBox, string.Empty); return; } var texts = new List(); foreach (var item in selectedItems) { var typeConverter = TypeDescriptor.GetConverter(item.GetType()); var text = typeConverter.ConvertToString(item); texts.Add(text); } var separator = GetMultiSelectSeparator(comboBox); SetMultiSelectText(comboBox, string.Join(separator, texts)); } private static void OnMultiSelectSeparatorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UpdateMultiSelectText(d as ComboBox); } private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var comboBoxItem = d as ComboBoxItem; var comboBox = ItemsControl.ItemsControlFromItemContainer(d) as ComboBox; var index = comboBox.ItemContainerGenerator.IndexFromContainer(comboBoxItem); var itemData = comboBox.Items[index]; var selectedItems = GetSelectedItems(comboBox); if (selectedItems == null) { selectedItems = new ObservableCollection(); SetSelectedItems(comboBox, selectedItems); } if ((bool)e.NewValue) { if (!selectedItems.Contains(itemData)) { selectedItems.Add(itemData); // 添加 } } else { if (selectedItems.Contains(itemData)) { selectedItems.Remove(itemData); // 移除 } } // UpdateMultiSelectText(comboBox); } } }