¿Cómo enlazar una List <string> a un control DataGridView?

84

Tengo un simple List<string>y me gustaría que se muestre en una DataGridViewcolumna.
Si la lista contendría objetos más complejos, simplemente establecería la lista como el valor de su DataSourcepropiedad.

Pero al hacer esto:

myDataGridView.DataSource = myStringList;

Recibo una columna llamada Lengthy se muestran las longitudes de las cadenas.

¿Cómo mostrar los valores de cadena reales de la lista en una columna?

Agnieszka
fuente

Respuestas:

70

Eso es porque DataGridView busca propiedades de los objetos que contienen. Para la cadena, solo hay una propiedad: la longitud. Entonces, necesitas una envoltura para una cadena como esta

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

Luego vincula el List<StringValue>objeto a tu cuadrícula. Funciona

sinm
fuente
3
El DataPropertyNamede la columna debe serValue
Rémi
¿Qué pasa con la agrupación? Ahora "A" no es igual a "A" y tengo dos grupos "A".
Rover
97

Prueba esto:

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

Espero que esto ayude.

Tamanna Jain
fuente
13
Si está usando una Lista en lugar de IList, puede usar List.ConvertAll(x => new { Value = x});.
Scotty.NET
7
Esto funciona, pero los cambios en list_string no actualizarán DataGridView.
Pedro77
Para actualizar Grid es necesario volver a ejecutar la instrucción linq.
Jeff
1
¿Qué es dgvSelectedNode.Show ()?
Duan Walker
18

Lo siguiente debería funcionar siempre que esté vinculado a cualquier cosa que implemente IEnumerable <string>. Vinculará la columna directamente a la cadena en sí, en lugar de a una ruta de propiedad de ese objeto de cadena.

<sdk:DataGridTextColumn Binding="{Binding}" />
jamisonLikeCode
fuente
He probado esta sugerencia y funcionó bien. Es más limpio que las otras soluciones.
Gustavo Cardoso
7
¿No es esto específico de Silverlight?
NoviceProgrammer
2
esto también funciona en WPF ... ¿por qué votarías a favor de un comentario incorrecto?
Boppity Bop
4
Votación negativa porque la pregunta original tiene la etiqueta "datagridview", que es el control de winforms. Esta solución no se aplica a winfroms.
VIS
13

también puede usar linq y tipos anónimos para lograr el mismo resultado con mucho menos código como se describe aquí .

ACTUALIZACIÓN: el blog no funciona, aquí está el contenido:

(..) Los valores que se muestran en la tabla representan la longitud de las cadenas en lugar de los valores de la cadena (!) Puede parecer extraño, pero así es como funciona el mecanismo de enlace de forma predeterminada: dado un objeto, intentará enlazar con la primera propiedad de ese objeto (la primera propiedad que puede encontrar). Cuando se pasa una instancia, la clase String, la propiedad a la que se une es String.Length, ya que no hay otra propiedad que proporcione la cadena real.

Eso significa que para que nuestro enlace sea correcto, necesitamos un objeto contenedor que expondrá el valor real de una cadena como una propiedad:

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

Si bien esta solución funciona como se esperaba, requiere bastantes líneas de código (principalmente para convertir la lista de cadenas a la lista de envoltorios de cadenas).

Podemos mejorar esta solución usando LINQ y tipos anónimos; usaremos la consulta LINQ para crear una nueva lista de envoltorios de cadenas (el envoltorio de cadenas será un tipo anónimo en nuestro caso).

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

 Table1.SetDataBinding(values.ToList());

El último cambio que vamos a hacer es mover el código LINQ a un método de extensión:

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 esta manera podemos reutilizar el código llamando a un método único en cualquier colección de cadenas:

Table1.SetDataBinding(testData.CreateStringWrapperForBinding());
Jarek Kardas
fuente
8

Este es un problema común, otra forma es usar el objeto 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" });

Este problema se describe en detalle aquí: http://www.psworld.pl/Programming/BindingListOfString

usuario1246920
fuente
2
Pero la tabla de datos es más pesada que List <T>, y la mayoría de los desarrolladores evitarían el uso de la tabla de datos.
Musikero31
2

Es posible que tenga problemas de rendimiento al asignar listas realmente grandes a través de LINQ. La siguiente solución es adecuada para listas grandes y sin subclases de cadenas:

Configure DataGridView (aquí "Ver") en modo virtual, cree la columna que necesita y anule / registre el evento 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();
}

entonces puede simplemente asignar su lista a DataGridView:

List<String> MyList = ...
View.DataSource = MyList;
usuario3042599
fuente
2

Prueba esto :

//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
fuente
1
Te das cuenta de que esta pregunta tiene como 6 años y ha sido respondida, ¿verdad?
Hozikimaru
2
primero debe agregar columnas a la vista de cuadrícula de datos o esto no funcionará
deltanine
0

Una alternativa es usar una nueva función auxiliar que tomará valores de List y se actualizará en DataGridView de la siguiente manera:

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

Entonces podemos llamar a esta función de la siguiente manera:

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