web-dev-qa-db-fra.com

ajouter par programme des colonnes et des lignes à WPF Datagrid

Je suis nouveau sur WPF. Je veux juste savoir comment ajouter des colonnes et des lignes par programme à un DataGrid dans WPF. La façon dont nous le faisions dans les formulaires Windows. créer des colonnes et des lignes de table et les lier à DataGrid.

Je crois que WPF DataGrid est légèrement différent de celui utilisé dans les formulaires ASP.net et Windows (corrigez-moi si je me trompe).

J'ai un nombre de lignes et de colonnes que je dois dessiner dans DataGrid afin que l'utilisateur puisse éditer les données dans les cellules.

67
Andy

Pour ajouter une ligne par programme:

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

Pour ajouter par programme une colonne:

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

Consultez this post sur le forum de discussion WPF DataGrid pour plus d'informations.

69
John Myczek

essayez ceci, cela fonctionne à 100%: ajoutez des colonnes et des lignes par programme: vous devez d'abord créer une classe d'élément:

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

        }
27
aminescm

J'ai eu le même problème. Ajouter de nouvelles lignes à WPF DataGrid nécessite une astuce. DataGrid s'appuie sur les champs de propriété d'un objet item. ExpandoObject permet d'ajouter de nouvelles propriétés de manière dynamique. Le code ci-dessous explique comment procéder:

// 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);

//modifier:

Notez que ce n'est pas la manière dont le composant doit être utilisé, cependant, cela simplifie beaucoup si vous ne disposez que de données générées par programme (par exemple, dans mon cas: une séquence de caractéristiques et une sortie de réseau neuronal).

20

J'ai trouvé une solution qui ajoute des colonnes au moment de l'exécution et se lie à un DataTable.

Malheureusement, avec 47 colonnes définies de cette manière, les données ne se lient pas assez vite pour moi. Des suggestions?

xaml

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

xaml.cs à l'aide de 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;
}
11
JohnB

edit: désolé, je n'ai plus le code mentionné ci-dessous. C'était une solution soignée, bien que complexe.


J'ai posté un exemple de projet décrivant comment utiliser PropertyDescriptor et les délégués lambda avec ObservableCollection et DynamicObject dynamiques pour remplir une grille avec des définitions de colonne fortement typées.

Les colonnes peuvent être ajoutées/supprimées au moment de l'exécution dynamiquement. Si vos données ne sont pas un objet de type connu, vous pouvez créer une structure de données permettant un accès par un nombre quelconque de colonnes et spécifier un PropertyDescriptor pour chaque "colonne".

Par exemple:

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

Vous pouvez définir les colonnes de cette façon:

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) 

Ou même mieux, dans le cas d'objets réels

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

Vous pouvez spécifier des colonnes fortement typées (liées à votre modèle de données):

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

Ensuite, il vous suffit de vous lier aux collections d’utilisateurs et les colonnes sont générées automatiquement au fur et à mesure que vous les spécifiez. Les chaînes transmises aux descripteurs de propriétés sont des noms pour les en-têtes de colonnes. Au moment de l'exécution, vous pouvez ajouter d'autres PropertyDescriptors à "Utilisateurs", ajouter une autre colonne à la grille.

4
doblak

Si vous avez déjà la liaison de données en place, la réponse de John Myczek est terminée.
Sinon, vous avez au moins deux options à ma connaissance si vous souhaitez spécifier la source de vos données. (Cependant, je ne suis pas sûr que cela soit conforme à la plupart des directives, comme MVVM)

option 1: comme l'a dit JohnB. Mais je pense que vous devriez utiliser votre propre collection définie au lieu d'un DataTable faiblement typé (pas d'infraction, mais vous ne pouvez pas dire à partir du code ce que représente chaque colonne)

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

dans xaml.cs

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

Si votre type a une propriété FirstName définie, vous pouvez alors faire ce que John Myczek a souligné.

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

Cela ne fonctionne évidemment pas si vous ne connaissez pas les propriétés que vous devrez afficher dans votre grille de données, mais si tel est le cas, vous aurez plus de problèmes à traiter et je pense que cela sort du cadre.

3
HCP