prism/mvvm: binding Columns to DataGrid

2019-02-07 07:50发布

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?

1条回答
我想做一个坏孩纸
2楼-- · 2019-02-07 08:28

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>
查看更多
登录 后发表回答