【问题标题】:programmatically add column & rows to WPF Datagrid以编程方式将列和行添加到 WPF Datagrid
【发布时间】:2026-02-13 02:45:02
【问题描述】:

我是 WPF 新手。我只想知道我们应该如何以编程方式将列和行添加到 WPF 中的 DataGrid。我们过去在 Windows 窗体中执行此操作的方式。创建表列和行,并将其绑定到 DataGrid。

我相信 WPF DataGrid 与 ASP.net 和 Windows 表单中使用的有点不同(如果我错了,请纠正我)。

我需要在 DataGrid 中绘制的行数和列数,以便用户可以编辑单元格中的数据。

【问题讨论】:

    标签: c# wpf datagrid wpf-controls silverlight-2.0


    【解决方案1】:

    以编程方式添加一行:

    DataGrid.Items.Add(new DataItem());
    

    以编程方式添加列:

    DataGridTextColumn textColumn = new DataGridTextColumn(); 
    textColumn.Header = "First Name"; 
    textColumn.Binding = new Binding("FirstName"); 
    dataGrid.Columns.Add(textColumn); 
    

    查看 WPF DataGrid 讨论板上的 this post 了解更多信息。

    【讨论】:

    • -1:因为您展示了令人痛苦的简单部分,但没有展示如何将数据实际绑定到那些运行时添加的列。我确信 Andy 想要构建一个显示某种数据的应用程序,而不仅仅是列名。
    • 这只是在 DataGridTextColumn 上设置属性的问题。我更新了答案。
    • +1:我确认可行,谢谢。我还发现,当您添加方括号时,即Binding("[FirstName]")在下面查看我之前的答案,它可以工作,但是在绑定大型数据集时它会明显变慢。
    • DataItem 是一个对象,它的外观如何?
    • 有没有办法使用这个代码添加多列标题?
    【解决方案2】:

    试试这个,它 100% 有效:以编程方式添加列和行: 您首先需要创建项目类:

    public class Item
            {
                public int Num { get; set; }
                public string Start { get; set; }
                public string Finich { get; set; }
            }
    
            private void generate_columns()
            {
                DataGridTextColumn c1 = new DataGridTextColumn();
                c1.Header = "Num";
                c1.Binding = new Binding("Num");
                c1.Width = 110;
                dataGrid1.Columns.Add(c1);
                DataGridTextColumn c2 = new DataGridTextColumn();
                c2.Header = "Start";
                c2.Width = 110;
                c2.Binding = new Binding("Start");
                dataGrid1.Columns.Add(c2);
                DataGridTextColumn c3 = new DataGridTextColumn();
                c3.Header = "Finich";
                c3.Width = 110;
                c3.Binding = new Binding("Finich");
                dataGrid1.Columns.Add(c3);
    
                dataGrid1.Items.Add(new Item() { Num = 1, Start = "2012, 8, 15", Finich = "2012, 9, 15" });
                dataGrid1.Items.Add(new Item() { Num = 2, Start = "2012, 12, 15", Finich = "2013, 2, 1" });
                dataGrid1.Items.Add(new Item() { Num = 3, Start = "2012, 8, 1", Finich = "2012, 11, 15" });
    
            }
    

    【讨论】:

    • 有没有办法使用这个代码添加多列标题?
    【解决方案3】:

    我遇到了同样的问题。向 WPF DataGrid 添加新行需要一个技巧。 DataGrid 依赖于项目对象的属性字段。 ExpandoObject 允许动态添加新属性。下面的代码解释了如何做到这一点:

    // using System.Dynamic;
    
    DataGrid dataGrid;
    
    string[] labels = new string[] { "Column 0", "Column 1", "Column 2" };
    
    foreach (string label in labels)
    {
        DataGridTextColumn column = new DataGridTextColumn();
        column.Header = label;
        column.Binding = new Binding(label.Replace(' ', '_'));
    
        dataGrid.Columns.Add(column);
    }
    
    int[] values = new int[] { 0, 1, 2 };
    
    dynamic row = new ExpandoObject();
    
    for (int i = 0; i < labels.Length; i++)
        ((IDictionary<String, Object>)row)[labels[i].Replace(' ', '_')] = values[i];
    
    dataGrid.Items.Add(row);
    

    //编辑:

    请注意,这不是组件的使用方式,但是,如果您只有以编程方式生成的数据(例如,在我的例子中:一系列特征和神经网络输出),它会大大简化。

    【讨论】:

    • @bartek-dzieńkowski 很棒
    • 谢谢,这是最适合我用例的!
    【解决方案4】:

    我找到了一个在运行时添加列并绑定到 DataTable 的解决方案。

    不幸的是,以这种方式定义了 47 列,它绑定到数据的速度对我来说不够快。有什么建议吗?

    xaml

    <DataGrid
      Name="dataGrid"
      AutoGenerateColumns="False"
      ItemsSource="{Binding}">
    </DataGrid>
    

    xaml.cs 使用 System.Windows.Data;

    if (table != null) // table is a DataTable
    {
      foreach (DataColumn col in table.Columns)
      {
        dataGrid.Columns.Add(
          new DataGridTextColumn
          {
            Header = col.ColumnName,
            Binding = new Binding(string.Format("[{0}]", col.ColumnName))
          });
      }
    
      dataGrid.DataContext = table;
    }
    

    【讨论】:

    • 你当时找到解决办法了吗??
    • 为什么在绑定路径中使用“[{0}]”?它对我不起作用,但是当我只使用没有正方形和卷曲的名称时,它会起作用吗?
    【解决方案5】:

    编辑:对不起,我不再有下面提到的代码。这是一个巧妙的解决方案,虽然很复杂。


    我发布了一个示例项目,描述了如何使用 PropertyDescriptor 和 lambda 委托与动态 ObservableCollection 和 DynamicObject 来填充具有强类型列定义的网格。

    可以在运行时动态地添加/删除列。如果您的数据不是已知类型的对象,您可以创建一个数据结构,允许任意数量的列进行访问,并为每个“列”指定一个 PropertyDescriptor。

    例如:

    IList<string> ColumnNames { get; set; }
    //dict.key is column name, dict.value is value
    Dictionary<string, string> Rows { get; set; }
    

    您可以这样定义列:

    var descriptors= new List<PropertyDescriptor>();
    //retrieve column name from preprepared list or retrieve from one of the items in dictionary
    foreach(var columnName in ColumnNames)
        descriptors.Add(new DynamicPropertyDescriptor<Dictionary, string>(ColumnName, x => x[columnName]))
    MyItemsCollection = new DynamicDataGridSource(Rows, descriptors) 
    

    如果是一些真实的物体,甚至更好

    public class User 
    {
        public string FirstName { get; set; }
        public string LastName{ get; set; }
        ...
    }
    

    您可以指定强类型的列(与您的数据模型相关):

    var propertyDescriptors = new List<PropertyDescriptor>
    {
        new DynamicPropertyDescriptor<User, string>("First name", x => x.FirstName ),
        new DynamicPropertyDescriptor<User, string>("Last name", x => x.LastName ),
        ...
    }
    
    var users = retrieve some users
    
    Users = new DynamicDataGridSource<User>(users, propertyDescriptors, PropertyChangedListeningMode.Handler);
    

    然后,您只需绑定到用户集合,并在您指定它们时自动生成列。传递给属性描述符的字符串是列标题的名称。在运行时,您可以向“用户”添加更多 PropertyDescriptor,向网格添加另一列。

    【讨论】:

    • @doblak 我发现这正是我所需要的。你还有解决方案的代码吗?
    • @zhangz 更新了答案,DynamicPropertyDescriptor 的想法见这篇帖子:jopinblog.wordpress.com/2007/05/12/…
    【解决方案6】:

    如果您已经准备好数据绑定,John Myczek 的回答就完成了。
    如果没有,如果您想指定数据来源,我知道您至少有 2 个选项。 (但是我不确定这是否在 符合大多数准则,例如 MVVM)

    选项 1: 就像 JohnB 所说的那样。但我认为你应该使用自己定义的集合 而不是弱类型的 DataTable (没有冒犯,但你不能从 编码每列代表什么)

    xaml.cs

    DataContext = myCollection;
    
    //myCollection is a `ICollection<YourType>` preferably
    `ObservableCollection<YourType>
    
     - option 2) Declare the name of the Datagrid in xaml
    
            <WpfToolkit:DataGrid Name=dataGrid}>
    

    xaml.cs

    CollectionView myCollectionView = 
          (CollectionView)CollectionViewSource.GetDefaultView(yourCollection);
    dataGrid.ItemsSource = myCollectionView;
    

    如果您的类型定义了 FirstName 属性,那么您可以按照 John Myczek 指出的那样做。

    DataGridTextColumn textColumn = new DataGridTextColumn(); 
    dataColumn.Header = "First Name"; 
    dataColumn.Binding = new Binding("FirstName"); 
    dataGrid.Columns.Add(textColumn); 
    

    如果您不知道需要在 dataGrid 中显示的属性,这显然是行不通的,但如果是这种情况,您将有更多问题需要处理,我相信这超出了这里的范围。

    【讨论】:

      【解决方案7】:

      在 CodeBehind 中将 DataTable 绑定到 DataGridTextColumn 中 xaml

      <DataGrid
        Name="TrkDataGrid"
        AutoGenerateColumns="False"
        ItemsSource="{Binding}">
      </DataGrid>
      

      xaml.cs

        foreach (DataColumn col in dt.Columns)
        {
          TrkDataGrid.Columns.Add(
            new DataGridTextColumn
            {
              Header = col.ColumnName,
              Binding = new Binding(string.Format("[{0}]", col.ColumnName))
            });
        }
      
        TrkDataGrid.ItemsSource= dt.DefaultView;
      

      【讨论】:

        【解决方案8】:

        如果您已经准备好数据绑定,John Myczek 的回答就完成了。 如果没有,如果您想指定数据源,我知道您至少有 2 个选项。 (但是我不确定这是否符合大多数准则,例如 MVVM)

        然后,您只需绑定到用户集合,并在您指定它们时自动生成列。传递给属性描述符的字符串是列标题的名称。在运行时,您可以向“用户”添加更多 PropertyDescriptor,将另一列添加到网格中。

        【讨论】: