如何调整WPF DataGrid以适应其内容?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (465)

目的

我想为DataGrid(标准,来自WPF)设置这样的大小,以便所有单元格(文本)都可以完全可见。我有DockPanel的窗口,里面有DataGrid,所以当我调整窗口的大小时,所有嵌套的小部件(DockPanel和DataGrid)都会相应地调整大小。

示例(edit-1)

假设你有一个窗口,宽度为100像素,并且DataGrid有一列,该单元格是“快速棕色狐狸......”(400像素宽)。因此,DataGrid应该调整到400像素(可能更多,因为填充),窗口也应调整到400像素(也更多,因为填充)。

我没有找到任何标准方法来做到这一点(AFAIK WPF提供了将内容剪辑到所需宽度的方式,我的问题恰恰相反),所以我想出了这样丑陋的解决方法,这不太好。

解决方法

  1. 遍历DataGrid标题(假设它们只是字符串)并计算文本所需的宽度
  2. 迭代每列的DataGrid行(假设它们是TextBlock或TextBox)并计算文本所需的最大宽度 - 为TextBlock / TextBox添加水平填充和DataGrid单元格的水平边距
  3. 总结列的DataGrid ActualWidth和(2)中计算的最大宽度之间的所有差异,
  4. (3)中计算的差值增加窗口宽度,

问题

我做了几次测试,在某些情况下,计算的宽度太大(这是小问题),因为有些情况太小。问题从其核心程序开始 - 计算TextBox / TextBlock所需的宽度,计算出的宽度始终小于1个单位(如果将宽度设置为计算的宽度,则文本中的1个像素始终被剪切)。

那么我在这里忽略哪个因素?或者也许更好 - 是否有一些方法来调整DataGrid的大小以适应其内容?

代码

计算文本所需的宽度(此处为TextBlock):

    public static double TextWidth(this TextBlock widget, string text)
    {
        var formattedText = new FormattedText(text, // can use arbitrary text
                                              System.Globalization.CultureInfo.CurrentCulture,
                                              widget.FlowDirection,
                                              widget.FontFamily.GetTypefaces().FirstOrDefault(),
                                              widget.FontSize, 
                                              widget.Foreground);

        return formattedText.Width+widget.Padding.Left+widget.Padding.Right;
    }

调整窗口大小以适应DataGrid内容(ugly_factor是丑陋的解决方法;-),因为我没有弄清楚如何正确地修复它我将它设置为1.3,这样我的窗口“从不”太小):

    public static void AdjustWidthToDataGrid(this Window window, DataGrid dataGrid, double ugly_factor)
    {
        var max_widths = dataGrid.Columns.Select(it => window.TextWidth(it.Header as string) 
                                                                        * ugly_factor).ToArray();

        foreach (var row in Enumerable.Range(0, dataGrid.Items.Count))
            foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))
            {
                var cell = dataGrid.GetCell(row, col);
                double width = 0;
                if (cell.Content is TextBlock)
                    width = (cell.Content as TextBlock).TextWidth();
                else if (cell.Content is TextBox)
                    width = (cell.Content as TextBox).TextWidth();

                if (cell.Content is FrameworkElement)
                {
                    var widget = cell.Content as FrameworkElement;
                    width = width + widget.Margin.Left + widget.Margin.Right;
                }

                max_widths[col] = Math.Max(max_widths[col], 
                                           width*ugly_factor+cell.Padding.Left+cell.Padding.Right);
            }

        double width_diff = 0;

        foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))
            width_diff += Math.Max(0,max_widths[col] - dataGrid.Columns[col].ActualWidth);

        if (width_diff > 0)
            window.Width = window.ActualWidth+ width_diff;
    }
提问于
用户回答回答于

如果我理解你的问题并且你想要:

  1. 一个DataGrid,列的宽度与其最宽的内容一样宽。
  2. DataGrid适合其内容。

这可以通过数据绑定来实现:

<DataGrid AutoGenerateColumns="False"
          EnableRowVirtualization="True"
          Height="111"
          HorizontalAlignment="Left"
          ItemsSource="{Binding}"
          Margin="72,203,0,0"
          Name="dataGrid"
          RowDetailsVisibilityMode="VisibleWhenSelected"
          VerticalAlignment="Top"
          Width="{Binding Path=ActualWidth, ElementName=grid}">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="Column1"
                            Binding="{Binding Path=Something1}"
                            Header="Column1" 
                            Width="Auto"  />
        <DataGridTextColumn x:Name="Column2"
                            Binding="{Binding Path=Something2}"
                            Header="Column2"
                            Width="*" />
    </DataGrid.Columns>
</DataGrid>

这里第一列是需要的宽度,第二列是剩下的可用空间。然而,DataGrid的宽度与其周围的Grid的宽度相同,因此达到了想要的结果。

用户回答回答于

我只是出于同样的问题,我必须在数据网格的列中提供选项,以根据标题和单元格的内容来适应其宽度。我使用了下面的代码:

private void FitToContent()
    {
        // where dg is my data grid's name...
        foreach (DataGridColumn column in dg.Columns)
        {
            //if you want to size ur column as per the cell content
            column.Width = new DataGridLength(1.0, DataGridLengthUnitType.SizeToCells);
            //if you want to size ur column as per the column header
            column.Width = new DataGridLength(1.0, DataGridLengthUnitType.SizeToHeader);
            //if you want to size ur column as per both header and cell content
            column.Width = new DataGridLength(1.0, DataGridLengthUnitType.Auto);
        }
    }

此外,我提供了一个选项列以适应显示器(数据网格的宽度)。为此,我使用了以上相同的代码,并进行了以下小改动:

column.Width = new DataGridLength(1.0, DataGridLengthUnitType.Star);

FOR ALL COLUMNS .... :)确保您将Horizo​​ntalScrollVisibility保持为自动。

扫码关注云+社区

领取腾讯云代金券