如何将 List < string > 绑定到 DataGridView 控件?

我有一个简单的 List<string>,我希望它显示在一个 DataGridView列。
如果列表包含更复杂的对象,只需将列表建立为其 DataSource属性的值。

但是这样做的时候:

myDataGridView.DataSource = myStringList;

我得到一个名为 Length的列,并显示字符串的长度。

如何在列中显示列表中的实际字符串值?

158521 次浏览

Thats because DataGridView looks for properties of containing objects. For string there is just one property - length. So, you need a wrapper for a string like this

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

Then bind List<StringValue> object to your grid. It works

you can also use linq and anonymous types to achieve the same result with much less code as described here.

UPDATE: blog is down, here's the content:

(..) The values shown in the table represent the length of strings instead of string values (!) It may seem strange, but that’s how binding mechanism works by default – given an object it will try to bind to the first property of that object (the first property it can find). When passed an instance the String class the property it binds to is String.Length since there’s no other property that would provide the actual string itself.

That means that to get our binding right we need a wrapper object that will expose the actual value of a string as a property:

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

While this solution works as expected it requires quite a few lines of code (mostly to convert list of strings to the list of string wrappers).

We can improve this solution by using LINQ and anonymous types- we’ll use LINQ query to create a new list of string wrappers (string wrapper will be an anonymous type in our case).

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


Table1.SetDataBinding(values.ToList());

The last change we’re going to make is to move the LINQ code to an extension method:

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

This way we can reuse the code by calling single method on any collection of strings:

Table1.SetDataBinding(testData.CreateStringWrapperForBinding());

Try this:

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

I hope this helps.

The following should work as long as you're bound to anything that implements IEnumerable<string>. It will bind the column directly to the string itself, rather than to a Property Path of that string object.

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

This is common issue, another way is to use DataTable object

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

This problem is described in detail here: http://www.psworld.pl/Programming/BindingListOfString

An alternate is to use a new helper function which will take values from List and update in the DataGridView as following:

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

Then we can call this function the following way:

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

You might run into performance issues when assigning really large lists through LINQ. Following solution is suitable for large lists and without subclassing String:

Set DataGridView (here "View") to virtual mode, create column you need and override / register for event 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();
}

then you can simply assign your list to DataGridView:

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

Try this :

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