domingo, 21 de febrero de 2010

[Winforms] - ListView, como usarlos y pasar ítems entre ellos

 

Introducción


En este articulo tratare de mostrar como se hace uso de ListView de manera que se puedan visualizar los registros, y manipularlos, en este caso se editara individualmente un ítem de la lista, y se trabajara mediante la el pasaje de la selección a otro ListView.

Algunas propiedades importante que se han usado en el ejemplo son

- View= Details, permite definir el layout de los ítem dentro del ListView, por tratarse de ítem con estilo de grilla, se usa el modo de detalle.

- FullRowSelect = True, esta propiedad permite que al seleccionar un ítem este sea se resalte a lo largo del registro

- HideSelection = False, cuando el control pierde el foco este mantiene un un control griseada la selección activa.

La creación de las columnas fue realizada en tiempo de diseño, para los cual se hizo uso las opciones mostradas en la siguiente imagen

 

 

Carga del ListView


El primer paso que se realizaría será la carga de los ítems dentro del control.

private void Form1_Load(object sender, EventArgs e)
{
    DataTable dt = ObtenerDatos();

    foreach (DataRow row in dt.Rows)
    {
        ListViewItem item = new ListViewItem(Convert.ToString(row["id"]));
        item.SubItems.Add(Convert.ToString(row["descripcion"]));
        item.SubItems.Add(Convert.ToString(row["precio"]));

        lswProductos.Items.Add(item);  

    }
}

A modo de ejemplo en este caso se ha usado como origen de dato un DataTable cargado manualmente desde código:

private DataTable ObtenerDatos()
{
    DataTable dt = new DataTable();

    dt.Columns.Add("Id");
    dt.Columns.Add("descripcion");
    dt.Columns.Add("precio");

    DataRow row = dt.NewRow();
    row["id"] = 1;
    row["descripcion"] = "Prod 1";
    row["precio"] = 140;
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["id"] = 2;
    row["descripcion"] = "Prod 2";
    row["precio"] = 30;
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["id"] = 3;
    row["descripcion"] = "Prod 3";
    row["precio"] = 60;
    dt.Rows.Add(row);

    row = dt.NewRow();
    row["id"] = 4;
    row["descripcion"] = "Prod 4";
    row["precio"] = 110;
    dt.Rows.Add(row);
    return dt;
}

 

En este caso por cada ítem del origen de datos se recorrer en un ciclo del foreach y se van creando los ListViewItem que definen cada registro.

A cada ítem del ListView se le definen sus SubItems que representaran las columnas.

Debe aclararse que la primer columna en el ListView es representada por el propio ListViewItem, es por eso que no hay un SubItem que represente la columna “Id”.

 

Pasaje de ítems entre ListView


Una de las acciones mas comunes es la selección de ítems para su posterior trabajo con estos datos.

Es por eso que en el ejemplo se veras dos botones que permitirán pasar los registros entre controles.

 

private void btnAgregar_Click(object sender, EventArgs e)
{
    foreach(ListViewItem item in lswProductos.SelectedItems)
    {
        lswProductos.Items.Remove(item); 
        lswProductosSeleccionados.Items.Add(item);
    }
}

private void btnQuitar_Click(object sender, EventArgs e)
{
    foreach (ListViewItem item in lswProductosSeleccionados.SelectedItems)
    {
        lswProductosSeleccionados.Items.Remove(item);
        lswProductos.Items.Add(item);
    }
}

Como se observa en cada caso las listas son recorridas en sus ítems seleccionados, procediendo a la eliminación del registro y su posterior agregado en la segunda lista.

 

Edición del ítem seleccionado


Algo que será raro encontrar en el ListView, es que este no posee un método claro para poder detectar cual es el registro o ítem actualmente seleccionado, todas las propiedades hacen referencia a un conjunto de registros.

 

private void lswProductos_MouseDoubleClick(object sender, MouseEventArgs e)
{
    ListViewItem item = lswProductos.GetItemAt(e.X, e.Y);

    if (item != null)
    {
        txtId.Text = item.Text;
        txtDescripcion.Text = item.SubItems[1].Text;
        txtPrecio.Text = item.SubItems[2].Text;
    }
}

 

El evento MouseDoubleClick posee en sus argumentos dos propiedades que especifican las coordenadas del cursor, las cuales combinadas a el método GetItemAt() permiten seleccionar que ítem se ha pulsado, y con este la edición del mismo

 

[C#]
[VB.NET]

19 comentarios:

  1. Hola Leandro,

    haciendo doble click funciona correctamente, pero como hago cuando el usuario seleccione un item determinado a travez de la tecla "enter", podrias ayudarme por favor ya que le he dado vueltas y no consigo hacerlo, muchisimas gracias de antemano. ROBERTO IZURIETA

    ResponderEliminar
  2. hola, Roberto

    mira publique un ejemplo de codigo sobre el tema

    [Winforms] Seleccionar Fila con ENTER – DataGridView y ListView

    no esta completo aun en la explicacion del articulo, pero si tienes el codigo para descargar

    espero te sea de utilidad
    saludos

    ResponderEliminar
  3. Muchas gracias Leandro por tu respuesta y servicialidad.

    Ya que lo necesitaba urgente, se me ocurrio una solución en base a la clase del evento (MouseDoubleClick) del control ListView que pusistes como ejemplo.

    La solución lo hice con el evento (KeyDown) del control ListView. Aquí te dejo el código de referencia:

    private void lswProductos_KeyDown(object sender, MouseEventArgs e)
    {
    ListViewItem item = lswProductos.GetItemAt(lswProductos.FocusedItem.Position.X, lswProductos.FocusedItem.Position.Y);

    if (item != null & e.KeyCode == Keys.Enter)
    {
    txtId.Text = item.Text;
    txtDescripcion.Text = item.SubItems[1].Text;
    txtPrecio.Text = item.SubItems[2].Text;
    }
    }

    Controla que la tecla presionada sea ENTER, y le paso la posición a travez de (FocusedItem.Position).

    Saludos y que tengas un buen día.

    Roberto Izurieta Moreno

    ResponderEliminar
  4. Perdón hay un error tipográfico en la declaración de la clase:

    FALSO:
    private void lswProductos_KeyDown(object sender, MouseEventArgs e)

    CORRECTO:
    private void lswProductos_KeyDown(object sender, KeyEventArgs e)

    Hasta pronto.

    Roberto Izurieta Moreno.

    ResponderEliminar
  5. Hola Leandro,
    Estoy haciendo un foreach sobre una tabla sql con un listview, en realidad es un filtro para una busqueda sobre la tabla y me esta generando un error de pila.
    genera esto:
    "Excepción no controlada del tipo 'System.StackOverflowException' en mscorlib.dll"
    Me das una mano...
    gracias!!

    ResponderEliminar
  6. hola Santiago

    Disculpa la demora en la respuesta

    La verdad es algo complidado decir que puede estar sucediendo sin poder ver el codigo que usas para cargar la lista.

    Por ahi podrias hacer la pregunta en el foro de MSDN, alli participo activamente, y sino soy yo quien responde seguro alguien mas brindara la ayuda

    Foros MSDN

    saludos

    ResponderEliminar
  7. Me ha salvado, Sr. Leandro! Mis items no se añadían a mi Listview porque olvidaba agregarle columnas y usar el objeto ListViewItem.

    ResponderEliminar
  8. Hola Leandro,
    AProvechando este articulo queria preguntarte como puedo seleccionar un Item de mi listview y luego borrarlo con un boton. He intentado de varias maneras y ya se que ListView NO TIENEN UN METODO PARA TOMAR UNA LINEA y borrarla.
    Trate de recuperar parte del codigo que dejaste en este blog, precisamente la parte:
    'ListView1.Items.Clear()
    'private void lswProductos_MouseDoubleClick(object sender, MouseEventArgs e)

    {

    ListViewItem item = lswProductos.GetItemAt(e.X, e.Y);



    if (item != null)

    {

    txtId.Text = item.Text;

    txtDescripcion.Text = item.SubItems[1].Text;

    txtPrecio.Text = item.SubItems[2].Text;

    }

    }
    Pero no puede adaptarlo a lo que quiero.
    Gracias

    ResponderEliminar
  9. hola Federico

    pero si hay eventos de seleccion, podrias usar el SelectedIndexChanged

    ListView Events

    o sea los eventos son del item del listview
    con la seleccion determinas que item se selecciono y despues usas el Remove()

    How to: Add and Remove Items with the Windows Forms ListView Control

    saludos

    ResponderEliminar
  10. hola leandro .. hay alguna forma de hacer mas ancho el scrolbar de un listview. es que estoy desarrollando un sistema para pantalla tactil y la pantalla es de 7" , y muestro mucha info en listview,, si hay alguna forma te agradeceria mucho oalguna idea..

    ResponderEliminar
  11. hola leandro buenos dias: hay alguna form,a d ehacer mas ancho el ScrollBar de Listview., lo ocupo para un sistema de pantalla tactil

    ResponderEliminar
  12. hola

    la verdad nunca he implementado algo asi, si es un desarrollo tactil deberias evaluar usar WPF

    para winform quizas debas ver si algun api de windows permite lograrlo

    Winforms - Adjust width of vertical scrollbar on CheckedListBox

    saludos

    ResponderEliminar
  13. Hola.
    Existe alguna forma de indicarle qué fila seleccionar por código?
    En el datagridView existe el ".Rows[indice].Selected=true", cómo se haría esto en un ListView?

    Por otra parte, tengo un DatagridView y no sé si convertir el control a ListView, consume menos recursos un ListView que un datagridView? gracias.

    ResponderEliminar
  14. hola joan

    ninguno de los dos consume mas recursos del otro, cada uno tinee su funcionalidad, quizas si el grid se considera mas pesado es porque tiene mas funcionalidad que el listview

    en el listview lo que seleccionas es un item
    ListViewItem.Selected Property

    saludos

    ResponderEliminar
  15. Hola buenas noches,Tengo dos forms,en el primero se llena la lista y en el segundo se muestran los Items seleccionados,y quiero que en el segudo form al elegir uno y eliminarlo se elimine tambien del primer form,como puedo hacerlo?

    ResponderEliminar
  16. Hola tengo una duda en establecer el ancho de una columna de un listview cuando esta en modo TILE. Le paso como parametro en ancho lvw.Columns.Add(texto,ancho,alineamiento) pero no funciona... Mi listview solo va a tener una sola columna

    ResponderEliminar
  17. Hola Leandro quisiera poner dos lineas de texto en una elemento del listview no se si me explico, que la linea del listview se vea algo como
    _________________________________________________________________
    1 x 10 lia $10
    galletita
    _________________________________________________________________

    Gracias

    ResponderEliminar
  18. Hola Leandro, y si en el listview1 el numero de datos es a gusto del usuario como hago para crear el private DataTable ObtenerDatos() ya que ahi esta llamando a todos los elementos de forma manual y pues se supone que yo no sé cuales son los valores que introduzca el usuario y cuantos son, gracias de antemano

    ResponderEliminar
  19. Hola Leandro. Necesito poner los items de un listbox en celdas vacias de una columna de datagridview. Hasta ahora sólo he logrado que se cargue la primera en la primer celda vacia, pero necesito que llene todas las celdas vacias con los valores que estan el en listbox.
    te dejo el código que hasta ahora tengo
    Public Sub inserta()
    Dim Celda
    For i = 0 To FrmSorteo.LstSorteo.Items.Count - 1
    ' Recorremos las filas
    For Each row As DataGridViewRow In FrmSorteo.DgvJuga.Rows
    If (row.IsNewRow) Then
    ' Si es la fila de nuevos registros (la última fila en blanco del control DataGridView), continuamos el bucle.
    Continue For
    End If
    ' Recorremos las celdas de cada fila
    For Each col As DataGridViewCell In row.Cells ' Obtenemos el valor de la celda
    Dim value As Object = col.Value
    If ((value Is Nothing) OrElse (value Is DBNull.Value)) Then ' Al menos una celda está vacía.
    Dim rowIndex As Integer = rowIndex
    Dim columnIndex As Integer = 6 ' Seleccionamos la celda vacía.
    FrmSorteo.DgvJuga.CurrentCell = FrmSorteo.DgvJuga.Rows(rowIndex).Cells(columnIndex)
    Celda = FrmSorteo.DgvJuga.CurrentCell
    ' Abandonamos el procedimiento
    'FrmSorteo.DgvJuga.Rows(i).Cells(6).Value = FrmSorteo.LstSorteo.Items(i).ToString
    'FrmSorteo.LstSorteo.Items.Clear()
    Celda.value = FrmSorteo.LstSorteo.Items(i).ToString
    End If

    Next
    Return
    Next
    Next i
    End Sub

    ResponderEliminar