如何在 Listview 中获取选定的 SubItem 索引并突出显示它?

问题描述

我正在尝试获取选定的 ListViewItem 索引,以便当用户单击特定行(例如第 2 行)时,我希望将单击的单元格的文本设置为 TextBox 的文本。

我也想只突出显示这个单元格,理想情况下使用 ListView 使用的常规选择,或者我是否需要创建一个从 ListView 继承的类来执行此操作?

像这样:

enter image description here

enter image description here

解决方法

您可以自己绘制选中的 ListViewItem.ListViewSubItem,所有者绘制控件(设置 ListView.OwnerDraw = true),然后处理 ListView.DrawSubItem 事件。
ListView.DrawColumnHeader 事件可以使用默认值。

▶ 我正在使用 TextRenderer,因为这是默认渲染器。如果您使用 Graphics.DrawText,您会注意到不同之处。

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

或者,您可以在通知鼠标交互时更改子项的颜色(此处使用 MouseDown 事件)并保存之前的状态(此处仅保存颜色)。最好保存状态,因为每个 SubItem 都可以有自己的设置,因此您不能只是恢复到父 ListViewItem 或 ListView 值。

如前所述,在每个父 ListViewItem 中设置 UseItemStyleForSubItems = false,否则忽略颜色设置。
此外,FullRowSelect 必须设置为 false,否则毫无意义:)

这里,状态保存在一个名为 Tuple 字段的可空字段 (ListViewSubItem,Color[]) 中。
类对象可能更好,只是更短。

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

这就是它的工作原理:

ListView SubItem Selection


▶ 关于 Item / SubItem 索引,正如问题中提到的:

当您检索ListView.HitTest点击的ListViewItem / SubItem

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

那么ListViewItem索引当然是:

var itemIndex = hitTest.Item.Index;

SubItem.Index 是:

var subItemIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);