如何在WPF DataGrid中实现类似Microsoft Access表的关联记录功能
在WPF DataGrid中实现类似Access的关联数据展开功能
要实现Microsoft Access中那种点击行左侧"+"展开关联数据的效果,你可以利用WPF DataGrid的RowDetailsTemplate结合自定义行头按钮完成,具体步骤如下:
1. 准备数据实体
定义包含子集合的主实体类,同时实现INotifyPropertyChanged接口确保UI响应属性变化:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; public class Order : INotifyPropertyChanged { private int _orderId; public int OrderId { get => _orderId; set { _orderId = value; OnPropertyChanged(); } } private string _customerName; public string CustomerName { get => _customerName; set { _customerName = value; OnPropertyChanged(); } } // 存储关联的子数据 public ObservableCollection<OrderItem> OrderItems { get; set; } = new ObservableCollection<OrderItem>(); private bool _isExpanded; // 控制行详情的展开/折叠状态 public bool IsExpanded { get => _isExpanded; set { _isExpanded = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class OrderItem { public int ProductId { get; set; } public string ProductName { get; set; } public int Quantity { get; set; } }
2. 实现XAML布局
在DataGrid中配置自定义行头按钮、行详情模板,并绑定数据:
<Window x:Class="WpfDataGridExpandDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfDataGridExpandDemo" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <!-- 转换器:将布尔值转为"+"/"-"符号 --> <local:BooleanToExpandSymbolConverter x:Key="BooleanToExpandSymbolConverter"/> </Window.Resources> <Grid> <DataGrid x:Name="OrderDataGrid" AutoGenerateColumns="False" CanUserAddRows="False"> <DataGrid.Columns> <DataGridTextColumn Header="订单ID" Binding="{Binding OrderId}" Width="100"/> <DataGridTextColumn Header="客户名称" Binding="{Binding CustomerName}" Width="200"/> </DataGrid.Columns> <!-- 自定义行头:添加展开/折叠按钮 --> <DataGrid.RowHeaderTemplate> <DataTemplate> <Button Width="20" Height="20" Click="ExpandCollapseButton_Click" Content="{Binding IsExpanded, Converter={StaticResource BooleanToExpandSymbolConverter}}"> <Button.Style> <Style TargetType="Button"> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Background" Value="Transparent"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="#EEEEEE"/> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button> </DataTemplate> </DataGrid.RowHeaderTemplate> <!-- 行详情模板:显示关联的子数据 --> <DataGrid.RowDetailsTemplate> <DataTemplate> <DataGrid ItemsSource="{Binding OrderItems}" AutoGenerateColumns="False" Margin="20,0,0,0"> <DataGrid.Columns> <DataGridTextColumn Header="产品ID" Binding="{Binding ProductId}" Width="100"/> <DataGridTextColumn Header="产品名称" Binding="{Binding ProductName}" Width="200"/> <DataGridTextColumn Header="数量" Binding="{Binding Quantity}" Width="80"/> </DataGrid.Columns> </DataGrid> </DataTemplate> </DataGrid.RowDetailsTemplate> </DataGrid> </Grid> </Window>
3. 实现转换器和后台逻辑
创建布尔值转符号的转换器,并处理按钮点击事件切换展开状态:
转换器代码
using System; using System.Globalization; using System.Windows.Data; namespace WpfDataGridExpandDemo { public class BooleanToExpandSymbolConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return (bool)value ? "-" : "+"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return (string)value == "-"; } } }
后台按钮点击事件
using System.Windows; using System.Windows.Controls; namespace WpfDataGridExpandDemo { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // 初始化模拟数据 LoadSampleData(); } private void LoadSampleData() { var orders = new ObservableCollection<Order> { new Order { OrderId = 1, CustomerName = "张三", OrderItems = new ObservableCollection<OrderItem> { new OrderItem { ProductId = 101, ProductName = "笔记本", Quantity = 2 }, new OrderItem { ProductId = 102, ProductName = "钢笔", Quantity = 5 } } }, new Order { OrderId = 2, CustomerName = "李四", OrderItems = new ObservableCollection<OrderItem> { new OrderItem { ProductId = 201, ProductName = "鼠标", Quantity = 1 }, new OrderItem { ProductId = 202, ProductName = "键盘", Quantity = 1 } } } }; OrderDataGrid.ItemsSource = orders; } private void ExpandCollapseButton_Click(object sender, RoutedEventArgs e) { var button = sender as Button; var order = button.DataContext as Order; if (order == null) return; // 切换展开状态 order.IsExpanded = !order.IsExpanded; // 更新行详情的可见性 var row = OrderDataGrid.ItemContainerGenerator.ContainerFromItem(order) as DataGridRow; if (row != null) { row.DetailsVisibility = order.IsExpanded ? Visibility.Visible : Visibility.Collapsed; } } } }
关键说明
RowDetailsTemplate是WPF DataGrid内置的行详情模板,用来承载关联的子数据表格。- 自定义行头按钮通过绑定
IsExpanded属性控制显示"+"或"-",点击时切换状态并更新行详情可见性。 - 实体类实现
INotifyPropertyChanged是为了让UI实时响应IsExpanded属性的变化。
内容的提问来源于stack exchange,提问作者Alejoho
相关产品推荐
相关产品推荐

