如何绑定一个WPF DataGrid中的列可变数目?
我的WPF应用程序生成的数据集可能每一次都有不同的列数。包含在输出是将被用于应用格式每一列的说明。输出的简化版本可能是这样的:
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 to apply formatting. A simplified version of the output might be something like:
class Data
{
IList<ColumnDescription> ColumnDescriptions { get; set; }
string[][] Rows { get; set; }
}
本类设置为DataContext的一个WPF的DataGrid,但我其实编程方式创建列:
This class is set as the DataContext on a WPF DataGrid but I actually create the columns programmatically:
for (int i = 0; i < data.ColumnDescriptions.Count; i++)
{
dataGrid.Columns.Add(new DataGridTextColumn
{
Header = data.ColumnDescriptions[i].Name,
Binding = new Binding(string.Format("[{0}]", i))
});
}
有什么办法来取代这个code与XAML文件呢?
Is there any way to replace this code with data bindings in the XAML file instead?
下面是在DataGrid绑定列一个解决方法。由于列属性为只读,就像每个人都注意到了,我做了一个附加属性称为BindableColumns哪些更新DataGrid中列每次通过CollectionChanged事件集合的变化。
Here's a workaround for Binding Columns in the DataGrid. Since the Columns property is ReadOnly, like everyone noticed, I made an Attached Property called BindableColumns which updates the Columns in the DataGrid everytime the collection changes through the CollectionChanged event.
如果我们有一个DataGridColumn的这一集
If we have this Collection of DataGridColumn's
public ObservableCollection<DataGridColumn> ColumnCollection
{
get;
private set;
}
然后,我们可以绑定BindableColumns像这样的ColumnCollection
Then we can bind BindableColumns to the ColumnCollection like this
<DataGrid Name="dataGrid"
local:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection}"
AutoGenerateColumns="False"
...>
附加属性BindableColumns
The Attached Property 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);
}
}