Вот обходной путь для привязки столбцов в DataGrid. Поскольку свойство Columns имеет значение ReadOnly, как все заметили, я создал прикрепленное свойство под названием BindableColumns, которое обновляет столбцы в DataGrid каждый раз, когда коллекция изменяется через событие CollectionChanged.
Если у нас есть эта коллекция DataGridColumn's
public ObservableCollection<DataGridColumn> ColumnCollection
{
get;
private set;
}
Затем мы можем привязать BindableColumns к ColumnCollection следующим образом
<DataGrid Name="dataGrid"
local:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection}"
AutoGenerateColumns="False"
...>
Прикрепленное свойство BindableColumns
public class DataGridColumnsBehavior
{
public static readonly DependencyProperty BindableColumnsProperty =
DependencyProperty.RegisterAttached("BindableColumns",
typeof(ObservableCollection<DataGridColumn>),
typeof(DataGridColumnsBehavior),
new UIPropertyMetadata(null, BindableColumnsPropertyChanged));
private static void BindableColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
DataGrid dataGrid = source as DataGrid;
ObservableCollection<DataGridColumn> columns = e.NewValue as ObservableCollection<DataGridColumn>;
dataGrid.Columns.Clear();
if (columns == null)
{
return;
}
foreach (DataGridColumn column in columns)
{
dataGrid.Columns.Add(column);
}
columns.CollectionChanged += (sender, e2) =>
{
NotifyCollectionChangedEventArgs ne = e2 as NotifyCollectionChangedEventArgs;
if (ne.Action == NotifyCollectionChangedAction.Reset)
{
dataGrid.Columns.Clear();
foreach (DataGridColumn column in ne.NewItems)
{
dataGrid.Columns.Add(column);
}
}
else if (ne.Action == NotifyCollectionChangedAction.Add)
{
foreach (DataGridColumn column in ne.NewItems)
{
dataGrid.Columns.Add(column);
}
}
else if (ne.Action == NotifyCollectionChangedAction.Move)
{
dataGrid.Columns.Move(ne.OldStartingIndex, ne.NewStartingIndex);
}
else if (ne.Action == NotifyCollectionChangedAction.Remove)
{
foreach (DataGridColumn column in ne.OldItems)
{
dataGrid.Columns.Remove(column);
}
}
else if (ne.Action == NotifyCollectionChangedAction.Replace)
{
dataGrid.Columns[ne.NewStartingIndex] = ne.NewItems[0] as DataGridColumn;
}
};
}
public static void SetBindableColumns(DependencyObject element, ObservableCollection<DataGridColumn> value)
{
element.SetValue(BindableColumnsProperty, value);
}
public static ObservableCollection<DataGridColumn> GetBindableColumns(DependencyObject element)
{
return (ObservableCollection<DataGridColumn>)element.GetValue(BindableColumnsProperty);
}
}
CollectionChanged
событии коллекции столбцов, но никогда не отменяете его регистрацию. Таким образом,DataGrid
объект будет оставаться в живых до тех пор, пока существует модель представления, даже если шаблон элемента управления, который изначально содержалDataGrid
объект, был заменен. Есть ли какой-либо гарантированный способ снова отменить регистрацию этого обработчика событий, когда онDataGrid
больше не требуется?dataGrid.Columns.Add(column)
DataGridColumn с заголовком «X», уже существующим в коллекции Columns DataGrid. DataGrids не может совместно использовать столбцы и не может содержать повторяющиеся экземпляры столбцов.Я продолжил свои исследования и не нашел разумного способа сделать это. Свойство Columns в DataGrid не является чем-то, к чему я могу привязаться, на самом деле оно только для чтения.
Брайан предположил, что что-то можно сделать с помощью AutoGenerateColumns, поэтому я посмотрел. Он использует простое отражение .Net для просмотра свойств объектов в ItemsSource и генерирует столбец для каждого из них. Возможно, я мог бы «на лету» сгенерировать тип со свойством для каждого столбца, но это уже не так.
Поскольку эту проблему так легко решить в коде, я буду придерживаться простого метода расширения, который вызываю всякий раз, когда контекст данных обновляется новыми столбцами:
источник
Я нашел статью в блоге Деборы Курата с хорошим трюком, как показывать переменное количество столбцов в DataGrid:
Заполнение DataGrid динамическими столбцами в приложении Silverlight с помощью MVVM
По сути, она создает
DataGridTemplateColumn
и помещаетItemsControl
внутрь, отображающее несколько столбцов.источник
Мне удалось сделать возможным динамическое добавление столбца, используя только такую строку кода:
Что касается вопроса, это не решение на основе XAML (поскольку, как уже упоминалось, нет разумного способа сделать это), а также решение, которое будет работать напрямую с DataGrid.Columns. Фактически он работает с ItemsSource, привязанным к DataGrid, который реализует ITypedList и как таковой предоставляет настраиваемые методы для получения PropertyDescriptor. В одном месте кода вы можете определить «строки данных» и «столбцы данных» для своей сетки.
Если бы у вас были:
вы можете использовать, например:
и ваша сетка, использующая привязку к MyItemsCollection, будет заполнена соответствующими столбцами. Эти столбцы можно изменять (добавлять новые или удалять существующие) во время выполнения динамически, и сетка автоматически обновляет коллекцию столбцов.
Упомянутый выше DynamicPropertyDescriptor является просто обновлением обычного PropertyDescriptor и обеспечивает определение строго типизированных столбцов с некоторыми дополнительными параметрами. В противном случае DynamicDataGridSource отлично работал бы с базовым PropertyDescriptor.
источник
Сделал версию принятого ответа, которая обрабатывает отписку.
источник
Вы можете создать пользовательский элемент управления с определением сетки и определить «дочерние» элементы управления с различными определениями столбцов в xaml. Родителю требуется свойство зависимости для столбцов и метод загрузки столбцов:
родитель:
Дочерний Xaml:
И, наконец, самая сложная часть - найти, где вызвать LoadGrid.
Я борюсь с этим, но получил работу, вызвав after
InitalizeComponent
в моем конструкторе окна (childGrid - это x: name в window.xaml):Связанная запись в блоге
источник
Возможно, вы сможете сделать это с помощью AutoGenerateColumns и DataTemplate. Я не уверен, что это будет работать без большого количества работы, вам придется поиграть с этим. Честно говоря, если у вас уже есть рабочее решение, я бы пока не стал вносить изменения, если для этого нет веской причины. Элемент управления DataGrid становится очень хорошим, но он все еще нуждается в некоторой доработке (а мне еще предстоит много учиться), чтобы легко выполнять такие динамические задачи.
источник
Вот пример того, как я делаю это программно:
источник