123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- using System;
- using System.Collections.Generic;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Controls.Primitives;
- using System.Windows.Data;
- using System.Windows.Input;
- using System.Windows.Media;
- #if NET40
- using System.Windows.Threading;
- #endif
- using HandyControl.Data;
- using HandyControl.Interactivity;
- namespace HandyControl.Controls;
- [TemplatePart(Name = AutoCompletePanel, Type = typeof(Panel))]
- [TemplatePart(Name = EditableTextBox, Type = typeof(System.Windows.Controls.TextBox))]
- [TemplatePart(Name = AutoPopupAutoComplete, Type = typeof(Popup))]
- public class ComboBox : System.Windows.Controls.ComboBox
- {
- #if NET40
- private string _searchText;
- private DispatcherTimer _autoCompleteTimer;
- #endif
- private bool _isAutoCompleteAction = true;
- private Panel _autoCompletePanel;
- private System.Windows.Controls.TextBox _editableTextBox;
- private Popup _autoPopupAutoComplete;
- private const string AutoCompletePanel = "PART_AutoCompletePanel";
- private const string AutoPopupAutoComplete = "PART_Popup_AutoComplete";
- private const string EditableTextBox = "PART_EditableTextBox";
- public ComboBox()
- {
- CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
- {
- if (IsReadOnly)
- {
- return;
- }
- SetCurrentValue(SelectedValueProperty, null);
- SetCurrentValue(SelectedItemProperty, null);
- SetCurrentValue(SelectedIndexProperty, -1);
- SetCurrentValue(TextProperty, "");
- }));
- }
- public override void OnApplyTemplate()
- {
- if (_editableTextBox != null)
- {
- BindingOperations.ClearBinding(_editableTextBox, System.Windows.Controls.TextBox.TextProperty);
- _editableTextBox.GotFocus -= EditableTextBox_GotFocus;
- _editableTextBox.LostFocus -= EditableTextBox_LostFocus;
- }
- base.OnApplyTemplate();
- if (IsEditable)
- {
- _editableTextBox = GetTemplateChild(EditableTextBox) as System.Windows.Controls.TextBox;
- if (_editableTextBox != null)
- {
- _editableTextBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
- #if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
- _editableTextBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
- #endif
- _editableTextBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
- _editableTextBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
- if (AutoComplete)
- {
- #if NET40
- _autoCompleteTimer = new DispatcherTimer
- {
- Interval = TimeSpan.FromMilliseconds(500)
- };
- _autoCompleteTimer.Tick += AutoCompleteTimer_Tick;
- #endif
- _autoPopupAutoComplete = GetTemplateChild(AutoPopupAutoComplete) as Popup;
- _autoCompletePanel = GetTemplateChild(AutoCompletePanel) as Panel;
- _editableTextBox.SetBinding(System.Windows.Controls.TextBox.TextProperty, new Binding(SearchTextProperty.Name)
- {
- UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
- Mode = BindingMode.OneWayToSource,
- #if !NET40
- Delay = 500,
- #endif
- Source = this
- });
- _editableTextBox.GotFocus += EditableTextBox_GotFocus;
- _editableTextBox.LostFocus += EditableTextBox_LostFocus;
- }
- }
- }
- }
- #if NET40
- private void AutoCompleteTimer_Tick(object sender, EventArgs e)
- {
- UpdateSearchItems(_searchText);
- _autoCompleteTimer.Stop();
- }
- #endif
- private void EditableTextBox_LostFocus(object sender, RoutedEventArgs e)
- {
- if (_autoPopupAutoComplete != null)
- {
- _autoPopupAutoComplete.IsOpen = false;
- }
- }
- #if !NET40
- protected override void OnDropDownClosed(EventArgs e)
- {
- base.OnDropDownClosed(e);
- _isAutoCompleteAction = false;
- }
- #endif
- private void EditableTextBox_GotFocus(object sender, RoutedEventArgs e)
- {
- if (_autoPopupAutoComplete != null && _editableTextBox != null &&
- !string.IsNullOrEmpty(_editableTextBox.Text))
- {
- _autoPopupAutoComplete.IsOpen = true;
- }
- }
- protected override void OnSelectionChanged(SelectionChangedEventArgs e)
- {
- _isAutoCompleteAction = false;
- base.OnSelectionChanged(e);
- #if NET40
- _isAutoCompleteAction = true;
- #endif
- }
- /// <summary>
- /// 数据搜索委托
- /// </summary>
- public Func<ItemCollection, object, IEnumerable<object>> SearchFunc { get; set; }
- /// <summary>
- /// 是否自动完成输入
- /// </summary>
- public static readonly DependencyProperty AutoCompleteProperty = DependencyProperty.Register(
- nameof(AutoComplete), typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnAutoCompleteChanged));
- private static void OnAutoCompleteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var ctl = (ComboBox) d;
- if (ctl._editableTextBox != null)
- {
- ctl.UpdateSearchItems(ctl._editableTextBox.Text);
- }
- }
- /// <summary>
- /// 是否自动完成输入
- /// </summary>
- public bool AutoComplete
- {
- get => (bool) GetValue(AutoCompleteProperty);
- set => SetValue(AutoCompleteProperty, ValueBoxes.BooleanBox(value));
- }
- /// <summary>
- /// 搜索文本
- /// </summary>
- internal static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register(
- nameof(SearchText), typeof(string), typeof(ComboBox), new PropertyMetadata(default(string), OnSearchTextChanged));
- private static void OnSearchTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var ctl = (ComboBox) d;
- if (ctl._isAutoCompleteAction)
- {
- #if NET40
- ctl._searchText = e.NewValue as string;
- ctl._autoCompleteTimer.Stop();
- ctl._autoCompleteTimer.Start();
- #else
- ctl.UpdateSearchItems(e.NewValue as string);
- #endif
- }
- ctl._isAutoCompleteAction = true;
- }
- /// <summary>
- /// 搜索文本
- /// </summary>
- internal string SearchText
- {
- get => (string) GetValue(SearchTextProperty);
- set => SetValue(SearchTextProperty, value);
- }
- public static readonly DependencyProperty SelectionBrushProperty =
- TextBoxBase.SelectionBrushProperty.AddOwner(typeof(ComboBox));
- public Brush SelectionBrush
- {
- get => (Brush) GetValue(SelectionBrushProperty);
- set => SetValue(SelectionBrushProperty, value);
- }
- #if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
- public static readonly DependencyProperty SelectionTextBrushProperty =
- TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(ComboBox));
- public Brush SelectionTextBrush
- {
- get => (Brush) GetValue(SelectionTextBrushProperty);
- set => SetValue(SelectionTextBrushProperty, value);
- }
- #endif
- public static readonly DependencyProperty SelectionOpacityProperty =
- TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(ComboBox));
- public double SelectionOpacity
- {
- get => (double) GetValue(SelectionOpacityProperty);
- set => SetValue(SelectionOpacityProperty, value);
- }
- public static readonly DependencyProperty CaretBrushProperty =
- TextBoxBase.CaretBrushProperty.AddOwner(typeof(ComboBox));
- public Brush CaretBrush
- {
- get => (Brush) GetValue(CaretBrushProperty);
- set => SetValue(CaretBrushProperty, value);
- }
- /// <summary>
- /// 更新搜索的项目
- /// </summary>
- /// <param name="key"></param>
- private void UpdateSearchItems(string key)
- {
- if (_editableTextBox != null && _autoPopupAutoComplete != null)
- {
- _autoPopupAutoComplete.IsOpen = !string.IsNullOrEmpty(key);
- _autoCompletePanel.Children.Clear();
- if (SearchFunc == null)
- {
- if (!string.IsNullOrEmpty(key))
- {
- foreach (var item in Items)
- {
- var content = item?.ToString();
- if (content == null) continue;
- if (!content.Contains(key)) continue;
- _autoCompletePanel.Children.Add(CreateSearchItem(item));
- }
- }
- }
- else
- {
- foreach (var item in SearchFunc.Invoke(Items, key))
- {
- _autoCompletePanel.Children.Add(CreateSearchItem(item));
- }
- }
- }
- }
- private ComboBoxItem CreateSearchItem(object content)
- {
- var item = new ComboBoxItem
- {
- Content = content,
- Style = ItemContainerStyle,
- ContentTemplate = ItemTemplate
- };
- item.PreviewMouseLeftButtonDown += AutoCompleteItem_PreviewMouseLeftButtonDown;
- return item;
- }
- private void AutoCompleteItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
- {
- if (sender is ComboBoxItem comboBoxItem)
- {
- if (_autoPopupAutoComplete != null)
- {
- _autoPopupAutoComplete.IsOpen = false;
- }
- _isAutoCompleteAction = false;
- SelectedValue = comboBoxItem.Content;
- }
- }
- }
|