【问题标题】:prism/mvvm: binding Columns to DataGridprism/mvvm:将列绑定到 DataGrid
【发布时间】:2010-12-06 14:15:27
【问题描述】:

我正在使用这样的标准 .NET DataGrid:

<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>

这很好用。现在我想在 ViewModel 中定义列,而不是在 xaml 中设置固定列,我想动态生成它们。但是,如果我尝试将 Columns 绑定到任何东西,我会得到一个错误,说

DataGrid.Columns 是只读属性,不能绑定。

有没有办法将 DataGrid 列动态绑定到代码后面的内容?

【问题讨论】:

    标签: wpf binding mvvm datagrid prism


    【解决方案1】:

    是的,Columns 属性是只读的,所以我们不能直接绑定到它。如果要绑定列,则可以尝试使用绑定到的附加属性,从而更新列。

    更新
    在 CollectionChanged 事件中使用更改增量。

    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);
        }
    }
    

    然后您可以将 BindableColumns 属性绑定到您的 ColumnsCollection

    <DataGrid AutoGenerateColumns="False"
              local:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection}">
        <!-- ... -->
    </DataGrid>
    

    【讨论】:

    • 我一直在使用它,但是我遇到了一个问题,我需要在后台线程上更新 ObservableCollection(我正在使用 Dispatcher 来执行此操作)。然后,上面的代码在 CollectionChanged 委托中失败,并出现错误“调用线程无法访问此对象,因为不同的线程拥有它”。有什么建议吗?
    • 我和安德鲁·斯蒂芬斯的情况一样。找不到解决办法。有人帮忙吗?
    • 我认为您必须先取消绑定项目源,然后才能在后台线程中更新它。您无法在后台线程中访问绑定到 UI(使用 raisepropertychanged/collectionchanged)的任何对象。另一种选择是使用您应该在后台线程中更改/访问的不同对象。然后使用 Continue with(如果您正在使用任务)然后将该对象传递给 ContinueWith 块。
    • 只是这个解决方案的一个后续问题,现在我有一个动态列,我怎样才能有一个动态项目源/单元格值到这个列?
    • 没关系,我明白了,我只是做了一个索引属性并使用列标题将其绑定到列。
    猜你喜欢
    • 2018-02-07
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 2013-12-17
    • 2011-12-04
    • 2013-12-09
    相关资源
    最近更新 更多