即使专注于另一个控件,如何更改listview选择的行backcolor?

我有一个程序,它使用条形码扫描仪作为输入设备,这意味着我需要将焦点保持在文本框上。

该程序具有listview控件,当扫描某个条形码时,我以编程方式选择其中一个项目。 我通过以下方式设置行的背景颜色:

listviewitem.BackColor = Color.LightSteelBlue; 

我尝试过的事情:

  • listview.HideSelection设置为false
  • 设置颜色后调用listview.Focus()
  • listviewitem.Focused设置为true
  • call listview.Invalidate
  • call listview.Update()
  • call listview.Refresh()
  • 以上的不同组合

我还在计时器中进行了上述组合,以便在不同的线程上调用它们但仍然没有成功。

有任何想法吗?

更多信息:

  • 这里的关键是控制焦点。 当我选择其中一个项目时, listview控件没有焦点
  • 我通过这样做选择一个项目:

     listView1.Items[index].Selected = true; 
  • Focus始终位于文本框中。

  • 电脑没有键盘或鼠标,只有条形码阅读器。

我有这个代码来关注文本框:

 private void txtBarcode_Leave(object sender, EventArgs e) { this.txtBarcode.Focus(); } 

你需要有一个文本框添加该代码来模拟我的问题。

    假设您已将ListView控件的HideSelection属性设置为False,您所描述的内容与预期完全一致 。 这是一个用于演示目的的屏幕截图。 我创建了一个空白项目,向表单添加了ListView控件和TextBox控件,向ListView添加了一些示例项,将其视图设置为“Details”(虽然这适用于任何视图),并将HideSelection为false。 我正如您在问题中所示处理TextBox.Leave事件,并添加了一些简单的逻辑,以便在其名称输入TextBox时选择相应的ListViewItem请注意, ListView选择了“Test Item Six”:

    测试项目的屏幕截图 - 请注意,即使ListView控件没有焦点,也会突出显示“测试项目六”。

    现在,正如我最初所怀疑的那样, 如果你自己设置BackColor属性那么你就会搞砸了 。 我不确定你为什么要这样做,因为控件已经默认使用默认选择颜色来指示所选项目。 如果要使用不同的颜色,则应更改Windows主题,而不是尝试编写代码来执行此操作。

    事实上,如果我添加行item.BackColor = Color.LightSteelBlue除了我现有的代码以选择与键入TextBox的名称相对应的ListViewItem ,我得到的结果与上面显示的完全相同 。 在将焦点设置到控件之前,项目的背景颜色不会更改。 这是预期的行为,因为当他们拥有焦点时所选项目看起来与他们的父控件未聚焦时看起来不同。 聚焦控件上的选定项目使用系统高亮颜色绘制; 未聚焦控件上的选定项目使用系统3D颜色绘制。 否则,无法判断ListView控件是否具有焦点。 此外,当ListView控件具有焦点时,操作系统将完全忽略任何自定义BackColor属性。 背景将以默认系统突出显示颜色绘制。

    当然,将焦点显式设置为ListView控件会导致自定义背景颜色应用于ListViewItem ,并且使用与我在计算机上选择的颜色方案形成鲜明对比的颜色渲染事物(请记住,不是每个人都使用默认值)。 但问题显而易见: 由于您在TextBox.Leave事件处理程序方法中编写的代码,您无法将焦点设置为ListView控件!

    我现在可以告诉你,把焦点放在改变焦点的事件上是不对的。 在Windows中这是一个很难的规则,你不允许这样做, 文档甚至会警告你不要这样做。 据推测,你的回答将是“我必须”的,但这不是借口。 如果一切都按预期工作,那么你首先不会问这个问题。

    所以现在怎么办? 您的应用程序的设计已被破坏。 我建议修理它。 不要尝试自己设置BackColor属性并指示选择了一个项目。 它与Windows突出显示所选项目的默认方式冲突。 此外,请勿尝试将焦点设置在焦点更改事件中。 Windows明确禁止这样做,文档很清楚,你不应该这样做。 如果目标计算机没有鼠标或键盘,则不清楚用户如何将焦点设置为其他任何内容,除非您编写代码来执行此操作,而您不应该这样做。

    但我很少相信你会想要修复你的应用程序。 忽略文档中警告的人往往是那些不在Q&A网站上听取善意建议的人。 因此,我会告诉你如何获得你想要的效果。 关键在于不设置ListViewItemSelected属性,这可以避免自定义BackColor与系统默认高亮颜色之间的冲突。 它还使您不必将焦点显式设置为ListView控件并再次返回(正如我们在上面建立的那样,实际上并没有发生,给定您的Leave事件处理程序方法)。 这样做会产生以下结果:

    修复了示例 - 注意“选定”项目的丑陋蓝色与我当前的主题设置形成对比。

    这是代码 – 它不是很漂亮,但这只是一个概念certificate,而不是最佳实践的样本:

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

    标准ListView不允许您设置所选行的背景颜色。 所选行的背景(和前景)颜色始终由OS的主题控制。

    你必须让所有者绘制你的ListView来解决这个问题,你可以使用ObjectListView 。 ObjectListView是一个围绕.NET WinForms ListView的开源包装器,它使得它容易使用,并且可以轻松地允许在普通ListView中非常困难的东西 – 比如改变了所选行的颜色。

     this.objectListView1.UseCustomSelectionColors = true; this.objectListView1.HighlightBackgroundColor = Color.Lime; this.objectListView1.UnfocusedHighlightBackgroundColor = Color.Lime; 

    这显示了ObjectListView 没有焦点时。

    在此处输入图像描述

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

    这是一个ListView的解决方案,它不允许多个选择,也没有图像(例如复选框)。

    1. 为ListView设置事件处理程序(在此示例中,它名为listView1 ):
      • DRAWITEM
      • 离开(在ListView的焦点丢失时调用)
    2. 声明一个全局int变量(即包含ListView的Form的成员,在本例中它名为gListView1LostFocusItem )并为其赋值-1
      • int gListView1LostFocusItem = -1;
    3. 实现事件处理程序如下:

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

    在这种情况下,您无法将注意力集中在listview控件上。 txtBarcode_Leave方法会阻止这种情况。 但是如果您希望能够通过单击选择listview项目,只需将下面的代码添加到listview的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 } } } 

    就这样做:

    1. 设置属性UnfocusedHighlighForegroundColor =“Blue”
    2. 设置属性UnfocusedHighlighBackgroundColor =“White”
    3. 设置属性UserCustomSelectionColors = true

    祝好运 :)