Estoy tratando de obtener el índice ListViewItem seleccionado, de modo que cuando el usuario haga clic en una fila en particular, como la fila 2, quiero que el texto de la celda en la que se hizo clic se establezca en un texto de TextBox.

También quiero resaltar solo esta celda, idealmente usando la selección regular que ListView usa, o ¿necesito crear una clase que herede de ListView para hacer esto?

Algo como esto:

enter image description here enter image description here

2
Joan Venge 23 ene. 2021 a las 13:30

1 respuesta

La mejor respuesta

Puede dibujar usted mismo el ListViewItem.ListViewSubItem seleccionado, propietario-dibujando el Control (set ListView.OwnerDraw = true), luego maneje el evento ListView.DrawSubItem.
El evento ListView.DrawColumnHeader puede usar valores predeterminados.

► Estoy usando TextRenderer desde este es el renderizador predeterminado. Si usa Graphics.DrawText, notará la diferencia.

TextFormatFlags flags = TextFormatFlags.LeftAndRightPadding |
                        TextFormatFlags.VerticalCenter;

private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
    var lv = sender as ListView;
    var subItem = lv.HitTest(lv.PointToClient(MousePosition)).SubItem;

    if (subItem != null && e.SubItem == subItem) {
        using (var brush = new SolidBrush(SystemColors.Highlight)) {
            e.Graphics.FillRectangle(brush, e.SubItem.Bounds);
        }
        TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.SubItem.Font, 
                              e.Bounds, SystemColors.HighlightText, flags);
    }
    else {
        e.DrawDefault = true;
    }
}

private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) 
    => e.DrawDefault = true;

// Invalidate on a mouse interaction, otherwise the ListView doesn't redraw the SubItem
private void listView1_MouseUp(object sender, MouseEventArgs e)
    => (sender as ListView).Invalidate();

O puede cambiar los colores de un subelemento cuando se notifica una interacción del mouse (aquí, usando el evento MouseDown) y guardar el estado anterior (solo los colores aquí). Es mejor guardar el estado porque cada SubItem puede tener su propia configuración, por lo que no puede volver a los valores de ListViewItem principal o ListView.

Como se mencionó, configure UseItemStyleForSubItems = false < / a> en cada ListViewItem principal; de lo contrario, se ignoran las configuraciones de colores.
Además, se debe configurar
FullRowSelect a false, de lo contrario no tiene sentido :)

Aquí, el estado se guarda en un campo de tupla que acepta valores NULL, (ListViewSubItem, Color[]). Un objeto de clase es probablemente mejor, esto es más corto.

private (ListViewItem.ListViewSubItem Item, Color[] colors)? previousItem = null;

private void listView1_MouseDown(object sender, MouseEventArgs e)
{
    var lv = sender as ListView;
    var subItem = lv.HitTest(e.Location).SubItem;

    if (previousItem.HasValue) {
        // If an Item's Colors have been changed, restore the state
        // It removes the selection if you click in an empty area
        previousItem.Value.Item.BackColor = previousItem.Value.colors[0];
        previousItem.Value.Item.ForeColor = previousItem.Value.colors[1];
        lv.Invalidate(previousItem.Value.Item.Bounds);
    }

    if (subItem != null) {
        // Save the SubItem's colors state
        previousItem = (subItem, new[] { subItem.BackColor, subItem.ForeColor });
        // Set new Colors. Here, using the default highlight colors
        subItem.BackColor = SystemColors.Highlight;
        subItem.ForeColor = SystemColors.HighlightText;
        lv.Invalidate(subItem.Bounds);
    }
}

Así es como funciona esto:

ListView SubItem Selection


► Acerca del índice de artículo / subtelemento, como se menciona en la pregunta:

Cuando recupera el ListViewItem / SubItem en el que se hizo clic con ListView.HitTest

 var hitTest = lv.HitTest(e.Location);
   

Entonces el índice ListViewItem es, por supuesto:

var itemIndex = hitTest.Item.Index;

Y el SubItem.Index es:

var subItemIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);
3
Jimi 30 ene. 2021 a las 07:05