Как изменить размер WPF DataGrid в соответствии с его содержимым? - PullRequest
21 голосов
/ 02 января 2011

Цель

Я хотел бы установить такой размер для 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;
    }

Ответы [ 5 ]

20 голосов
/ 27 мая 2011

Я только что вышел из той же проблемы, когда мне пришлось задать параметры в столбце сетки данных, чтобы они соответствовали его ширине в соответствии с содержимым как заголовка, так и ячейки.Я использовал следующий код:

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);

ДЛЯ ВСЕХ КОЛОНН .... .... Убедитесь, что вы сохраняете HorizontalScrollVisibility в Auto.

8 голосов
/ 02 января 2011

Если я правильно понял ваш вопрос, и вы хотите:

  1. A 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, которая находится вокруг него, поэтому желаемый результат достигнут.

2 голосов
/ 16 марта 2017

SizeToCells - это то, что у меня сработало. Мне нравится это, потому что это в XAML и это сжато.

<DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="Name" Width="SizeToCells"/>
1 голос
/ 20 июля 2018

В моем случае я обнаружил, что DataGrid по умолчанию использует HorizontalAlignment="Stretch" VerticalAlignment="Stretch", поэтому я установил его на

<DataGrid ItemsSource="{Binding Source}" Width="Auto" Height="Auto" 
          HorizontalAlignment="Center" VerticalAlignment="Center"/>

Тогда работает.

1 голос
/ 18 ноября 2011

Комментарий Марко - это ответ:

Я немного растерялся из-за твоей логики изменения размера. Прежде всего, если вы установите окно SizeToContent="WidthAndHeight", тогда окно будет показано в полном размере сетки данных. С другой стороны, если вы показываете окно в некотором предопределенном размере, и вы хотите изменить размер окна после того, как окно показывается, то в этот момент изменение размера до требуемой таблицы данных очень противоречит интуиции. Потому что изменение размера будет прыгать, скажем, с 100px до 400px, но что если я захочу изменить размер до 250px ... (если вы изменяете размер, перетаскивая угол окна)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...