第二部分:桌面应用开发
18. DataGrid控件——表格数据展示与编辑
实例介绍
之前用ItemsControl展示任务列表时,编辑一条任务得点按钮、弹窗口,步骤繁琐;用户反馈“改个截止日期还要点三次,太麻烦”。后来换成DataGrid控件:任务数据直接以表格形式展示,双击单元格就能编辑(比如完成状态点复选框、截止日期用日期选择器),还能一键排序/筛选。用户说“终于像个正经的管理工具了”,效率提升不止一倍。这节就带你给任务管理工具加上DataGrid,彻底解决表格数据的展示与编辑痛点。
需求分析
DataGrid要解决“表格数据高效交互”问题,具体需求如下:
1.数据展示:清晰呈现任务的标题、截止日期、完成状态;
2.直接编辑:单元格双击/回车即可编辑,支持复选vb.net教程C#教程python教程SQL教程access 2010教程
框(完成状态)、日期选择器(截止日期)等专用控件;
3.列自定义:隐藏不必要的列(如ID),自定义列的显示与编辑模板;
4.排序筛选:支持按截止日期排序,筛选完成/未完成任务;
5.编辑验证:截止日期不能早于当前日期,标题不能为空;
6.样式统一:与全局样式(如按钮、输入框)保持一致,表格行 hover 效果自然;
7.性能优化:数据量大时启用虚拟滚动,避免卡顿。
代码实现
前置条件:.NET 6+、WPF;延续任务管理工具案例,复用TaskItem、TaskViewModel及全局样式;需引用System.Windows.Data(排序/筛选)。
场景1:基础DataGrid展示任务
用DataGrid绑定ViewModel的TaskList,自动生成列(快速上手)。
MainWindow.xaml中添加DataGrid
xml
<Grid Margin="10">
<!-- 基础DataGrid -->
<DataGrid x:Name="TaskDataGrid"
ItemsSource="{Binding TaskList}"
AutoGenerateColumns="True"
CanUserAddRows="False"
Margin="10"
FontSize="14"
RowHeight="35"/>
</Grid>
TaskViewModel中初始化数据
csharp
public partial class TaskViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<TaskItem> _taskList = new();
public TaskViewModel()
{
// 模拟数据
TaskList.Add(new TaskItem { Title = "学习DataGrid", DueDate = DateTime.Now.AddDays(3), IsCompleted = false });
TaskList.Add(new TaskItem { Title = "写表格编辑功能", DueDate = DateTime.Now.AddDays(-1), IsCompleted = true });
TaskList.Add(new TaskItem { Title = "优化样式", DueDate = DateTime.Now.AddDays(5), IsCompleted = false });
}
}
场景2:自定义列(复选框+日期选择器)
关闭自动生成列,自定义列类型(完成状态用复选框,截止日期用日期选择器)。
MainWindow.xaml中自定义列
xml
<DataGrid x:Name="TaskDataGrid"
ItemsSource="{Binding TaskList}"
AutoGenerateColumns="False" <!-- 关闭自动生成列 -->
CanUserAddRows="False"
Margin="10"
FontSize="14"
RowHeight="35"
CellEditEnding="TaskDataGrid_CellEditEnding"> <!-- 编辑结束事件(验证用) -->
<DataGrid.Columns>
<!-- 1. 完成状态列(复选框) -->
<DataGridCheckBoxColumn Header="完成"
Binding="{Binding IsCompleted, Mode=TwoWay}"
Width="60"
IsReadOnly="False"/>
<!-- 2. 任务标题列(文本) -->
<DataGridTextColumn Header="任务标题"
Binding="{Binding Title, Mode=TwoWay}"
Width="*"
IsReadOnly="False"/>
<!-- 3. 截止日期列(日期选择器) -->
<DataGridTemplateColumn Header="截止日期" Width="150">
<!-- 显示模板(TextBlock) -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DueDate, StringFormat='yyyy-MM-dd'}"
VerticalAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<!-- 编辑模板(DatePicker) -->
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DueDate, Mode=TwoWay}"
VerticalAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
场景3:编辑验证(截止日期+标题)
在CellEditEnding事件中验证编辑内容,不符合规则则取消编辑。
MainWindow.xaml.cs中添加验证逻辑
csharp
private void TaskDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var task = e.Row.Item as TaskItem;
if (task == null) return;
// 1. 验证标题(不能为空)
if (e.Column.Header.ToString() == "任务标题")
{
var textBox = e.EditingElement as TextBox;
if (string.IsNullOrWhiteSpace(textBox?.Text))
{
MessageBox.Show("任务标题不能为空!", "验证失败", MessageBoxButton.OK, MessageBoxImage.Warning);
e.Cancel = true; // 取消编辑
return;
}
}
// 2. 验证截止日期(不能早于今天)
if (e.Column.Header.ToString() == "截止日期")
{
var datePicker = e.EditingElement as DatePicker;
if (datePicker?.SelectedDate < DateTime.Today)
{
MessageBox.Show("截止日期不能早于今天!", "验证失败", MessageBoxButton.OK, MessageBoxImage.Warning);
e.Cancel = true; // 取消编辑
return;
}
}
}
场景4:排序与筛选
用CollectionViewSource实现排序(按截止日期)和筛选(完成/未完成任务)。
MainWindow.xaml中添加排序筛选控件
xml
<StackPanel Orientation="Horizontal" Margin="10">
<Button Content="按截止日期排序" Click="SortByDueDate_Click" Margin="0 0 10 0"/>
<ComboBox x:Name="FilterComboBox"
Width="150"
SelectionChanged="FilterComboBox_SelectionChanged">
<ComboBoxItem Content="全部任务"/>
<ComboBoxItem Content="已完成任务"/>
<ComboBoxItem Content="未完成任务"/>
</ComboBox>
</StackPanel>
MainWindow.xaml.cs中排序筛选逻辑
csharp
private ICollectionView _taskView;
public MainWindow()
{
InitializeComponent();
var viewModel = new TaskViewModel();
DataContext = viewModel;
// 获取TaskList的视图(用于排序筛选)
_taskView = CollectionViewSource.GetDefaultView(viewModel.TaskList);
}
// 按截止日期排序
private void SortByDueDate_Click(object sender, RoutedEventArgs e)
{
_taskView.SortDescriptions.Clear();
_taskView.SortDescriptions.Add(new SortDescription(nameof(TaskItem.DueDate), ListSortDirection.Ascending));
}
// 筛选任务
private void FilterComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItem = FilterComboBox.SelectedItem as ComboBoxItem;
if (selectedItem == null) return;
switch (selectedItem.Content.ToString())
{
case "已完成任务":
_taskView.Filter = item => (item as TaskItem)?.IsCompleted == true;
break;
case "未完成任务":
_taskView.Filter = item => (item as TaskItem)?.IsCompleted == false;
break;
default:
_taskView.Filter = null; // 显示全部
break;
}
}
场景5:性能优化(虚拟滚动)
数据量大时启用虚拟滚动,只渲染可见行(减少内存占用)。
MainWindow.xaml中开启虚拟滚动
xml
<DataGrid x:Name="TaskDataGrid"
ItemsSource="{Binding TaskList}"
AutoGenerateColumns="False"
CanUserAddRows="False"
Margin="10"
FontSize="14"
RowHeight="35"
EnableRowVirtualization="True" <!-- 启用行虚拟滚动 -->
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling" <!-- 复用行容器(性能更好) -->
MaxHeight="500"/> <!-- 限制高度,显示滚动条 -->
逐行讲解
场景1:基础DataGrid
ItemsSource:绑定ViewModel的TaskList(ObservableCollection
AutoGenerateColumns:True时自动根据TaskItem的属性生成列(如Title→文本列,IsCompleted→复选框列),False时手动定义列;
CanUserAddRows:False关闭自动添加行(避免用户误加空行);
RowHeight:设置行高(统一样式)。
场景2:自定义列
DataGridCheckBoxColumn:绑定IsCompleted(布尔值),直接显示复选框(无需编辑模板);
DataGridTextColumn:绑定Title(字符串),显示文本;
DataGridTemplateColumn:自定义列(灵活度最高),分CellTemplate(显示模式)和CellEditingTemplate(编辑模式);
CellTemplate:用TextBlock显示格式化的日期(StringFormat='yyyy-MM-dd');
CellEditingTemplate:用DatePicker让用户选择日期(提升编辑体验)。
场景3:编辑验证
CellEditEnding事件:单元格编辑结束前触发(可取消编辑);
e.EditingElement:获取编辑中的控件(如TextBox、DatePicker);
e.Cancel:设置为True取消编辑(保留原内容);
验证逻辑:针对不同列(标题/日期)分别验证,不符合规则则提示并取消。
场景4:排序与筛选
ICollectionView:DataGrid的ItemsSource实际绑定的是视图(而非原始集合),视图支持排序/筛选;
SortDescriptions:添加排序规则(如按DueDate升序);
Filter:设置筛选条件(如只显示已完成任务);
CollectionViewSource:可在XAML中定义视图(更符合MVVM),比如
场景5:虚拟滚动
EnableRowVirtualization:开启行虚拟滚动(只渲染可见行);
VirtualizationMode="Recycling":复用行容器(避免频繁创建/销毁行,提升性能);
MaxHeight:限制DataGrid高度,显示垂直滚动条(触发虚拟滚动)。
基础知识拓展
-
DataGrid核心列类型
列类型 用途说明
DataGridTextColumn 显示/编辑文本(如标题、描述)
DataGridCheckBoxColumn 显示/编辑布尔值(如完成状态)
DataGridComboBoxColumn 显示/编辑下拉列表(如任务优先级:高/中/低)
DataGridTemplateColumn 自定义列(如日期选择器、图片、按钮组合)
DataGridHyperlinkColumn 显示超链接(如任务链接) -
编辑模式与事件
编辑触发方式:双击单元格、按Enter键、点击F2键;
关键事件:
BeginningEdit:开始编辑前触发(可取消);
CellEditEnding:编辑结束前触发(验证用);
RowEditEnding:行编辑结束前触发(整行验证);
编辑模式:
Cell:单元格编辑(默认);
Row:整行编辑(需按Enter确认)。 -
MVVM友好的排序/筛选
在ViewModel中用ICollectionView管理视图(避免在View层写逻辑):
csharp
public partial class TaskViewModel : ObservableObject
{
private readonly ICollectionView _taskView;
[ObservableProperty]
private ObservableCollection<TaskItem> _taskList = new();
public ICollectionView TaskView => _taskView;
public TaskViewModel()
{
_taskView = CollectionViewSource.GetDefaultView(TaskList);
// 默认排序:按截止日期升序
_taskView.SortDescriptions.Add(new SortDescription(nameof(TaskItem.DueDate), ListSortDirection.Ascending));
}
// 筛选命令(按完成状态)
[RelayCommand]
private void FilterTasks(bool isCompleted)
{
_taskView.Filter = item => (item as TaskItem)?.IsCompleted == isCompleted;
}
}
-
分页实现
DataGrid本身不支持分页,需手动实现:
PagedCollectionView:第三方库(如System.Windows.Data.PagedCollectionView)支持分页;
自定义分页:用ObservableCollection显示当前页数据,加页码按钮(上一页/下一页/页码选择);
示例:每页显示10条,计算总页数TotalPages = (int)Math.Ceiling(TaskList.Count / 10.0),当前页数据CurrentPageTasks = TaskList.Skip((CurrentPage-1)*10).Take(10).ToList()。 -
样式定制
全局样式:在App.xaml中定义DataGrid样式(统一外观):
xml
<Style TargetType="DataGrid">
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#E0E0E0"/>
<Setter Property="RowBackground" Value="White"/>
<Setter Property="AlternatingRowBackground" Value="#F5F5F5"/> <!-- 交替行颜色 -->
<Setter Property="RowHeaderWidth" Value="0"/> <!-- 隐藏行头 -->
</Style>
行Hover效果:用DataGridRow的触发器实现:
xml
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E3F2FD"/> <!-- 浅蓝色hover -->
</Trigger>
</Style.Triggers>
</Style>
总结
DataGrid是WPF中表格数据交互的核心控件,适合需要高效展示/编辑数据的场景(如任务管理、数据报表)。关键要点:
1.自定义列:用DataGridTemplateColumn实现灵活的列(如日期选择器);
2.编辑验证:用CellEditEnding事件确保数据正确性;
3.排序筛选:通过ICollectionView实现(符合MVVM);
4.性能优化:启用虚拟滚动(数据量大时必备);
5.样式统一:用全局样式定制外观(提升用户体验)。
比如任务管理工具中,DataGrid让用户直接在表格里编辑任务,省去了弹窗和按钮,效率提升明显。掌握这些技巧,你可以轻松实现专业的表格交互功能!
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49467.html










