Как я могу установить ширину DataGridColumn, чтобы соответствовать содержимому («Авто»), но полностью заполнить доступное пространство для DataGrid в MVVM? - PullRequest
21 голосов
/ 15 февраля 2011

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

<DataGrid ItemsSource="{Binding Table}">
    <DataGrid.Columns>
        <DataGridTextColumn MinWidth="100" Width="Auto" Header="Column 1" Binding="{Binding Property1}" />
        <DataGridTextColumn MinWidth="200" Width="Auto" Header="Column 2" Binding="{Binding Property2}" />
    </DataGrid.Columns>
</DataGrid>

Это явно не работает из коробки с Width="Auto", так как всегда выглядит примерно так:

DataGrid: only the first part of the row is marked as

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

Если я вместо этого использую Width="*", содержимое столбцов обрезается, что для меня даже хуже.

Я нашел подобный вопрос здесь , и там был опубликован обходной путь. Это может работать, но я работаю с шаблоном MVVM, поэтому ItemsSource обновляется в ViewModel , и я не могу думать о способе сделать это оттуда, потому что я не могу получить доступ к свойству ActualWidth DataGridColumn. Кроме того, я хотел бы сделать это только в XAML, если это возможно.

Буду признателен за любую помощь. Спасибо!

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

Редактировать 2: После ответа Сауса я снова подумал о вариантах. Проблема в том, что мне нужно обновлять свойства Width и MinWidth также во время работы приложения, а не только после загрузки окна. Я уже пытался сделать что-то вроде

column.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
column.MinWidth = column.ActualWidth;
column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);

в некоторых случаях, которые запускаются при обновлении базового ItemsSource DataGrid. Однако это не работает, так как свойство ActualWidth, похоже, не меняется после установки Width на Auto. Есть ли возможность как-то «перекрасить» его для обновления свойства ActualWidth? Спасибо!

Ответы [ 7 ]

30 голосов
/ 18 февраля 2011

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

Griddy.Loaded += SetMinWidths; // I named my datagrid Griddy

и определите SetMinWidths как:

public void SetMinWidths(object source, EventArgs e )
        {
            foreach (var column in Griddy.Columns)
            {
                column.MinWidth = column.ActualWidth;
                column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
            }
        }

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

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

public class SetMinWidthToAutoAttachedBehaviour 
    {
        public static bool GetSetMinWidthToAuto(DependencyObject obj)
        {
            return (bool)obj.GetValue(SetMinWidthToAutoProperty);
        }

        public static void SetSetMinWidthToAuto(DependencyObject obj, bool value)
        {
            obj.SetValue(SetMinWidthToAutoProperty, value);
        }

        // Using a DependencyProperty as the backing store for SetMinWidthToAuto.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SetMinWidthToAutoProperty =
            DependencyProperty.RegisterAttached("SetMinWidthToAuto", typeof(bool), typeof(SetMinWidthToAutoAttachedBehaviour), new UIPropertyMetadata(false, WireUpLoadedEvent));

        public static void WireUpLoadedEvent(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = (DataGrid)d;

            var doIt = (bool)e.NewValue;

            if (doIt)
            {
                grid.Loaded += SetMinWidths;
            }
        }

        public static void SetMinWidths(object source, EventArgs e)
        {
            var grid = (DataGrid)source;

            foreach (var column in grid.Columns)
            {
                column.MinWidth = column.ActualWidth;
                column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
            }
        }
    }

, а затем для любой таблицы данных, к которой вы хотите применить это поведение, добавьте следующее:

<DataGrid ItemsSource="{Binding Table}" local:SetMinWidthToAutoAttachedBehaviour.SetMinWidthToAuto="true">

И тогда ваша совесть, а также ваш код будут ясны.

4 голосов
/ 15 февраля 2011

Использовать TextBlock с переносом текста внутри столбца шаблона:

<DataGrid ItemsSource="{Binding Table}">      
    <DataGrid.Columns>          
        <DataGridTextColumn MinWidth="100" Width="Auto" Header="Column 1"
                            Binding="{Binding Property1}" />          
        <DataGridTemplateColumn Width="*" Header="Column 2">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Property2}" TextWrapping="Wrap" />  
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>  
</DataGrid>
1 голос
/ 21 июня 2016

Я добавил Event к DataGrid, который переопределяет их ширину относительно фактической ширины DataGrid:

 private static void OnLoaded(object sender, RoutedEventArgs e)
    {
        DataGrid dg = sender as DataGrid;
        foreach (var column in dg.Columns)
        {
            column.Width = new DataGridLength(dg.ActualWidth / dg.Columns.Count, DataGridLengthUnitType.Pixel);
        }
    }

Строка:

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

был абсолютно бессмысленным. Определение DataGridLengthUnitType.Star уменьшает ширину столбцов до их минимальной ширины и делает их ширину статичной и недоступной для редактирования.

1 голос
/ 17 февраля 2011

как насчет этого:

для ваших столбцов MinWidth, вы устанавливаете привязку к ширине ScrollContent объекта DataGrid с помощью преобразователя, который делит эту ширину на количество столбцов

вам нужен код для конвертера, но это сохранит вашу структуру MVVM нетронутой.

может быть длинным выстрелом, но у него не было времени попробовать.

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

Возможно, вы захотите исследовать этот путь, хотя. Использование привязок для Widths с конвертерами - единственное, о чем я могу подумать: это может сработать: поскольку у вас есть два условия, которые необходимо учитывать при расчете ширины столбца, простого способа сделать это не будет.

1 голос
/ 15 февраля 2011

Если вы хотите, чтобы столбец никогда не обрезал ваши данные, добавьте следующее в определение Window / UserControl:

xmlns:System="clr-namespace:System;assembly=mscorlib"

Тогда для ширины столбцов вы можете использовать следующие.

 Width="{x:Static System:Double.NaN}"

Это делает столбец всегда достаточно широким, чтобы вместить самое длинное значение в столбце.

Поскольку приведенный выше код не работал в DataGrid, как насчет добавления ScrollViewer вокруг DataGrid следующим образом:

     <ScrollViewer HorizontalScrollBarVisibility="Auto" 
                  VerticalScrollBarVisibility="Auto">
        <DataGrid ItemsSource="{Binding Table}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn MinWidth="10" Width="Auto"  Header="Column 1" Binding="{Binding Property1}" />
                <DataGridTextColumn MinWidth="200" Width="*" Header="Column 2" Binding="{Binding Property2}" />                    
            </DataGrid.Columns>
        </DataGrid>
    </ScrollViewer>
0 голосов
/ 16 января 2019

используйте это для любого столбца, который вы хотите подогнать под его содержимое: Width = "SizeToCells"

0 голосов
/ 17 апреля 2014

Заставить последний столбец занять все оставшееся пространство в сетке данных

grid.Columns[grid.Columns.Count -1].Width = new 
                  DataGridLength(250, DataGridLengthUnitType.Star);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...