以编程方式向 WPF Datagrid 添加列和行

83

我想知道在WPF中如何通过编程方式向DataGrid添加列和行。就像我们在Windows窗体中所做的那样-创建表格列和行,然后将其绑定到DataGrid。

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

8个回答

81
以编程方式添加一行:
DataGrid.Items.Add(new DataItem());

如何以编程方式添加一列:

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

在WPF DataGrid讨论板块上查看此帖以获取更多信息。


9
因为你只展示了简单的部分,但没有说明如何将数据绑定到那些在运行时添加的列上。我相信Andy想要构建一个显示某种数据的应用程序,而不仅仅是列名。 - JohnB
只是在DataGridTextColumn上设置属性的问题。我更新了回答。 - John Myczek
+1:我确认这个方法可行,谢谢。我还发现当你添加方括号时,即Binding("[FirstName]") 请参见我下面的先前答案,它也可以工作,但是在绑定大型数据集时速度明显较慢。 - JohnB
1
作为一个对象,DataItem应该长什么样子? - C4d
这段代码有没有办法添加多列标题? - Denis

32

试试这个,百分之百有效:动态添加行和列:
你需要首先创建一个项目类:

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

这段代码有没有办法添加多列标题? - Denis

30

我曾经遇到过同样的问题。向 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 很棒! - Mahdi Khalili
谢谢,这是我使用情况下最好的选择! - Livo

13
我找到了一个在运行时添加列并绑定到 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;
}

当时你找到了解决方案吗? - 321X
2
为什么在绑定路径中要使用"[{0}]"?这样对我没用,但是当我只是使用名称而没有方括号和大括号时,它就起作用了呢? - smerlung

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
@zhangz更新了答案,请查看此帖子以获取DynamicPropertyDescriptor的想法:https://jopinblog.wordpress.com/2007/05/12/dynamic-propertydescriptors-with-anonymous-methods/ - doblak

3
如果您已经设置了数据绑定,John Myczek的答案已经很完整了。 如果没有,如果您想指定数据源,则我知道至少有两个选项。(但我不确定这是否符合大多数指南,如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); 

如果您不知道需要在数据网格中显示哪些属性,那么显然这种方法无法奏效,但如果是这种情况,您将面临更多问题,我相信这已经超出了本文的范围。


0
如果您已经设置了数据绑定,John Myczek的答案就是完整的。如果没有,我知道至少有两个选项可以指定数据源。(但我不确定这是否符合大多数指南,如MVVM)

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


0

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接