如何在Listview中获取选中的SubItem索引并高亮显示?
How to get the selected SubItem index in a Listview and highlight it?
我正在尝试获取选定的 ListViewItem 索引,以便当用户单击特定行(例如第 2 行)时,我希望将单击的单元格的文本设置为文本框的文本。
我也只想突出显示此单元格,最好使用 ListView 使用的常规选择,或者我是否需要创建一个继承自 ListView 的 class 来执行此操作?
像这样:
你可以自己画ListViewItem.ListViewSubItem selected, owner-drawing the Control (set 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
,否则没有意义:)
这里,状态保存在一个可空的命名元组字段中,(ListViewSubItem, Color[])
。
class 对象可能更好,只是更短。
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);
我正在尝试获取选定的 ListViewItem 索引,以便当用户单击特定行(例如第 2 行)时,我希望将单击的单元格的文本设置为文本框的文本。
我也只想突出显示此单元格,最好使用 ListView 使用的常规选择,或者我是否需要创建一个继承自 ListView 的 class 来执行此操作?
像这样:
你可以自己画ListViewItem.ListViewSubItem selected, owner-drawing the Control (set 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
,否则没有意义:)
这里,状态保存在一个可空的命名元组字段中,(ListViewSubItem, Color[])
。
class 对象可能更好,只是更短。
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);