Jak powiązać List <string> z kontrolką DataGridView?

85

Mam prosty List<string>i chciałbym, aby był wyświetlany w DataGridViewkolumnie.
Gdyby lista zawierała bardziej złożone obiekty, po prostu ustaliłby listę jako wartość jej DataSourcewłaściwości.

Ale robiąc to:

myDataGridView.DataSource = myStringList;

Otrzymuję wywołanie kolumny Lengthi wyświetlane są długości ciągów.

Jak wyświetlić rzeczywiste wartości ciągów z listy w kolumnie?

agnieszka
źródło

Odpowiedzi:

70

Dzieje się tak, ponieważ DataGridView szuka właściwości obiektów zawierających. W przypadku łańcucha istnieje tylko jedna właściwość - długość. Potrzebujesz więc opakowania na taki ciąg

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

Następnie połącz List<StringValue>obiekt z siatką. To działa

sinm
źródło
3
DataPropertyNameKolumny musi byćValue
Rémi
A co z grupowaniem? Teraz „A” nie jest równe „A” i mam dwie grupy „A”.
Rover,
98

Spróbuj tego:

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

Mam nadzieję, że to pomoże.

Tamanna Jain
źródło
13
Jeśli używasz listy zamiast IList, możesz użyć List.ConvertAll(x => new { Value = x});.
Scotty.NET
7
To działa, ale zmiany w list_string nie zaktualizują DataGridView.
Pedro77
Aby zaktualizować Grid, należy ponownie uruchomić instrukcję linq.
Jeff
1
co to jest dgvSelectedNode.Show ()?
Duan Walker
18

Poniższe działania powinny działać, o ile jesteś powiązany z czymkolwiek, co implementuje IEnumerable <string>. Będzie wiązać kolumnę bezpośrednio z samym łańcuchem, a nie ze ścieżką właściwości tego obiektu ciągu.

<sdk:DataGridTextColumn Binding="{Binding}" />
jamisonLikeCode
źródło
Przetestowałem tę sugestię i zadziałała poprawnie. Jest czystszy niż inne rozwiązania.
Gustavo Cardoso
7
Czy to nie jest specyficzne dla Silverlight?
NoviceProgrammer,
2
to działa również w WPF .. dlaczego miałbyś głosować za niepoprawnym komentarzem?
Boppity Bop
4
Głosowanie w dół, ponieważ oryginalne pytanie ma tag „datagridview”, który jest kontrolką winForms. To rozwiązanie nie dotyczy winfroms.
VIS
13

możesz również użyć linq i typów anonimowych, aby osiągnąć ten sam wynik przy znacznie mniejszej ilości kodu, jak opisano tutaj .

AKTUALIZACJA: blog nie działa, oto treść:

(..) Wartości pokazane w tabeli reprezentują długość łańcuchów zamiast wartości łańcuchowych (!) Może się to wydawać dziwne, ale tak domyślnie działa mechanizm wiązania - dany obiekt będzie próbował dowiązać się do jego pierwszej właściwości obiekt (pierwsza właściwość, jaką może znaleźć). Po przekazaniu instancji klasa String jest powiązana z właściwością String.Length, ponieważ nie ma innej właściwości, która zapewniłaby sam ciąg.

Oznacza to, że aby uzyskać prawidłowe powiązanie, potrzebujemy obiektu opakowującego, który ujawni rzeczywistą wartość ciągu jako właściwość:

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

Chociaż to rozwiązanie działa zgodnie z oczekiwaniami, wymaga kilku wierszy kodu (głównie do konwersji listy ciągów do listy opakowań ciągów).

Możemy ulepszyć to rozwiązanie za pomocą LINQ i typów anonimowych - użyjemy zapytania LINQ, aby utworzyć nową listę opakowań ciągów (w naszym przypadku opakowanie ciągu będzie typem anonimowym).

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

 Table1.SetDataBinding(values.ToList());

Ostatnią zmianą, jaką zamierzamy wprowadzić, jest przeniesienie kodu LINQ do metody rozszerzenia:

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

W ten sposób możemy ponownie użyć kodu, wywołując pojedynczą metodę na dowolnej kolekcji ciągów:

Table1.SetDataBinding(testData.CreateStringWrapperForBinding());
Jarek Kardas
źródło
8

Jest to częsty problem, innym sposobem jest użycie obiektu 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" });

Ten problem został szczegółowo opisany tutaj: http://www.psworld.pl/Programming/BindingListOfString

user1246920
źródło
2
Ale datatable jest cięższe niż List <T>, a większość programistów unikałoby użycia datatable.
Musikero 31
2

Podczas przypisywania naprawdę dużych list za pośrednictwem LINQ mogą wystąpić problemy z wydajnością. Poniższe rozwiązanie jest odpowiednie dla dużych list i bez podklas String:

Ustaw DataGridView (tutaj „Widok”) w tryb wirtualny, utwórz potrzebną kolumnę i zastąp / zarejestruj dla zdarzenia 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();
}

następnie możesz po prostu przypisać swoją listę do DataGridView:

List<String> MyList = ...
View.DataSource = MyList;
user3042599
źródło
2

Spróbuj tego :

//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);
}
Neojt
źródło
1
Zdajesz sobie sprawę, że to pytanie ma już 6 lat i czy masz na nie odpowiedź?
Hozikimaru
2
musisz najpierw dodać kolumny do widoku datagrid, inaczej to nie zadziała
deltanine
0

Alternatywą jest użycie nowej funkcji pomocniczej, która pobierze wartości z listy i zaktualizuje ją w DataGridView w następujący sposób:

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

Następnie możemy nazwać tę funkcję w następujący sposób:

    DisplayStringListInDataGrid(<nameOfListWithStrings>, ref <nameOfDataGridViewToDisplay>, <nameToBeGivenForTheNewColumn>);
Sudeep
źródło