DataGrid列宽在ItemsSource更改时未更新。

5

XAML:

<DataGrid.Columns>
    <DataGridTextColumn x:Name="colDisplayName" Width="Auto" IsReadOnly="True" Header="Name" Binding="{Binding ssn.SSN_DISPLAY_NAME}"></DataGridTextColumn>
    <DataGridTextColumn x:Name="colValue" Width="Auto" Header="Value" Binding="{Binding ssv.SSV_VALUE}" CellStyle="{StaticResource SingleClickEditing}"></DataGridTextColumn>
    <DataGridTextColumn x:Name="colDescription" Width="Auto" IsReadOnly="True" Header="Description" Binding="{Binding ssn.SSN_DESCRIPTION}"></DataGridTextColumn>
    <DataGridTextColumn x:Name="colUnit" Width="Auto" IsReadOnly="True" Header="Unit Abbreviation" Binding="{Binding ssn.UNIT_TYPE.UNIT_NAME.UN_ABBREVIATION}"></DataGridTextColumn>
    </DataGrid.Columns>

CS:

private void tvSystemConfiguration_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
       {
           dgSystemSettings.ItemsSource =
               ((tvSystemConfiguration.SelectedItem as SYSTEM_SETTINGS_GROUP).SYSTEM_SETTINGS_NAMEs.Join
               (ssdc.SYSTEM_SETTINGS_VALUEs, x => x.SSN_ID, y => y.SSV_SSN_ID, (x, y) => new DataGridItem{ ssn = x, ssv = y })).ToList();
       }

当列宽增加时,它会正确地缩小以适应大小,但是当列宽减小时,它并没有正确地缩小以适应大小。在ItemsSource更新后,即使它已经增加,也不会减小列的大小。希望这样说得清楚。任何帮助都将不胜感激。谢谢。

4个回答

8

对不起,这段话对我来说没有任何意义。

我理解了代码,但是这一部分:

当列大小增加时,列宽度会自动缩小以正确适应内容,但是当列大小减小时,列宽度不会正确地自动缩小以适应内容。在 ItemsSource 更新后,它将不会减小列的大小。

让我感到困惑。

我理解成这样:

如果列中内容的宽度增加,则列的宽度也会增加,但是如果内容的宽度减少,则列的宽度不会减少。

是这样吗?

如果是这样,这种行为是正常的:WPF 只会在需要时重新调整设置为“自动”的 DataGrid 列宽度,即:无法完全显示内容。因此,当内容的宽度缩小时,列不会重新调整大小,因为内容仍然可以完全显示。

我能想到的唯一强制 WPF 重新计算列宽度的方法就是在代码后端将它们全部强制设置为 0,然后再设置为自动,其中插入一两个 updateLayout(),但这不是很好的编程方式 :-/。

编辑: 基本上,在您的代码后端:

foreach (DataGridColumn c in dg.Columns)
    c.Width = 0;

// Update your DG's source here

foreach (DataGridColumn c in dg.Columns)
    c.Width = DataGridLength.Auto;

你可能需要在其中某处添加 dg.UpdateLayout()(在更新和重新设置为auto之后)。


2
是的,这正是我的问题,所有内容都可以完美地增加,但当列的内容缩小时,它无法正确调整列宽。 - jes9582
我也尝试在selecteditemchanged事件中将datagrid.itemssource设置为null,然后再次设置它,以尝试强制列仅增加,但似乎没有起作用。 - jes9582
是的,我能想到的唯一解决方案就是所描述的:清空数据表格的源,将所有列的宽度强制设为0,执行updateLayout(),然后将宽度重新设置为Auto,最后更新源。但这样会在屏幕上产生“闪烁”。 - David
有没有关于在代码后端强制宽度自动的建议? - jes9582
myColumn.Width = DataGridLength.Auto --- 请参见:http://msdn.microsoft.com/zh-cn/library/system.windows.controls.datagridlength%28v=VS.95%29.aspx - David
谢谢,伙计。我整个早上都在为了解决这个问题而疯狂地努力。我很感激你的帮助。 - jes9582

4

为了方便大家,这里提供一个基于David答案的扩展方法:

public static void AutoResizeColumnWidths(this System.Windows.Controls.DataGrid dataGrid)
{
    // https://dev59.com/VVPTa4cB1Zd3GeqPjn_P
    foreach (var column in dataGrid.Columns)
        column.Width = 0;

    dataGrid.UpdateLayout();

    foreach (var column in dataGrid.Columns)
        column.Width = System.Windows.Controls.DataGridLength.Auto;

    dataGrid.UpdateLayout();
}

它应该被称为:

dataGrid.AutoResizeColumnWidths();

使用Silverlight时,我只需要第一个UpdateLayout。此外,我还必须使用column.Width = new DataGridLength(0)。 - Mike Fuchs

1
屏幕上闪烁的内容和行数都减少了,不需要调用updateLayout函数。
            foreach (DataGridColumn col in dg.Columns)
            {
                col.Width = DataGridLength.SizeToCells;
                col.Width = DataGridLength.Auto;
            }

完美。谢谢。 - Brian Berns

0

也许我可以帮忙。我曾经遇到过同样的问题,但我找到了一个不错的解决方案。

private void DataGrid_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        DataGrid dg = (DataGrid)sender;
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            double width = 0;
            foreach (DataGridColumn column in dg.Columns)
            {
                width += column.ActualWidth;
            }
            dg.Width = width + 2;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接