即使焦点在另一个控件上,如何更改列表视图选定的行背景颜色?
Posted
技术标签:
【中文标题】即使焦点在另一个控件上,如何更改列表视图选定的行背景颜色?【英文标题】:How to change listview selected row backcolor even when focus on another control? 【发布时间】:2011-07-07 23:18:14 【问题描述】:我有一个使用条形码扫描仪作为输入设备的程序,这意味着我需要将焦点保持在文本框上。
该程序有一个列表视图控件,当扫描某个条形码时,我以编程方式选择其中一个项目。我通过以下方式设置行的背景颜色:
listviewitem.BackColor = Color.LightSteelBlue;
我尝试过的事情:
listview.HideSelection
设置为假
设置颜色后调用listview.Focus()
listviewitem.Focused
设置为真
致电listview.Invalidate
致电listview.Update()
致电listview.Refresh()
以上的不同组合
我还在计时器中进行了上述组合,以便在不同的线程上调用它们,但仍然没有成功。
有什么想法吗?
更多信息:
这里的关键是控制焦点。当我选择其中一项时,listview 控件没有焦点。我通过以下方式选择一项:
listView1.Items[index].Selected = true;
焦点始终在文本框中。
计算机没有键盘或鼠标,只有条形码阅读器。我有这段代码可以将焦点放在文本框上:
private void txtBarcode_Leave(object sender, EventArgs e)
this.txtBarcode.Focus();
您需要有一个文本框添加该代码来模拟我的问题。
【问题讨论】:
无法理解问题所在。代码listView1.Items[0].BackColor = Color.LightSteelBlue;
运行良好。你想达到什么目标却做不到?
我的猜测是默认的 Windows 选择突出显示覆盖了您的自定义背景颜色。实在是没法说;您的问题非常不清楚实际问题是什么。
我已经突出了问题的主要关键。谢谢大家看我的问题。
【参考方案1】:
假设您已将 ListView
控件的 HideSelection
属性设置为 False,您所描述的内容完全按预期工作。这是用于演示目的的屏幕截图。我创建了一个空白项目,在表单中添加了ListView
控件和TextBox
控件,将一些示例项添加到ListView
,将其视图设置为“详细信息”(尽管这适用于任何视图),然后设置HideSelection
为假。正如您在问题中显示的那样,我处理了TextBox.Leave
事件,并添加了一些简单的逻辑来选择相应的ListViewItem
,只要将其名称输入TextBox
。 注意ListView
中选择了“测试项目六”:
现在,正如我最初所怀疑的那样,如果你自己设置BackColor
属性,你会搞砸的。我不确定您为什么要这样做,因为控件已经使用默认选择颜色来默认指示选定的项目。如果你想使用不同的颜色,你应该改变你的 Windows 主题,而不是尝试编写代码来实现它。
事实上,如果我在现有代码之外添加行item.BackColor = Color.LightSteelBlue
以选择与输入TextBox
的名称相对应的ListViewItem
,我得到完全相同的东西如上图所示。在您将焦点设置到控件之前,项目的背景颜色不会改变。这是预期的行为,因为选定的项目在获得焦点时与在父控件未获得焦点时看起来不同。焦点控件上的选定项目用系统突出显示颜色绘制;未聚焦控件上的选定项目使用系统 3D 颜色绘制。否则,将无法判断 ListView
控件是否具有焦点。此外,当ListView
控件具有焦点时,操作系统完全忽略任何自定义BackColor
属性。背景以默认的系统突出显示颜色绘制。
将焦点显式设置到ListView
控件当然会导致自定义背景颜色应用于ListViewItem
,并且渲染的颜色与我选择的配色方案形成鲜明对比在我的电脑上(记住,不是每个人都使用默认值)。但是,问题立即变得显而易见:您无法将焦点设置到 ListView
控件,因为您在 TextBox.Leave
事件处理程序方法中编写了代码!
我现在可以告诉你,在焦点改变事件中设置焦点是错误的做法。在 Windows 中这是一条硬性规定,您不允许这样做,documentation 甚至明确警告你不要这样做。大概,您的回答将类似于“我必须”,但这不是借口。如果一切都按预期工作,那么您一开始就不会问这个问题。
那么,现在呢? 您的应用程序设计已损坏。我建议修复它。不要试图自己设置BackColor
属性来表示选择了一个项目。它与 Windows 突出显示选定项目的默认方式相冲突。另外,不要尝试在焦点改变事件中设置焦点。 Windows 明确禁止这样做,并且文档清楚地表明您不应该这样做。如果目标计算机没有鼠标或键盘,则首先不清楚用户将如何将焦点设置到其他任何东西上,除非您编写代码来执行此操作,而您不应该这样做。
但我非常不相信您会想要修复您的应用程序。忽略文档中警告的人往往是不听问答网站上善意建议的人。所以我会扔给你一根骨头,告诉你如何获得你想要的效果。 关键在于不要设置ListViewItem
的Selected
属性,这样可以避免你自定义的BackColor
和系统默认的高亮颜色冲突。它也让你不用显式设置将焦点移到ListView
控件并再次返回(正如我们在上面建立的,考虑到您的Leave
事件处理程序方法,这实际上并没有发生)。这样做会产生以下结果:
这是代码——它不是很漂亮,但这只是一个概念证明,而不是最佳实践示例:
public partial class Form1 : Form
public Form1()
InitializeComponent();
listView1.View = View.Details;
listView1.HideSelection = false;
private void textBox1_TextChanged(object sender, EventArgs e)
foreach (ListViewItem item in listView1.Items)
if (item.Text == textBox1.Text)
item.BackColor = Color.LightSteelBlue;
return;
private void textBox1_Leave(object sender, EventArgs e)
this.textBox1.Focus();
【讨论】:
哇 - 你在这里有点严厉!但总的来说,这是一个很好的答案;) @Vidar:嗯,经过反思,你是对的。我不知道为什么我在这里如此沮丧。也许评论线程中有一个扩展的交换,现在已被删除。或者我只是心情不好。我并不总是那么脾气暴躁!但是令人沮丧的应用程序确实弄错了...... 谢谢!今天早上已经为此奋斗了几个小时。 跳出框框思考。 按照 Vidar 的评论...我可能不是唯一一个来到这里的人,因为我想强制 ListBox 和 ListView 表现相同。开箱即用的不匹配样式让用户感到困惑。【参考方案2】:标准的ListView
不允许您设置选中 行的背景颜色。所选行的背景(和前景)颜色始终由操作系统的主题控制。
您必须拥有自己的 ListView
才能解决此问题,或者您可以使用 ObjectListView。 ObjectListView 是一个围绕 .NET WinForms ListView 的开源包装器,这使得它非常更易于使用,并且可以轻松实现普通 ListView 中非常困难的事情——比如更改所选行的颜色.
this.objectListView1.UseCustomSelectionColors = true;
this.objectListView1.HighlightBackgroundColor = Color.Lime;
this.objectListView1.UnfocusedHighlightBackgroundColor = Color.Lime;
当它没有有焦点时,这会显示 ObjectListView。
【讨论】:
好主意,但请注意它不适用于“列表”视图模式;您必须切换到“详细信息”查看模式【参考方案3】:这是一个不允许多选的 ListView 的解决方案,并且 没有图像(例如复选框)。
-
为 ListView 设置事件处理程序(在本例中,它被命名为 listView1):
DrawItem
离开(ListView 失去焦点时调用)
声明一个全局int变量(即包含ListView的Form成员,
在此示例中,它被命名为 gListView1LostFocusItem) 并将其赋值为 -1
int gListView1LostFocusItem = -1;
按如下方式实现事件处理程序:
private void listView1_Leave(object sender, EventArgs e)
// Set the global int variable (gListView1LostFocusItem) to
// the index of the selected item that just lost focus
gListView1LostFocusItem = listView1.FocusedItem.Index;
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
// If this item is the selected item
if (e.Item.Selected)
// If the selected item just lost the focus
if (gListView1LostFocusItem == e.Item.Index)
// Set the colors to whatever you want (I would suggest
// something less intense than the colors used for the
// selected item when it has focus)
e.Item.ForeColor = Color.Black;
e.Item.BackColor = Color.LightBlue;
// Indicate that this action does not need to be performed
// again (until the next time the selected item loses focus)
gListView1LostFocusItem = -1;
else if (listView1.Focused) // If the selected item has focus
// Set the colors to the normal colors for a selected item
e.Item.ForeColor = SystemColors.HighlightText;
e.Item.BackColor = SystemColors.Highlight;
else
// Set the normal colors for items that are not selected
e.Item.ForeColor = listView1.ForeColor;
e.Item.BackColor = listView1.BackColor;
e.DrawBackground();
e.DrawText();
注意:此解决方案会导致一些闪烁。解决此问题的方法是对 ListView 控件进行子类化,以便您 可以将受保护的属性 DoubleBuffered 更改为 true。
public class ListViewEx : ListView
public ListViewEx() : base()
this.DoubleBuffered = true;
【讨论】:
控件或表单不必监听它们自己的事件。只需覆盖 OnDrawItem 等。 谢谢。易于使其与多项选择一起使用。但是,使其适用于多列(子项)的干净解决方案仍不清楚。【参考方案4】:在SelectedIndexChanged
:
private void lBxDostepneOpcje_SelectedIndexChanged(object sender, EventArgs e)
ListViewItem item = lBxDostepneOpcje.FocusedItem as ListViewItem;
ListView.SelectedIndexCollection lista = lBxDostepneOpcje.SelectedIndices;
foreach (Int32 i in lista)
lBxDostepneOpcje.Items[i].BackColor = Color.White;
if (item != null)
item.Selected = false;
if (item.Index == 0)
else
lBxDostepneOpcje.Items[item.Index-1].BackColor = Color.White;
if (lBxDostepneOpcje.Items[item.Index].Focused == true)
lBxDostepneOpcje.Items[item.Index].BackColor = Color.LightGreen;
if (item.Index < lBxDostepneOpcje.Items.Count-1)
lBxDostepneOpcje.Items[item.Index + 1].BackColor = Color.White;
else if (lBxDostepneOpcje.Items[item.Index].Focused == false)
lBxDostepneOpcje.Items[item.Index].BackColor = Color.Blue;
【讨论】:
【参考方案5】:在这种情况下,您不能将焦点设置在列表视图控件上。 txtBarcode_Leave
方法可以防止这种情况发生。但是,如果您希望能够通过单击来选择列表视图项,只需将下面的代码添加到列表视图的MouseClick
事件处理程序:
private void listView1_MouseClick(object sender, MouseEventArgs e)
ListView list = sender as ListView;
for (int i = 0; i < list.Items.Count; i++)
if (list.Items[i].Bounds.Contains(e.Location) == true)
list.Items[i].BackColor = Color.Blue; // highlighted item
else
list.Items[i].BackColor = SystemColors.Window; // normal item
【讨论】:
嗨 Anton,很遗憾没有鼠标或键盘。【参考方案6】:就这样吧:
-
设置属性 UnfocusedHighlighForegroundColor = "Blue"
设置属性 UnfocusedHighlighBackgroundColor = "White"
设置属性 UserCustomSelectionColors = true
祝你好运:)
【讨论】:
以上是关于即使焦点在另一个控件上,如何更改列表视图选定的行背景颜色?的主要内容,如果未能解决你的问题,请参考以下文章
如何在另一个视图控制器上向 UInavigationcontroller 显示完整的选定表格单元格