在WPF的项目中希望给DataGrid动态添加列,而不是添加行。例如,现有的列名是“规则一”、“规则二”,他们希望能够不断添加新的规则(每按一次键添加新的一列),然后再在DataGrid里输入、修改。就是要像Access一样。
WPF中所有的ItemsControl只支持一维的数据结构,简单理解,我们熟悉的ListBox,ListView, ComboBox, 甚至DataGrid 都是仅支持一个维度的集合。为啥DataGrid有行和列? 其实是一个维度嵌套在另一个维度中,就能够形成二维的集合结构,但是对于DataGrid来说,对于它能够直接操作的还是第一维的DataGridRow。 我们集合中每一行元素或者讲每一个元素都是会被一个 DataGridRow包装好放入DataGrid。 然后在DataGridRow还会有进一步的每个元素的各个属性的包装 DataGridCell。在WPF中,DataGrid的可视树中是根本没有所谓列的概念的,只有行和单元格的概念。所以要动态添加列,只有在DataGrid没有显示前增加,即在DataGrid的逻辑树里面增加。 或者我们可以动态增加DataGrid所绑定的DataTable的列,然后重新设置DataGrid的绑定,让DataGrid重新根据数据源来自动生成列。
不过,这里也有一种方式,ObservableCollection集合里面是一个dynamic类型,它可以动态的添加属性,这种类型添加好属性之后,重新设置DataGrid的ItemsSource绑定即可,这种方式很多地方可以找到,代码如下:
ObservableCollection<dynamic> items = new ObservableCollection<dynamic>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 5; i++)
{
dynamic item = new DynamicObjectClass();
item.A = "Property A value - " + i.ToString();
item.B = "Property B value - " + i.ToString();
items.Add(item);
}
dataGrid.Columns.Add(new DataGridTextColumn() {Header="A", Binding = new Binding("A") });
dataGrid.Columns.Add(new DataGridTextColumn() {Header="B", Binding = new Binding("B") });
dataGrid.ItemsSource = items;
}
private void AddData_Click(object sender, RoutedEventArgs e)
{
dynamic item = new DynamicObjectClass();
item.A="New Item - A";
item.B="New Item - B";
items.Add(item);
}
int newColumnIndex = 1;
private void AddColumn_Click(object sender, RoutedEventArgs e)
{
foreach (DynamicObjectClass item in items)
{
item.TrySetMember(new SetPropertyBinder("NewColumn" + newColumnIndex), "New Column Value " + newColumnIndex.ToString());
}
dataGrid.Columns.Add(new DataGridTextColumn() { Header = "New Column" + newColumnIndex, Binding = new Binding("NewColumn" + newColumnIndex) });
newColumnIndex++;
}
对应的类及对象如下,每次新增列为属性NewColumn及其对应值:
item | A->Property A value 0 B->Property B value 0 NewColumn1-->New Value1
|
item | A->Property A value 1 B->Property B value 1 NewColumn1-->New Value1
|
item | A->Property A value 2 B->Property B value 2 NewColumn1-->New Value1 |
item | A->Property A value 3 B->Property B value 3 NewColumn1-->New Value1 |
item | A->Property A value 4 B->Property B value 4 NewColumn1-->New Value1 |
通过以上也发现,实际上新增的列为item列表下中对象的属性及其值,如果以此看做一列的话,实际上操作的还是item对应的一行。所以,也有第二种方式,即选择DataTable作为数据源,在DataTable里面动态增加了列之后,重新构造每一行数据,设置DataGrid.ItemsSource = null; 然后再重新设置ItemsSource到DataTable。代码大致如下:
DataTable dt = new DataTable();
public MainWindow()
{
InitializeComponent();
dt.Columns.Add(new DataColumn("Column1"));
dt.Columns.Add(new DataColumn("Column2"));
DataRow dr;
for (int i = 0; i < 5; i++)
{
dr = dt.NewRow();
for (int columIndex = 0; columIndex < dt.Columns.Count ; columIndex++)
dr[columIndex] = i.ToString() + " - " + columIndex.ToString();
dt.Rows.Add(dr);
}
dataGrid.ItemsSource = dt.DefaultView;
}
private void AddData_Click(object sender, RoutedEventArgs e)
{
DataRow dr = dt.NewRow();
for (int columIndex = 0; columIndex < dt.Columns.Count; columIndex++)
dr[columIndex] = "New Row - " + columIndex.ToString();
dt.Rows.Add(dr);
}
int newColumnIndex = 1;
private void AddColumn_Click(object sender, RoutedEventArgs e)
{
dt.Columns.Add(new DataColumn("New Column" + newColumnIndex++));
for (int i = 0; i < dt.Rows.Count; i++)
{
dt.Rows[i][dt.Columns.Count - 1] = i.ToString() + " - New Column";
}
dataGrid.ItemsSource = null;
dataGrid.ItemsSource = dt.DefaultView;
}