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

Posted

技术标签:

【中文标题】如何在 Listview 中获取选定的 SubItem 索引并突出显示它?【英文标题】:How to get the selected SubItem index in a Listview and highlight it? 【发布时间】:2021-04-27 16:28:01 【问题描述】:

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

我还想只突出显示这个单元格,最好使用 ListView 使用的常规选择,还是我需要创建一个继承自 ListView 的类来执行此操作?

类似这样的:

【问题讨论】:

为什么不使用DataGridView @RezaAghaei:我没有想到使用 DGV,我想我为了简单起见更多地使用列表视图。 从 .NET 2.0 开始,我再也没有使用 ListView 来显示这样的列表。假设你有一个项目列表,那么在 DataGridView 中显示它们就像dataGridView1.DataSource = list; 一样简单,或者你要在这里做的就像dataGridView1.SelectionMode = DataGridViewSelectionMode.CellSelect; 一样简单。我相信最好将其作为您未来应用程序的一个选项:) 与在 ListView 中更新单个单元格的方式相同,您可以在 DataGridView 中执行相同的操作,甚至更好(使用数据绑定)。 你不应该删除这个帖子,无论如何,除了琼,也许其他人也觉得它有用。 【参考方案1】:

您可以自己绘制选中的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 Field 的可为空的字段中,(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);
    

这就是它的工作原理:


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

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

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

那么ListViewItem索引当然是:

var itemIndex = hitTest.Item.Index;

SubItem.Index 是:

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

【讨论】:

以上是关于如何在 Listview 中获取选定的 SubItem 索引并突出显示它?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用复选框和自定义适配器从 Listview 中获取选定的列表项?

如何在edittext中获取列表选定项目?

获取 ListItem ContextMenu 中的选定项目

如何向Listview中的各列添加数据?

在android的listview中删除选定的行

如何样将listview按数值大小排序