WPF 自定义下拉框控件:多列显示、模糊搜索、支持大数据量

本篇文章将介绍如何自定义 WPF 下拉框控件,实现多列显示、模糊搜索功能,并能够高效处理几万行数据。文中提供了详细代码和使用方法,并附带注释,帮助你轻松实现自定义下拉框控件。

代码实现

using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfCustomControls
{
    public class MultiColumnComboBox : ComboBox
    {
        private GridView _gridView;

        public MultiColumnComboBox()
        {
            // 创建 GridView
            _gridView = new GridView();
            this.DisplayMemberPath = "Text";
            this.SelectedValuePath = "Value";
            this.IsEditable = true;
            this.IsTextSearchEnabled = false;
            this.ItemTemplate = new DataTemplate(typeof(Dictionary<string, string>));
            this.DropDownClosed += MultiColumnComboBox_DropDownClosed;
            this.PreviewTextInput += MultiColumnComboBox_PreviewTextInput;
        }

        // 列定义
        public List<MultiColumnComboBoxColumn> Columns
        {
            get { return (List<MultiColumnComboBoxColumn>)GetValue(ColumnsProperty); }
            set { SetValue(ColumnsProperty, value); }
        }

        public static readonly DependencyProperty ColumnsProperty =
            DependencyProperty.Register("Columns", typeof(List<MultiColumnComboBoxColumn>), typeof(MultiColumnComboBox), new PropertyMetadata(null, OnColumnsChanged));

        private static void OnColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MultiColumnComboBox comboBox = (MultiColumnComboBox)d;
            List<MultiColumnComboBoxColumn> columns = (List<MultiColumnComboBoxColumn>)e.NewValue;

            // 添加列到 GridView
            comboBox._gridView.Columns.Clear();
            foreach (MultiColumnComboBoxColumn column in columns)
            {
                GridViewColumn gridViewColumn = new GridViewColumn();
                gridViewColumn.Header = column.Header;
                gridViewColumn.DisplayMemberBinding = new Binding(column.BindingPath);
                comboBox._gridView.Columns.Add(gridViewColumn);
            }

            // 更新 ItemTemplate
            FrameworkElementFactory gridFactory = new FrameworkElementFactory(typeof(GridView));
            gridFactory.SetValue(GridView.ColumnHeaderTemplateProperty, new DataTemplate());
            gridFactory.SetValue(GridViewColumnHeader.HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch);
            gridFactory.SetValue(GridViewColumnHeader.VerticalContentAlignmentProperty, VerticalAlignment.Stretch);
            gridFactory.SetValue(GridViewColumnHeader.PaddingProperty, new Thickness(2));
            gridFactory.SetValue(GridViewColumnHeader.FontWeightProperty, FontWeights.Bold);
            gridFactory.SetValue(GridViewColumnHeader.BackgroundProperty, SystemColors.ControlLightBrush);
            gridFactory.SetValue(GridViewColumnHeader.BorderBrushProperty, SystemColors.ControlDarkBrush);
            gridFactory.SetValue(GridViewColumnHeader.BorderThicknessProperty, new Thickness(1));
            gridFactory.SetValue(GridViewColumnHeader.IsHitTestVisibleProperty, false);
            gridFactory.SetValue(GridViewColumnHeader.IsTabStopProperty, false);
            gridFactory.SetValue(GridViewColumnHeader.HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch);
            gridFactory.SetValue(GridViewColumnHeader.VerticalContentAlignmentProperty, VerticalAlignment.Stretch);
            gridFactory.SetValue(GridViewColumnHeader.ContentTemplateProperty, new DataTemplate());
            gridFactory.SetValue(GridViewColumnHeader.TemplateProperty, new ControlTemplate(typeof(GridViewColumnHeader)));
            gridFactory.SetValue(GridViewColumnHeader.RoleProperty, GridViewColumnHeaderRole.Normal);
            gridFactory.SetValue(GridView.ColumnHeaderToolTipProperty, null);
            gridFactory.SetValue(GridViewColumnHeader.CommandProperty, null);
            gridFactory.SetValue(GridViewColumnHeader.CommandParameterProperty, null);
            gridFactory.SetValue(GridViewColumnHeader.CommandTargetProperty, null);
            gridFactory.SetValue(GridViewColumnHeader.ContextMenuProperty, null);
            gridFactory.SetValue(GridViewColumnHeader.InputScopeProperty, null);
            gridFactory.SetValue(GridViewColumnHeader.IsStickyProperty, false);
            gridFactory.SetValue(GridViewColumnHeader.MaxWidthProperty, double.PositiveInfinity);
            gridFactory.SetValue(GridViewColumnHeader.MinWidthProperty, 0.0);
            gridFactory.SetValue(GridViewColumnHeader.WidthProperty, double.NaN);
            gridFactory.SetValue(GridView.ViewProperty, comboBox._gridView);

            FrameworkElementFactory borderFactory = new FrameworkElementFactory(typeof(Border));
            borderFactory.SetValue(Border.BorderBrushProperty, SystemColors.ControlDarkBrush);
            borderFactory.SetValue(Border.BorderThicknessProperty, new Thickness(1));
            borderFactory.SetValue(Border.PaddingProperty, new Thickness(2));
            borderFactory.SetValue(Border.BackgroundProperty, SystemColors.WindowBrush);
            borderFactory.SetValue(Border.CornerRadiusProperty, new CornerRadius(2));
            borderFactory.SetValue(Border.SnapsToDevicePixelsProperty, true);
            borderFactory.SetValue(Border.ChildProperty, gridFactory);

            FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));
            stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Vertical);
            stackPanelFactory.SetValue(StackPanel.SnapsToDevicePixelsProperty, true);
            stackPanelFactory.SetValue(StackPanel.ChildrenProperty, new TemplateBindingExtension(ItemsControl.ItemsProperty));

            FrameworkElementFactory scrollViewerFactory = new FrameworkElementFactory(typeof(ScrollViewer));
            scrollViewerFactory.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Hidden);
            scrollViewerFactory.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Auto);
            scrollViewerFactory.SetValue(ScrollViewer.CanContentScrollProperty, true);
            scrollViewerFactory.SetValue(ScrollViewer.PanningModeProperty, PanningMode.None);
            scrollViewerFactory.SetValue(ScrollViewer.PanningDecelerationProperty, 0.001);
            scrollViewerFactory.SetValue(ScrollViewer.PanningRatioProperty, 0.1);
            scrollViewerFactory.SetValue(ScrollViewer.SnapsToDevicePixelsProperty, true);
            scrollViewerFactory.SetValue(ScrollViewer.ContentProperty, borderFactory);
            scrollViewerFactory.SetValue(ScrollViewer.TemplateProperty, new ControlTemplate(typeof(ScrollViewer)));

            comboBox.ItemTemplate.VisualTree = scrollViewerFactory;
        }

        // 模糊查询
        private void MultiColumnComboBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(ItemsSource);
            if (view != null)
            {
                view.Filter = item =>
                {
                    if (string.IsNullOrEmpty(Text))
                    {
                        return true;
                    }

                    Dictionary<string, string> data = (Dictionary<string, string>)item;
                    foreach (MultiColumnComboBoxColumn column in Columns)
                    {
                        if (data[column.BindingPath].IndexOf(Text, System.StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            return true;
                        }
                    }

                    return false;
                };
            }
        }

        // 关闭下拉框时清空过滤条件
        private void MultiColumnComboBox_DropDownClosed(object sender, System.EventArgs e)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(ItemsSource);
            if (view != null)
            {
                view.Filter = null;
            }
        }
    }

    // 列定义类
    public class MultiColumnComboBoxColumn
    {
        public string Header { get; set; }
        public string BindingPath { get; set; }
    }
}

使用方法

<local:MultiColumnComboBox x:Name="multiColumnComboBox" Width="200" Height="30" ItemsSource="{Binding Data}">
    <local:MultiColumnComboBox.Columns>
        <local:MultiColumnComboBoxColumn Header="Name" BindingPath="Name" />
        <local:MultiColumnComboBoxColumn Header="Age" BindingPath="Age" />
    </local:MultiColumnComboBox.Columns>
</local:MultiColumnComboBox>

其中 Data 是一个包含多列数据的集合,例如:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public List<Dictionary<string, string>> Data { get; set; } = new List<Dictionary<string, string>>();
foreach (Person person in GetPersons())
{
    Dictionary<string, string> item = new Dictionary<string, string>();
    item["Name"] = person.Name;
    item["Age"] = person.Age.ToString();
    Data.Add(item);
}

总结

通过自定义 WPF 下拉框控件,你可以轻松实现多列显示、模糊搜索功能,并且能够高效处理大数据量。希望本文能够帮助你快速掌握自定义 WPF 控件的技巧,并将其应用到你的项目中。

WPF 自定义下拉框控件:多列显示、模糊搜索、支持大数据量

原文地址: https://www.cveoy.top/t/topic/kqIV 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录