I'm using a standard .NET DataGrid like this:
<DataGrid ItemsSource="{Binding Datensaetze}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="my col 1" Binding="{Binding MyCol1}"/>
<DataGridTextColumn Header="my col 2" Binding="{Binding MyCol2}"/>
<DataGridTextColumn Header="my col 3" Binding="{Binding MyCol3}"/>
</DataGrid.Columns>
</DataGrid>
This is working nicely. Now I want to define the columns in the ViewModel, and instead of setting fixed columns in xaml I want to generate them on the fly. However, if I try to bind the Columns to anything I get an error, saying
DataGrid.Columns is a readonly property and can't be bound.
Is there a way to dynamically bind the DataGrid columns to something in code behind?
Yes, the Columns Property is ReadOnly so we can't bind to it directly. If you want to Bind Columns then you can try to use an attached property which you bind to, which in turn updates the Columns.
Update
Using delta of changes in the CollectionChanged event.
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);
}
}
Then you can bind the BindableColumns property to your ColumnsCollection
<DataGrid AutoGenerateColumns="False"
local:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection}">
<!-- ... -->
</DataGrid>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With