You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF DataGrid虚拟化导致Expander图标与展开状态不一致的解决办法

WPF DataGrid虚拟化下自定义Expander状态不一致问题解决

问题

DataGrid启用行虚拟化时,自定义Expander点击展开后图标变为-,但滚动后图标变回+,而RowDetails仍保持展开状态。关闭虚拟化会导致数千行数据的性能问题,需要兼顾性能和状态一致性的方案。

原因

DataGrid虚拟化会回收不可见的行,Expander的IsExpanded状态仅存储在UI元素中,行被回收后状态丢失;而RowDetails的Visibility是通过后台代码手动设置的,和Expander状态没有绑定,导致两者脱节。

解决方案

将Expander的展开状态与数据模型绑定,让UI状态依赖于数据而非临时的UI元素状态,彻底解决虚拟化回收带来的状态丢失问题。

1. 扩展数据模型

给数据实体(如Patient类)添加IsDetailsExpanded属性并实现INotifyPropertyChanged:

public class Patient : INotifyPropertyChanged
{
    // 原有属性:FirstName, LastName, Total...

    private bool _isDetailsExpanded;
    public bool IsDetailsExpanded
    {
        get => _isDetailsExpanded;
        set
        {
            if (_isDetailsExpanded != value)
            {
                _isDetailsExpanded = value;
                OnPropertyChanged(nameof(IsDetailsExpanded));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 修改XAML绑定

添加转换器资源

在UserControl.Resources中添加布尔值转可见性的转换器:

<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

绑定DataGridRow的DetailsVisibility

修改DataGridRow的Style,将DetailsVisibility绑定到数据模型的属性:

<Style TargetType="{x:Type DataGridRow}">
    <Setter Property="Template">
        <!-- 原有Template内容保持不变 -->
    </Setter>
    <Setter Property="DetailsVisibility" 
            Value="{Binding IsDetailsExpanded, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</Style>

绑定Expander的IsExpanded

移除Expander的事件处理,双向绑定到数据模型属性:

<DataGridTemplateColumn Width="Auto">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Expander Template="{StaticResource SimpleExpanderTemp}"
                      IsExpanded="{Binding IsDetailsExpanded, Mode=TwoWay}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

3. 移除后台事件代码

删除后台的Expander_Expanded和Expander_Collapsed方法,状态同步完全通过绑定实现:

public partial class OutstandingPatientDataGrid : UserControl
{
    public OutstandingPatientDataGrid()
    {
        InitializeComponent();
    }
    // 移除两个事件处理方法
}

效果说明

  • 点击Expander时,IsDetailsExpanded属性更新,同步RowDetails的显示状态
  • 行被虚拟化回收后,复用行时会从数据模型读取IsDetailsExpanded值,自动同步Expander图标和RowDetails状态
  • 保持虚拟化开启,确保大数据量下的性能

内容的提问来源于stack exchange,提问作者May Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 22:24:54