WPF 自定义下拉框控件:多列显示、模糊搜索、支持大数据量
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 控件的技巧,并将其应用到你的项目中。
原文地址: https://www.cveoy.top/t/topic/kqIV 著作权归作者所有。请勿转载和采集!