How do I bind a WPF DataGrid to a variable number of columns?

后端 未结 8 1401
逝去的感伤
逝去的感伤 2020-11-22 10:29

My WPF application generates sets of data which may have a different number of columns each time. Included in the output is a description of each column that will be used t

8条回答
  •  粉色の甜心
    2020-11-22 11:06

    Made a version of the accepted answer that handles unsubscription.

    public class DataGridColumnsBehavior
    {
        public static readonly DependencyProperty BindableColumnsProperty =
            DependencyProperty.RegisterAttached("BindableColumns",
                                                typeof(ObservableCollection),
                                                typeof(DataGridColumnsBehavior),
                                                new UIPropertyMetadata(null, BindableColumnsPropertyChanged));
    
        /// Collection to store collection change handlers - to be able to unsubscribe later.
        private static readonly Dictionary _handlers;
    
        static DataGridColumnsBehavior()
        {
            _handlers = new Dictionary();
        }
    
        private static void BindableColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            DataGrid dataGrid = source as DataGrid;
    
            ObservableCollection oldColumns = e.OldValue as ObservableCollection;
            if (oldColumns != null)
            {
                // Remove all columns.
                dataGrid.Columns.Clear();
    
                // Unsubscribe from old collection.
                NotifyCollectionChangedEventHandler h;
                if (_handlers.TryGetValue(dataGrid, out h))
                {
                    oldColumns.CollectionChanged -= h;
                    _handlers.Remove(dataGrid);
                }
            }
    
            ObservableCollection newColumns = e.NewValue as ObservableCollection;
            dataGrid.Columns.Clear();
            if (newColumns != null)
            {
                // Add columns from this source.
                foreach (DataGridColumn column in newColumns)
                    dataGrid.Columns.Add(column);
    
                // Subscribe to future changes.
                NotifyCollectionChangedEventHandler h = (_, ne) => OnCollectionChanged(ne, dataGrid);
                _handlers[dataGrid] = h;
                newColumns.CollectionChanged += h;
            }
        }
    
        static void OnCollectionChanged(NotifyCollectionChangedEventArgs ne, DataGrid dataGrid)
        {
            switch (ne.Action)
            {
                case NotifyCollectionChangedAction.Reset:
                    dataGrid.Columns.Clear();
                    foreach (DataGridColumn column in ne.NewItems)
                        dataGrid.Columns.Add(column);
                    break;
                case NotifyCollectionChangedAction.Add:
                    foreach (DataGridColumn column in ne.NewItems)
                        dataGrid.Columns.Add(column);
                    break;
                case NotifyCollectionChangedAction.Move:
                    dataGrid.Columns.Move(ne.OldStartingIndex, ne.NewStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    foreach (DataGridColumn column in ne.OldItems)
                        dataGrid.Columns.Remove(column);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    dataGrid.Columns[ne.NewStartingIndex] = ne.NewItems[0] as DataGridColumn;
                    break;
            }
        }
    
        public static void SetBindableColumns(DependencyObject element, ObservableCollection value)
        {
            element.SetValue(BindableColumnsProperty, value);
        }
    
        public static ObservableCollection GetBindableColumns(DependencyObject element)
        {
            return (ObservableCollection)element.GetValue(BindableColumnsProperty);
        }
    }
    

提交回复
热议问题