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

求助:WPF DataGrid首次加载列尺寸异常,窗口调整后恢复正常

WPF DataGrid 列尺寸异常问题修复

问题描述

DataGrid中多数列设为Auto宽度,仅一列设为*,首次加载时列尺寸显示异常(*列挤占其他列导致内容截断),窗口最大化后显示恢复正常。注释转换器、简化列数、给异常列设置MinWidth等操作仅会转移问题,无法彻底解决。需求是实现Auto列自适应内容宽度、*列填充剩余屏幕空间的布局。

相关XAML代码:

<Grid>
    <DataGrid AutoGenerateColumns="False"
              GridLinesVisibility="Horizontal"
              CanUserAddRows="False"
              IsReadOnly="True"
              x:Name="PartsGrid"
              CanUserSortColumns="True"
              ItemsSource="{Binding Source}"
              SelectedItem="{Binding SelectedItem}"
              Margin="{StaticResource SmallLeftRightMargin}"
              KeyboardNavigation.TabNavigation="Once">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Date, StringFormat={}{0:yy/MM/dd HH:mm}}"
                                Header="Date" />
            <DataGridTextColumn Binding="{Binding Name}"
                                Header="Name"
                                Width="*" />
            <DataGridTextColumn Binding="{Binding Quantity}"
                                Header="Qty" />
            <DataGridTextColumn Binding="{Binding Thickness}"
                                Header="Thickness" />
            <DataGridTextColumn Binding="{Binding Material}"
                                Header="Material" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

解决方案

方法1:Loaded事件中强制刷新布局

在DataGrid的Loaded事件触发后,强制更新布局并重置*列宽度,确保列尺寸计算时机正确:

<DataGrid ... Loaded="PartsGrid_Loaded">
    <!-- 列定义 -->
</DataGrid>

后台代码:

private void PartsGrid_Loaded(object sender, RoutedEventArgs e)
{
    var dataGrid = sender as DataGrid;
    dataGrid?.UpdateLayout();
    
    // 重置*列宽度,触发重新计算
    if (dataGrid?.Columns[1] is DataGridTextColumn starColumn)
    {
        starColumn.Width = new DataGridLength(0, DataGridLengthUnitType.Star);
        starColumn.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
    }
}

方法2:绑定DataGrid宽度到父容器ActualWidth

避免DataGrid因父容器布局未稳定导致宽度计算错误,直接绑定到父Grid的实际宽度:

<Grid x:Name="ParentGrid">
    <DataGrid ... Width="{Binding ActualWidth, ElementName=ParentGrid}">
        <!-- 列定义 -->
    </DataGrid>
</Grid>

方法3:禁用横向滚动并显式声明Auto列

如果不需要横向滚动,禁用HorizontalScrollBarVisibility,同时给Auto列显式设置Width="Auto",确保布局计算基于可用空间:

<DataGrid ... HorizontalScrollBarVisibility="Disabled">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Date, StringFormat={}{0:yy/MM/dd HH:mm}}"
                            Header="Date"
                            Width="Auto" />
        <DataGridTextColumn Binding="{Binding Name}"
                            Header="Name"
                            Width="*" />
        <DataGridTextColumn Binding="{Binding Quantity}"
                            Header="Qty"
                            Width="Auto" />
        <DataGridTextColumn Binding="{Binding Thickness}"
                            Header="Thickness"
                            Width="Auto" />
        <DataGridTextColumn Binding="{Binding Material}"
                            Header="Material"
                            Width="Auto" />
    </DataGrid.Columns>
</DataGrid>

方法4:异步数据加载后延迟计算宽度

如果ItemsSource是异步加载的,在数据加载完成后延迟触发宽度计算,确保内容已渲染:

// 数据加载完成后调用此方法
private void RefreshColumnWidths()
{
    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
    {
        PartsGrid.UpdateLayout();
        foreach (var column in PartsGrid.Columns)
        {
            if (column.Width.IsStar)
            {
                var tempWidth = column.Width;
                column.Width = new DataGridLength(0, DataGridLengthUnitType.Auto);
                column.Width = tempWidth;
            }
        }
    }));
}

原理说明

首次加载时,DataGrid的布局计算优先级低于父容器,导致*列提前占用过多空间,Auto列尚未完成内容宽度计算。通过强制刷新布局、延迟计算或绑定宽度到稳定的父容器尺寸,可让Auto列先计算出所需宽度,*列再填充剩余空间。

内容的提问来源于stack exchange,提问作者Bas Nederveen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:50:54