Як прив’язати <string> List до елемента керування DataGridView?


84

У мене є простий, List<string>і я хотів би, щоб він відображався у DataGridViewстовпці.
Якщо список містив би більш складні об'єкти, просто встановив би його як значення його DataSourceвластивості.

Але при цьому:

myDataGridView.DataSource = myStringList;

Я отримую виклик стовпця Lengthі відображаються довжини рядків.

Як відобразити фактичні значення рядків зі списку у стовпці?

Відповіді:


70

Це тому, що DataGridView шукає властивості об’єктів, що містять. Для рядка існує лише одна властивість - length. Отже, вам потрібна обгортка для такого рядка

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

Потім прив’яжіть List<StringValue>об’єкт до вашої сітки. Це працює


3
DataPropertyNameКолони повинна бутиValue
Rémi

А як щодо групування? Тепер "А" не дорівнює "А", і я маю дві групи "А".
Rover

97

Спробуйте це:

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

Сподіваюся, це допоможе.


13
Якщо ви використовуєте List замість IList, ви можете використовувати List.ConvertAll(x => new { Value = x});.
Scotty.NET

7
Це працює, але зміни до list_string не оновлять DataGridView.
Pedro77

Для оновлення Grid потрібно повторно запустити оператор linq.
Джефф

1
що таке dgvSelectedNode.Show ()?
Duan Walker

18

Наступне має працювати, доки ви прив’язані до будь-чого, що реалізує IEnumerable <string>. Він буде прив'язувати стовпець безпосередньо до самого рядка, а не до Шляху властивостей цього рядкового об'єкта.

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

Я перевірив це припущення, і воно спрацювало правильно. Він чистіший за інші рішення.
Густаво Кардосо

7
Хіба це не специфічно для silverlight?
NoviceProgrammer

2
це працює і в WPF .. чому б ви проголосували за неправильний коментар?
Boppity Bop

4
Проголосування проти, оскільки вихідне запитання має тег "datagridview", який є контролем winforms. Це рішення не поширюється на виграші.
ВІС

13

Ви також можете використовувати типи linq та анонімні, щоб досягти того самого результату з набагато меншим кодом, як описано тут .

ОНОВЛЕННЯ: блог не працює, ось вміст:

(..) Значення, показані в таблиці, представляють довжину рядків замість рядкових значень (!) Це може здатися дивним, але саме так механізм прив'язки працює за замовчуванням - якщо об'єкт спробує прив'язати до першої властивості цього об'єкт (перша властивість, яку він може знайти). Коли передається екземпляр класу String, властивістю, до якої він пов'язується, є String.Length, оскільки немає жодної іншої властивості, яка могла б забезпечити фактичний рядок.

Це означає, що для отримання нашого права прив’язки нам потрібен об’єкт-обгортка, який буде виставляти фактичне значення рядка як властивість:

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

Хоча це рішення працює, як очікувалося, воно вимагає досить багато рядків коду (переважно для перетворення списку рядків у список обгортки рядків).

Ми можемо вдосконалити це рішення, використовуючи LINQ та анонімні типи - ми будемо використовувати запит LINQ, щоб створити новий список обгортки рядків (у нашому випадку обгортка рядків буде анонімним типом).

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

 Table1.SetDataBinding(values.ToList());

Остання зміна, яку ми вносимо, - це переміщення коду LINQ до методу розширення:

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

Таким чином, ми можемо повторно використовувати код, викликаючи єдиний метод для будь-якої колекції рядків:

Table1.SetDataBinding(testData.CreateStringWrapperForBinding());

8

Це поширена проблема, інший спосіб - використовувати об’єкт 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" });

Ця проблема докладно описана тут: http://www.psworld.pl/Programming/BindingListOfString


2
Але таблиця даних важча за List <T>, і більшість розробників уникатимуть її використання.
Musikero31,

2

Ви можете зіткнутися з проблемами продуктивності при призначенні справді великих списків через LINQ. Наступне рішення підходить для великих списків і без підкласування рядка:

Встановіть DataGridView (тут "Перегляд") у віртуальний режим, створіть потрібний стовпець та перевизначте / зареєструйте подію 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();
}

тоді ви можете просто призначити свій список DataGridView:

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

2

Спробуйте це :

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

1
Ви розумієте, що це запитання приблизно 6 років, і на нього відповіли правильно?
Хозікімару

2
вам потрібно спочатку додати стовпці до подання
сітки даних, інакше

0

Альтернативним варіантом є використання нової допоміжної функції, яка прийме значення зі списку та оновлення в DataGridView наступним чином:

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

Тоді ми можемо викликати цю функцію наступним чином:

    DisplayStringListInDataGrid(<nameOfListWithStrings>, ref <nameOfDataGridViewToDisplay>, <nameToBeGivenForTheNewColumn>);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.