adicionar programaticamente colunas e linhas ao datagrid do WPF

Eu sou novo no WPF. Eu só quero saber como devemos adicionar colunas e linhas programaticamente a um DataGrid no WPF. A maneira como costumávamos fazer isso nas janelas. crie colunas e linhas de tabelas e vincule-as a DataGrid.

Eu acredito que o DataGrid do WPF é um pouco diferente do usado no ASP.net e no Windows (corrija-me se estiver errado).

Eu tenho o número de linhas e colunas que eu preciso desenhar no DataGrid para que o usuário possa editar os dados nas células.

Para adicionar programaticamente uma linha:

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

Para adicionar programaticamente uma coluna:

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

Confira este post no quadro de discussão do WPF DataGrid para obter mais informações.

tente isso, ele funciona 100%: adicione colunas e linhas programaticamente: primeiro você precisa criar uma class de item:

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

Eu tive o mesmo problema. Adicionar novas linhas ao WPF DataGrid requer um truque. DataGrid depende dos campos de propriedade de um object de item. ExpandoObject permite adicionar novas propriedades dinamicamente. O código abaixo explica como fazer isso:

 // 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)row)[labels[i].Replace(' ', '_')] = values[i]; dataGrid.Items.Add(row); 

//editar:

Note que esta não é a maneira como o componente deve ser usado, no entanto, ele simplifica muito se você tiver apenas dados gerados programaticamente (por exemplo, no meu caso: uma seqüência de resources e saída de neural network).

Eu encontrei uma solução que adiciona colunas em tempo de execução e se liga a um DataTable .

  • Como faço para vincular um DataGrid WPF a um número variável de colunas?

Infelizmente, com 47 colunas definidas dessa maneira, elas não se ligam aos dados com rapidez suficiente para mim. Alguma sugestão?

xaml

   

xaml.cs usando 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; } 

edit : desculpe, eu não tenho mais o código mencionado abaixo. Era uma solução perfeita, embora complexa.


Eu publiquei um projeto de exemplo descrevendo como usar os delegates PropertyDescriptor e lambda com ObservableCollection dynamic e DynamicObject para preencher uma grade com definições de coluna fortemente tipadas .

Colunas podem ser adicionadas / removidas no tempo de execução dinamicamente . Se seus dados não forem um object com um tipo conhecido, você poderá criar uma estrutura de dados que permita o access por qualquer número de colunas e especifique um PropertyDescriptor para cada “coluna”.

Por exemplo:

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

Você pode definir colunas desta maneira:

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

Ou melhor ainda, no caso de alguns objects reais

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

Você pode especificar colunas fortemente tipadas (relacionadas ao seu modelo de dados):

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

Então você só liga para collections de usuários e as colunas são autogeradas quando você as define. Strings passados ​​para descritores de propriedade são nomes para headers de coluna. Em tempo de execução, você pode adicionar mais PropertyDescriptors a ‘Users’ para adicionar outra coluna à grade.

Se você já tem a binding de dados em vigor, a resposta de John Myczek está completa.
Se não, você tem pelo menos duas opções que eu conheço se você quiser especificar a origem dos seus dados. (No entanto, não tenho certeza se isso está ou não de acordo com a maioria das diretrizes, como o MVVM)

opção 1: como JohnB disse. Mas eu acho que você deveria usar sua própria coleção definida ao invés de uma DataTable fracamente tipada (sem ofensa, mas você não pode dizer do código o que cada coluna representa)

xaml.cs

 DataContext = myCollection; //myCollection is a `ICollection` preferably `ObservableCollection - option 2) Declare the name of the Datagrid in xaml  

em xaml.cs

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

Se o seu tipo tiver uma propriedade definida por FirstName , você poderá fazer o que John Myczek apontou.

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

Obviamente, isso não funciona se você não souber as propriedades que precisará mostrar em seu dataGrid, mas se esse for o caso, você terá mais problemas para lidar, e acredito que isso esteja fora do escopo aqui.

Se você já tem a binding de dados em vigor, a resposta de John Myczek está completa. Se não, você tem pelo menos duas opções que eu conheço se você quiser especificar a origem dos seus dados. (No entanto, não tenho certeza se isso está ou não de acordo com a maioria das diretrizes, como o MVVM)

Então você só liga para collections de usuários e as colunas são autogeradas quando você as define. Strings passados ​​para descritores de propriedade são nomes para headers de coluna. Em tempo de execução, você pode adicionar mais PropertyDescriptors a ‘Users’ para adicionar outra coluna à grade.