[WPF 一问一答] WPF DataGrid 如何增加列?

问:

WPF的项目,客户希望给DataGrid添加列(当然,也要能添加行了),而且不是只添一次,而是不断的增加列。例如,现有的列名是“规则一”、“规则二”,他们希望能够不断添加新的规则(每按一次键添加新的一列),然后再在DataGrid里输入、修改。就是要像Access一样。

一般的DataGrid是绑定到指定的ObservableCollection, 而每一列实际是绑定到the property of the data source. 像现在这样的要求,该如何绑定才行呢?

我试着先把数据放到一个DataTable里,然后DataGrid binding to this DataTable,make "AutomaticGenerateColumn = True"。然后每次用户选择添加,就添加到DataTable里,希望DataGrid能根据DataTable的变化自动产生新列,但是DataGrid不能自动更新,不知道为什么,另外这种在中间加DataTable的办法好像也不是太好,希望能找到更聪明点的办法。

[原帖:http://social.microsoft.com/Forums/zh-CN/wpfzhchs/thread/69ac1292-9512-4bd3-b691-795f64cb0aa0]

 

----------------------------------

答:

WPF中所有的ItemsControl只支持一维的数据结构,简单理解,我们的ListBox,ListView, ComboBox, 甚至DataGrid 都是仅支持一个维度的集合。这里你要问了,为啥DataGrid有行和列? 其实我们是这么设计的,一个维度嵌套在另一个维度中,就能够形成二维的集合结构,但是对于DataGrid来说,对于他能够直接操作的还是第一维的DataGridRow。 我们集合中每一行元素或者讲每一个元素都是会被一个 DataGridRow包装好放入DataGrid。 然后在DataGridRow还会有进一步的每个元素的各个属性的包装 DataGridCell。 为什么我要讲这个,是因为我要告诉你,在WPF中,一旦这个DataGrid显示出来的,他的可视树中是根本没有所谓列的概念的,他的可视树里面只有行和单元格的概念。所以你的第一个问题,要动态添加列,只有在DataGrid没有显示前增加,即在DataGrid的逻辑树里面增加。 或者我们可以动态增加DataGrid所绑定的DataTable的列,然后重新设置DataGrid的绑定,让DataGrid重新根据数据源来自动生成列。

所以,我上面已经回答了你的 “一般的DataGrid是绑定到指定的ObservableCollection, 而每一列实际是绑定到the property of the data source. 像现在这样的要求,该如何绑定才行呢?” 这个问题,是不能实现的。WPF中的DataGrid在绑定后显示出来了,就不能再加列了,每个明确的类型的属性是不能随意增加的。

除非,你的ObservableCollection集合里面是一个dynamic类型,他可以动态的添加属性,这种类型你可以添加好类型之后,重新设置DataGrid的ItemsSource绑定即可(注:此方法只能用在WPF 4 .Net 4 Framework里面,参考此文:http://blogs.msdn.com/b/llobo/archive/2009/11/02/new-wpf-feature-binding-to-dynamic-objects.aspx

代码片段:

 

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

 

例子比较复杂,你下载看一下: https://skydrive.live.com/#!/?cid=51b2fdd068799d15&sc=documents&uc=1&id=51B2FDD068799D15%21827

------------------------------------------------------

如果你是选择DataTable作为数据源,那就相对简单一点,你在DataTable里面动态增加了列之后,和新列的每一行数据之后,你可以先设置DataGrid.ItemsSource = null; 然后再重新设置ItemsSource到你的DataTable:

XAML:

  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
      <Button Content="Add Column" Click="AddColumn_Click" Margin="5"/>
      <Button Content="Add Data" Click="AddData_Click" Margin="5"/>
    </StackPanel>
    <DataGrid x:Name="dataGrid" AutoGenerateColumns="True" Grid.Row="1"/>
  </Grid>
 

C#:

  public partial class MainWindow : Window
  {
    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;
    }
  }

 

下载:https://skydrive.live.com/#!/?cid=51b2fdd068799d15&sc=documents&uc=1&id=51B2FDD068799D15%21825

posted @ 2011-09-08 02:08  Jarrey  阅读(13650)  评论(3编辑  收藏  举报