Как сделать последний столбец в datagrid WPF, чтобы все левое пространство было всегда?

Стандартный WPF 4 Datagrid.

Скажем, у меня есть datagrid 200 пикселей в ширину и 2 столбца. Я бы хотел, чтобы столбцы всегда занимали все пространство, а это означает, что пользователь изменит размер первого столбца на 50 пикселей, а последний будет равен 150.

Сначала я установил ширину 100 пикселей для 1-го столбца и * для последнего (в XAML).

Я думал, что проблема заключается в удалении виртуального третьего столбца, как описано здесь:

http://wpf.codeplex.com/Thread/View.aspx?ThreadId=58939

но нет никакой разницы - все же, при изменении размеров столбцов я получаю дополнительное пространство справа - с виртуальным столбцом, это виртуальный столбец (по умолчанию белый цвет), без него это пустое пространство (по умолчанию серый).

ВОПРОС: как принудительно применять ограничение, независимо от того, как пользователь изменяет размеры столбцов,

sum(columns width)==datagrid width

?

редактирует

Да, я использую WPF 4.

РЕШЕНИЕ

Я назвал один из ответов как решение, но на самом деле это не решение из-за дизайна WPF. Это просто то, что WPF может сделать в лучшем случае, и это не очень хорошо - в первую очередь опция CanUserResize для столбца означает действительно IsResizeable, и эта опция при включении противоречит Шире, установленной на *. Поэтому без какого-либо действительно умного трюка вы получите:

  • datagrid, который последний столбец в поверхностном изменении размера, но на самом деле это не так, и отображается небольшое пространство справа (т.е. виртуальный столбец не изменяется) - для последнего столбца: CanUserResize = true, Width = *

  • datagrid, для которого последний столбец не может быть изменен пользователем, и показано соответственно, изначально не отображается пробел справа, но его можно показать, когда пользователь изменяет размер любого элемента datagrid - для последнего столбца: CanUserResize = false, Width = *

До сих пор я вижу две проблемы с WPat datagrid:

  • вводящего в заблуждение наименования
  • противоречие функций

У меня все еще есть уши, чтобы решить эту проблему.

Ответ 1

Установите ширину сетки данных в значение "Авто". Вы позволяете столбцам правильно изменять размеры внутри самой сетки, но у вас есть проводная ширина до 200.

ОБНОВЛЕНИЕ. Основываясь на комментарии @micas, я, возможно, неправильно понял. В этом случае попробуйте использовать 100 для левой ширины столбца и 100 * для правого столбца (обратите внимание на звездочку). Это будет использоваться по умолчанию для ширины для правого столбца до 100, но позволяет изменять размер для заполнения сетки.

Ответ 2

Вы можете установить ширину столбца на звездочку по коду. В своем конструкторе добавьте:

    Loaded += (s, e) => dataGrid1.Columns[3].Width =
new DataGridLength(1, DataGridLengthUnitType.Star);

Ответ 3

Я только что реализовал это как присоединенное поведение. Проблема заключается в том, что вы установите последний столбец DataGrid на *, он изменит размер, чтобы соответствовать, но тогда все автоподбор других ячеек испортится. Чтобы решить эту проблему, приложенное поведение выполняет автоматическую подгонку вручную других (не последних) ячеек.

Это также работает при изменении размера других столбцов - после загрузки вы можете изменить размер, и последний столбец будет всегда заполняться. Обратите внимание, что это поведение работает один раз в событии Loaded

// Behavior usage: <DataGrid DataGridExtensions.LastColumnFill="True"/>
public class DataGridExtensions
{
    public static readonly DependencyProperty LastColumnFillProperty = DependencyProperty.RegisterAttached("LastColumnFill", typeof(bool), typeof(DataGridExtensions), new PropertyMetadata(default(bool), OnLastColumnFillChanged));

    public static void SetLastColumnFill(DataGrid element, bool value)
    {
        element.SetValue(LastColumnFillProperty, value);
    }

    public static bool GetLastColumnFill(DataGrid element)
    {
        return (bool)element.GetValue(LastColumnFillProperty);
    }

    private static void OnLastColumnFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var dataGrid = d as DataGrid;
        if (dataGrid == null) return;

        dataGrid.Loaded -= OnDataGridLoaded;
        dataGrid.Loaded += OnDataGridLoaded;
    }        

    private static void OnDataGridLoaded(object sender, RoutedEventArgs e)
    {
        var dataGrid = sender as DataGrid;
        if (dataGrid == null) return;

        var lastColumn = dataGrid.Columns.LastOrDefault();
        if(lastColumn != null)
            lastColumn.Width = new DataGridLength(1, DataGridLengthUnitType.Star);

        // Autofit all other columns
        foreach (var column in dataGrid.Columns)
        {
            if (column == lastColumn) break;

            double beforeWidth = column.ActualWidth;
            column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToCells);
            double sizeCellsWidth = column.ActualWidth;
            column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToHeader);
            double sizeHeaderWidth = column.ActualWidth;
            column.MinWidth = Math.Max(beforeWidth, Math.Max(sizeCellsWidth, sizeHeaderWidth));
        }
    }
}

Ответ 4

Будьте предупреждены: это хак....

Я зарегистрировался на событие "AutoGeneratedColumns" в методе "OnLastColumnFillChanged" Dr. ABT и скопировал в него Loaded-метод, и он работает. Я еще не проверил его еще раз, поэтому YMMV.

Мое изменение:

    private static void OnLastColumnFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var dataGrid = d as DataGrid;
        if (dataGrid == null) return;

        dataGrid.Loaded -= OnDataGridLoaded;
        dataGrid.Loaded += OnDataGridLoaded;

        dataGrid.AutoGeneratedColumns -= OnDataGrid_AutoGeneratedColumns;
        dataGrid.AutoGeneratedColumns += OnDataGrid_AutoGeneratedColumns;
    }

    private static void OnDataGrid_AutoGeneratedColumns(object sender, EventArgs e)
    {
        var dataGrid = sender as DataGrid;
        if (dataGrid == null) return;

        var lastColumn = dataGrid.Columns.LastOrDefault();
        if (lastColumn != null)
            lastColumn.Width = new DataGridLength(1, DataGridLengthUnitType.Star);

        // Autofit all other columns
        foreach (var column in dataGrid.Columns)
        {
            if (column == lastColumn) break;

            double beforeWidth = column.ActualWidth;
            column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToCells);
            double sizeCellsWidth = column.ActualWidth;
            column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToHeader);
            double sizeHeaderWidth = column.ActualWidth;
            column.MinWidth = Math.Max(beforeWidth, Math.Max(sizeCellsWidth, sizeHeaderWidth));
        }
    }

О, и не забудьте добавить пространство имен в объявление XAML!:)

Вверх сверху:

xmlns:ext="clr-namespace:TestProject.Extensions"

И затем в объявлении DataGrid:

ext:DataGridExtensions.LastColumnFill="True"

Обновление: Я сказал, что пробег будет меняться! Конечно, шахта.

Этот бит "автофитурных столбцов" вызвал некоторые из моих столбцов в DataGrid с переменным числом столбцов только шириной, чем заголовок столбца. Я удалил эту часть, и теперь она, похоже, работает со всеми DataGrids в приложении.

Теперь у меня есть:

    private static void OnDataGrid_AutoGeneratedColumns(object sender, EventArgs e)
    {
        var dataGrid = sender as DataGrid;
        if (dataGrid == null) return;

        UpdateColumnWidths(dataGrid);

    }

    private static void OnDataGridLoaded(object sender, RoutedEventArgs e)
    {
        var dataGrid = sender as DataGrid;
        if (dataGrid == null) return;

        UpdateColumnWidths(dataGrid);
    }

    private static void UpdateColumnWidths(DataGrid dataGrid)
    {
        var lastColumn = dataGrid.Columns.LastOrDefault();
        if (lastColumn == null) return;

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

    }

Ответ 5

Здесь очень простой ответ, все выполнено в коде позади. :-) Все столбцы будут автоматически измерены; последний столбец заполнит все оставшееся пространство.

// build your datasource, e.g. perhaps you have a:
List<Person> people = ...

// create your grid and set the datasource
var dataGrid = new DataGrid();
dataGrid.ItemsSource = people;

// set AutoGenerateColumns to false and manually define your columns
// this is the price for using my solution :-)
dataGrid.AutoGenerateColumns = false;

// example of creating the columns manually.
// there are obviously more clever ways to do this 
var col0 = new DataGridTextColumn();
col0.Binding = new Binding("LastName");
var col1 = new DataGridTextColumn();
col1.Binding = new Binding("FirstName");
var col2 = new DataGridTextColumn();
col2.Binding = new Binding("MiddleName");
dataGrid.Columns.Add(col0);
dataGrid.Columns.Add(col1);
dataGrid.Columns.Add(col2);

// Set the width to * for the last column
col2.Width = new DataGridLength(1, DataGridLengthUnitType.Star);