web-dev-qa-db-fra.com

Comment lier un List <string> à un contrôle DataGridView?

J'ai un simple List<string> et je voudrais qu'il soit affiché dans une colonne DataGridView.
Si la liste devait contenir des objets plus complexes, la liste serait simplement définie comme la valeur de sa propriété DataSource.

Mais en faisant ceci:

myDataGridView.DataSource = myStringList;

Je reçois une colonne appelée Length et les longueurs des chaînes sont affichées.

Comment afficher les valeurs de chaîne réelles de la liste dans une colonne?

77
agnieszka

C'est parce que DataGridView recherche les propriétés des objets contenant. Pour string, il n'y a qu'une propriété - longueur. Donc, vous avez besoin d'un wrapper pour une chaîne comme celle-ci

public class StringValue
{
    public StringValue(string s)
    {
        _value = s;
    }
    public string Value { get { return _value; } set { _value = value; } }
    string _value;
}

Liez ensuite List<StringValue> objet à votre grille. Ça marche

67
sinm

Essaye ça:

IList<String> list_string= new List<String>();
DataGridView.DataSource = list_string.Select(x => new { Value = x }).ToList();
dgvSelectedNode.Show();

J'espère que ça aide.

90
Tamanna Jain

Ce qui suit devrait fonctionner tant que vous êtes lié à tout ce qui implémente IEnumerable <string>. Il liera la colonne directement à la chaîne elle-même, plutôt qu'à un chemin de propriété de cet objet chaîne.

<sdk:DataGridTextColumn Binding="{Binding}" />
19
jamisonLikeCode

vous pouvez également utiliser linq et les types anonymes pour obtenir le même résultat avec beaucoup moins de code comme décrit ici .

UPDATE: le blog est en panne, voici le contenu:

(..) Les valeurs affichées dans le tableau représentent la longueur des chaînes au lieu des valeurs de chaîne (!) Cela peut sembler étrange, mais c'est ainsi que fonctionne le mécanisme de liaison par défaut - pour un objet, il essaiera de se lier à la première propriété de celle-ci. objet (la première propriété qu'il peut trouver). Lorsqu'une instance est transmise à la classe String, la propriété à laquelle elle se lie est String.Length, car il n'y a pas d'autre propriété qui fournirait la chaîne elle-même.

Cela signifie que pour obtenir notre droit de liaison, nous avons besoin d'un objet wrapper qui exposera la valeur réelle d'une chaîne en tant que propriété:

public class StringWrapper
    {
     string stringValue;
     public string StringValue { get { return stringValue; } set { stringValue = value; } }

     public StringWrapper(string s)
     {
     StringValue = s;
     }
  }   

   List<StringWrapper> testData = new List<StringWrapper>();

   // add data to the list / convert list of strings to list of string wrappers

  Table1.SetDataBinding(testdata);

Bien que cette solution fonctionne comme prévu, elle nécessite quelques lignes de code (principalement pour convertir une liste de chaînes en liste d'encapsuleurs).

Nous pouvons améliorer cette solution en utilisant LINQ et les types anonymes. Nous utiliserons la requête LINQ pour créer une nouvelle liste d’enveloppeurs de chaînes (l’encapsuleur sera un type anonyme dans notre cas).

 var values = from data in testData select new { Value = data };

 Table1.SetDataBinding(values.ToList());

Le dernier changement que nous allons effectuer consiste à déplacer le code LINQ vers une méthode d’extension:

public static class StringExtensions
  {
     public static IEnumerable CreateStringWrapperForBinding(this IEnumerable<string> strings)
     {
     var values = from data in strings
     select new { Value = data };

     return values.ToList();
     }

De cette façon, nous pouvons réutiliser le code en appelant une méthode unique sur n’importe quelle collection de chaînes:

Table1.SetDataBinding(testData.CreateStringWrapperForBinding());
13
Jarek Kardas

Ceci est un problème courant, une autre façon consiste à utiliser un objet DataTable

DataTable dt = new DataTable();
dt.Columns.Add("column name");

dt.Rows.Add(new object[] { "Item 1" });
dt.Rows.Add(new object[] { "Item 2" });
dt.Rows.Add(new object[] { "Item 3" });

Ce problème est décrit en détail ici: http://www.psworld.pl/Programming/BindingListOfString

8
user1246920

Vous pourriez rencontrer des problèmes de performances lorsque vous affectez des listes très volumineuses via LINQ. La solution suivante convient aux grandes listes sans sous-classement. Chaîne:

Définissez DataGridView (ici "View") en mode virtuel, créez la colonne dont vous avez besoin et substituez/enregistrez l'événement CellValueNeeded.

private void View_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
    // Optionally: check for column index if you got more columns
    e.Value = View.Rows[e.RowIndex].DataBoundItem.ToString();
}

alors vous pouvez simplement assigner votre liste à DataGridView:

List<String> MyList = ...
View.DataSource = MyList;
2
user3042599

Essaye ça :

//i have a 
List<string> g_list = new List<string>();

//i put manually the values... (for this example)
g_list.Add("aaa");
g_list.Add("bbb");
g_list.Add("ccc");

//for each string add a row in dataGridView and put the l_str value...
foreach (string l_str in g_list)
{
    dataGridView1.Rows.Add(l_str);
}
2
Neojt

Une autre solution consiste à utiliser une nouvelle fonction d'assistance qui utilisera les valeurs de List et se mettra à jour dans DataGridView comme suit:

    private void DisplayStringListInDataGrid(List<string> passedList, ref DataGridView gridToUpdate, string newColumnHeader)
    {
        DataTable gridData = new DataTable();
        gridData.Columns.Add(newColumnHeader);

        foreach (string listItem in passedList)
        {
            gridData.Rows.Add(listItem);
        }

        BindingSource gridDataBinder = new BindingSource();
        gridDataBinder.DataSource = gridData;
        dgDataBeingProcessed.DataSource = gridDataBinder;
    }

Ensuite, nous pouvons appeler cette fonction de la manière suivante:

    DisplayStringListInDataGrid(<nameOfListWithStrings>, ref <nameOfDataGridViewToDisplay>, <nameToBeGivenForTheNewColumn>);
0
Sudeep