如何在ListView中获取选定的子项索引并将其突出显示?

3
我正在尝试获取所选ListViewItem的索引,以便当用户单击特定行(如第2行)时,将单击的单元格文本设置为TextBox的文本。我还希望仅突出显示此单元格,理想情况下使用ListView使用的常规选择方式,或者我需要创建一个继承自ListView的类来完成此操作?类似于这样:

enter image description here enter image description here


@RezaAghaei:我没有想到使用DGV,我猜我更多地使用listviews来保持简单。 - Joan Venge
2
从.NET 2.0开始,我再也没有使用ListView来显示这样的列表了。假设您有一个项目列表,那么在DataGridView中显示它们就像dataGridView1.DataSource = list;一样容易,或者您要在这里做的就像dataGridView1.SelectionMode = DataGridViewSelectionMode.CellSelect;一样简单。我认为最好将其视为未来应用程序的选项 :) - Reza Aghaei
@Reza:哦,我明白了。在我的情况下,我只实时更新显示当前加密货币价格的几个单元格,而将其余部分保留,那么DGV能做到这一点吗?或者对于更新其元素/项来说,它是全有或全无的? - Joan Venge
1
你可以像在ListView中更新单个单元格一样,在DataGridView中进行更新,甚至更好(使用数据绑定)。 - Reza Aghaei
1
你不应该删除这篇帖子,毕竟除了 Joan 之外,可能还有其他人会发现它很有用。 - Reza Aghaei
显示剩余2条评论
1个回答

5
你可以通过绘制 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事件),您可以更改子项的颜色并保存先前的状态(仅在此处使用颜色)。最好保存状态,因为每个子项都可以有自己的设置,因此您不能仅将其恢复为父ListViewItem或ListView值。
如上所述,在每个父ListViewItem中设置{{link1:UseItemStyleForSubItems = false}},否则将忽略颜色设置。
另外,{{link2:FullRowSelect}}必须设置为false,否则没有意义:)
在这里,状态保存在可空命名元组字段(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


关于项目/子项目索引,正如问题中所提到的:

当您使用 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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接