using System.Collections; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Windows; using System.Windows.Controls; namespace Elwig.Controls { public class CheckComboBox : ListBox { public new static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(nameof(SelectedItems), typeof(IList), typeof(CheckComboBox), new FrameworkPropertyMetadata(new ObservableCollection(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChangedCallback)); public new IList SelectedItems { get => (IList)GetValue(SelectedItemsProperty); set => SetValue(SelectedItemsProperty, value); } public static readonly DependencyProperty DelimiterProperty = DependencyProperty.Register(nameof(Delimiter), typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata(", ")); public string Delimiter { get => (string)GetValue(DelimiterProperty); set => SetValue(DelimiterProperty, value); } public static readonly DependencyProperty AllItemsSelectedContentProperty = DependencyProperty.Register(nameof(AllItemsSelectedContent), typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata("All")); public string AllItemsSelectedContent { get => (string)GetValue(AllItemsSelectedContentProperty); set => SetValue(AllItemsSelectedContentProperty, value); } public static readonly DependencyProperty IsSelectAllActiveProperty = DependencyProperty.Register(nameof(IsSelectAllActive), typeof(bool), typeof(CheckComboBox), new FrameworkPropertyMetadata(false)); public bool IsSelectAllActive { get => (bool)GetValue(IsSelectAllActiveProperty); set => SetValue(IsSelectAllActiveProperty, value); } public static readonly DependencyProperty SelectAllContentProperty = DependencyProperty.Register(nameof(SelectAllContent), typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata("All")); public string SelectAllContent { get => (string)GetValue(SelectAllContentProperty); set => SetValue(SelectAllContentProperty, value); } public static readonly DependencyProperty AllItemsSelectedProperty = DependencyProperty.Register(nameof(AllItemsSelected), typeof(bool?), typeof(CheckComboBox), new FrameworkPropertyMetadata(false)); public bool? AllItemsSelected { get => (bool?)GetValue(AllItemsSelectedProperty); set => SetValue(AllItemsSelectedProperty, value); } public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(nameof(IsDropDownOpen), typeof(bool), typeof(CheckComboBox), new FrameworkPropertyMetadata(false)); public bool IsDropDownOpen { get => (bool)GetValue(IsDropDownOpenProperty); set => SetValue(IsDropDownOpenProperty, value); } public static readonly DependencyProperty MaxDropDownHeightProperty = DependencyProperty.Register(nameof(MaxDropDownHeight), typeof(double), typeof(CheckComboBox), new FrameworkPropertyMetadata(ComboBox.MaxDropDownHeightProperty.DefaultMetadata.DefaultValue)); public double MaxDropDownHeight { get => (double)GetValue(MaxDropDownHeightProperty); set => SetValue(MaxDropDownHeightProperty, value); } public new static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent(nameof(SelectionChanged), RoutingStrategy.Bubble, typeof(SelectionChangedEventHandler), typeof(CheckComboBox)); public new event SelectionChangedEventHandler SelectionChanged { add => AddHandler(SelectionChangedEvent, value); remove => RemoveHandler(SelectionChangedEvent, value); } static CheckComboBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckComboBox), new FrameworkPropertyMetadata(typeof(CheckComboBox))); } private bool _viewHandled; private bool _modelHandled; private TextBlock _textBox; public CheckComboBox() { SelectionMode = SelectionMode.Multiple; } public override void OnApplyTemplate() { _textBox = (GetTemplateChild("TextBox") as TextBlock)!; var button = GetTemplateChild("Button") as Button; button!.Click += Button_MouseDown; var item = GetTemplateChild("SelectAllItem") as ListBoxItem; item!.PreviewMouseDown += SelectAllItem_MouseDown; if (SelectedItems is INotifyCollectionChanged collection) { collection.CollectionChanged += (s, e) => { SelectItems(); }; } IsEnabledChanged += OnIsEnabledChanged; base.SelectionChanged += OnSelectionChanged; base.OnApplyTemplate(); } private static void OnSelectedItemsChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e) { if (sender is CheckComboBox ccb) ccb.OnSelectedItemsChanged(); } private void OnSelectedItemsChanged() { if (SelectedItems is INotifyCollectionChanged collection) { collection.CollectionChanged += (s, e) => { SelectItems(); }; } SelectItems(); } private void Button_MouseDown(object sender, RoutedEventArgs evt) { IsDropDownOpen = !IsDropDownOpen; } private void SelectAllItem_MouseDown(object sender, RoutedEventArgs evt) { if (AllItemsSelected == false) { SelectAll(); } else { UnselectAll(); } evt.Handled = true; } private void OnSelectionChanged(object sender, SelectionChangedEventArgs evt) { SelectItemsReverse(); var dmp = DisplayMemberPath != null && DisplayMemberPath != "" ? DisplayMemberPath : null; if (SelectedItems.Count == ItemsSource.Cast().Count() && AllItemsSelectedContent != null) { _textBox.Text = AllItemsSelectedContent; AllItemsSelected = true; } else if (SelectedItems.Count == 0) { _textBox.Text = ""; AllItemsSelected = false; } else { _textBox.Text = string.Join(Delimiter, dmp == null ? SelectedItems.Cast() : SelectedItems.Cast() .Select(i => i.GetType().GetProperty(dmp)?.GetValue(i)) ); AllItemsSelected = null; } RaiseEvent(new SelectionChangedEventArgs(SelectionChangedEvent, evt.RemovedItems, evt.AddedItems)); } private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs evt) { if (!IsEnabled) IsDropDownOpen = false; } private void SelectItems() { if (_viewHandled || _modelHandled) return; _viewHandled = true; base.SelectedItems.Clear(); foreach (var item in SelectedItems) base.SelectedItems.Add(item); _viewHandled = false; } private void SelectItemsReverse() { if (_modelHandled || _viewHandled) return; _modelHandled = true; SelectedItems.Clear(); foreach (var item in base.SelectedItems) SelectedItems.Add(item); _modelHandled = false; } } }