Как привязать List ‹string› к элементу управления DataGridView?

У меня есть простой List<string>, и я бы хотел, чтобы он отображался в столбце DataGridView.
Если бы список содержал более сложные объекты, просто установил бы список как значение его свойства DataSource.

Но при этом:

myDataGridView.DataSource = myStringList;

Я получаю столбец с именем Length, и отображаются длины строк.

Как отобразить фактические строковые значения из списка в столбце?


person agnieszka    schedule 26.01.2009    source источник


Ответы (8)


Это потому, что DataGridView ищет свойства содержащихся объектов. Для строки есть только одно свойство - длина. Итак, вам нужна оболочка для такой строки

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

Затем привяжите объект List<StringValue> к вашей сетке. Оно работает

person sinm    schedule 26.01.2009
comment
DataPropertyName столбца должен быть Value - person Rémi; 10.07.2013
comment
А как насчет группировки? Теперь A не равно A, и у меня есть две группы A. - person Rover; 06.09.2013

Попробуй это:

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

Надеюсь, это поможет.

person Tamanna Jain    schedule 12.07.2010
comment
Если вы используете List вместо IList, вы можете использовать List.ConvertAll(x => new { Value = x});. - person Scotty.NET; 09.10.2012
comment
Это работает, но изменения в list_string не обновят DataGridView. - person Pedro77; 19.04.2013
comment
Чтобы обновить сетку, необходимо снова запустить оператор linq. - person Jeff; 02.08.2016
comment
что такое dgvSelectedNode.Show ()? - person Duan Walker; 23.08.2018

Следующее должно работать, пока вы привязаны к чему-либо, что реализует IEnumerable ‹string›. Он привяжет столбец непосредственно к самой строке, а не к пути свойства этого строкового объекта.

<sdk:DataGridTextColumn Binding="{Binding}" />
person jamisonLikeCode    schedule 15.11.2010
comment
Я проверил это предложение, и оно сработало. Это чище, чем другие решения. - person Gustavo Cardoso; 28.02.2011
comment
Разве это не относится к silverlight? - person NoviceProgrammer; 05.07.2011
comment
это работает и в WPF ... зачем вам голосовать за неправильный комментарий? - person Boppity Bop; 09.06.2013
comment
Голосование вниз, потому что исходный вопрос имеет тег datagridview, который является элементом управления winforms. Это решение не распространяется на winfroms. - person V.I.S.; 24.08.2015

вы также можете использовать 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());
person Jarek Kardas    schedule 07.07.2009

Это обычная проблема, другой способ - использовать объект 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

person user1246920    schedule 03.03.2012
comment
Но datatable тяжелее List ‹T›, и большинство разработчиков избегали бы его использования. - person Musikero31; 08.10.2014

Вы можете столкнуться с проблемами производительности при назначении действительно больших списков через LINQ. Следующее решение подходит для больших списков и без подкласса String:

Установите 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;
person user3042599    schedule 08.08.2014

Попробуй это :

//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);
}
person Neojt    schedule 09.11.2015
comment
Вы понимаете, что этому вопросу уже 6 лет, и вы ответили правильно? - person Hozikimaru; 09.11.2015
comment
вам нужно сначала добавить столбцы в представление сетки данных, иначе это не сработает - person deltanine; 25.01.2017

Альтернативой является использование новой вспомогательной функции, которая будет принимать значения из списка и обновлять в 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>);
person Sudeep    schedule 30.03.2014