using System; using System.Collections; using System.Collections.Specialized; using System.Windows.Controls; using System.Windows.Data; namespace WPFluent.Controls { [TemplatePart(Name = FilterTextBox, Type = typeof(System.Windows.Controls.TextBox))] [TemplatePart(Name = "PART_EditableTextBox", Type = typeof(System.Windows.Controls.TextBox))] public class ComboBoxEx : ComboBox { private const string FilterTextBox = "PART_FilterTextBox"; // Using a DependencyProperty as the backing store for FilterBoxPlaceholderText. This enables animation, styling, binding, etc... public static readonly DependencyProperty FilterBoxPlaceholderTextProperty = DependencyProperty.Register( nameof(FilterBoxPlaceholderText), typeof(string), typeof(ComboBoxEx), new PropertyMetadata("输入关键字")); public static readonly DependencyProperty HeaderPlacementProperty = DependencyProperty.Register( nameof(HeaderPlacement), typeof(Dock), typeof(ComboBoxEx), new PropertyMetadata(Dock.Top)); // Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc... public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( nameof(Header), typeof(string), typeof(ComboBoxEx), new PropertyMetadata(null)); public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register( nameof(PlaceholderText), typeof(string), typeof(ComboBoxEx), new PropertyMetadata("请选择...")); public static readonly DependencyProperty ShowFilterBoxProperty = DependencyProperty.Register( nameof(ShowFilterBox), typeof(bool), typeof(ComboBoxEx), new PropertyMetadata(true)); private System.Windows.Controls.TextBox filterTextBox; private ICollectionView view; static ComboBoxEx() { DefaultStyleKeyProperty.OverrideMetadata( typeof(ComboBoxEx), new FrameworkPropertyMetadata(typeof(ComboBoxEx))); } /// /// 过滤搜索 /// /// /// private void PART_FilterTextBox_TextChanged(object sender, TextChangedEventArgs e) { if (filterTextBox == null) return; if (view != null) { view.Filter += (o) => { if (o is string) { var value = o.ToString().ToLower(); return value.IndexOf(filterTextBox.Text.ToLower(), StringComparison.Ordinal) != -1; } else { var obj = GetPropertyValue(o, DisplayMemberPath); //在xaml中写入Combobox时 if (obj is ComboBoxItem item) { obj = item.Content; } var value = Convert.ToString(obj).ToLower(); return value.IndexOf(filterTextBox.Text.ToLower(), StringComparison.Ordinal) != -1; } }; } } /// /// 获取view /// /// /// 适用于在xaml中添加ComboBoxItem的情况 protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) { base.OnItemsChanged(e); view = CollectionViewSource.GetDefaultView(Items); } /// /// 获取view /// /// /// /// 适用于绑定ItemsSource protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue) { base.OnItemsSourceChanged(oldValue, newValue); view = CollectionViewSource.GetDefaultView(ItemsSource); } /// /// 获取属性,若无法获取则返回源对象 /// public static object GetPropertyValue(object obj, string path) { if (obj == null) return string.Empty; var result = obj; if (!string.IsNullOrEmpty(path)) { var property = obj.GetType().GetProperty(path); if (property != null) { try { result = property.GetValue(obj, null); return result; } catch { try { var type = obj.GetType(); var mInfo = type.GetMethod($"get_{path}"); if (mInfo != null) { result = mInfo.Invoke(obj, null); return result; } } catch { } } } } return result; } /// /// 应用样板 /// public override void OnApplyTemplate() { base.OnApplyTemplate(); if (filterTextBox != null) { filterTextBox.TextChanged -= PART_FilterTextBox_TextChanged; } filterTextBox = GetTemplateChild(FilterTextBox) as System.Windows.Controls.TextBox; if (filterTextBox != null) { filterTextBox.TextChanged += PART_FilterTextBox_TextChanged; } } [Category("自定义"), Bindable(true, BindingDirection.OneWay), Description("搜索框水印")] public string FilterBoxPlaceholderText { get { return (string)GetValue(FilterBoxPlaceholderTextProperty); } set { SetValue(FilterBoxPlaceholderTextProperty, value); } } [Category("自定义"), Bindable(true, BindingDirection.TwoWay), Description("标题")] public string Header { get { return (string)GetValue(HeaderProperty); } set { SetValue(HeaderProperty, value); } } //public bool PlaceholderEnable //{ // get { return (bool)GetValue(PlaceholderEnableProperty); } // set { SetValue(PlaceholderEnableProperty, value); } //} //// Using a DependencyProperty as the backing store for PlaceholderEnable. This enables animation, styling, binding, etc... //public static readonly DependencyProperty PlaceholderEnableProperty = DependencyProperty.Register( // nameof(PlaceholderEnable), // typeof(bool), // typeof(ComboBoxEx), // new PropertyMetadata(true) //); [Category("自定义"), Bindable(true, BindingDirection.OneWay), Description("标题位置")] public Dock HeaderPlacement { get { return (Dock)GetValue(HeaderPlacementProperty); } set { SetValue(HeaderPlacementProperty, value); } } /// /// /// /// /// 特性含义:属性面板(支持分组,支持数据绑定,支持属性提示) /// [Category("自定义分组"),Bindable(true,BindingDirection.OneWay),Description("选择框水印")] /// [Category("自定义"), Bindable(true, BindingDirection.OneWay), Description("选择框水印")] public string PlaceholderText { get { return (string)GetValue(PlaceholderTextProperty); } set { SetValue(PlaceholderTextProperty, value); } } /// /// 获取或者设置下拉列表过滤文本框的显示与隐藏 /// [Category("自定义"), Bindable(true, BindingDirection.OneWay), Description("过滤框")] public bool ShowFilterBox { get => (bool)GetValue(ShowFilterBoxProperty); set { SetValue(ShowFilterBoxProperty, value); } } } }