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

时间:2011-03-03 10:44:54

标签: c# winforms listview focus backcolor

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

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

listviewitem.BackColor = Color.LightSteelBlue;

我尝试过的事情:

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

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

有什么想法吗?

更多信息:

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

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

  • 计算机没有键盘或鼠标,只有条形码阅读器。

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

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

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

6 个答案:

答案 0 :(得分:34)

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

中选择了“测试项目六”

Screenshot of test project — note that "Test Item Six" is highlighted, even though the ListView control does not have the focus.

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

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

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

我现在可以告诉你,将注意力集中在改变焦点的事件上是错误的。在Windows中这是一个很难的规则,你不允许这样做,documentation甚至警告你明确不要这样做。据推测,你的回答将是“我必须”的,但这不是理由。如果一切都按预期工作,那么你首先不会问这个问题。

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

但令人惊讶的是,我很少相信您会想要修复您的应用程序。忽略文档中警告的人往往是那些不在Q&amp; A网站上听取善意建议的人。因此,我会告诉你如何获得你想要的效果。 关键在于不设置ListViewItem的{​​{1}}属性,这可以避免自定义Selected与系统默认突出显示颜色之间的冲突。它还可以释放你必须明确地将焦点设置到BackColor控件并再次返回(正如我们上面所建到的那样,实际上并没有发生,考虑到你的ListView事件处理程序方法)。这样做会产生以下结果:

Fixed sample — notice the ugly blue color of the "selected" item contrasting with my current theme settings.

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

Leave

答案 1 :(得分:20)

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

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

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

具有焦点时,显示ObjectListView。

enter image description here

答案 2 :(得分:1)

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

    }

答案 3 :(得分:1)

这是一个不允许多项选择的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();
    }
    
  4. 注意:此解决方案会导致一些闪烁。对此的修复涉及为您创建ListView控件的子类 可以将受保护的属性 DoubleBuffered 更改为true。

    public class ListViewEx : ListView
    {
        public ListViewEx() : base()
        {
            this.DoubleBuffered = true;
        }
    }
    

答案 4 :(得分:0)

在这种情况下,您无法将注意力集中在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
            }
        }
    }

答案 5 :(得分:-1)

就这样做:

  1. 设置属性UnfocusedHighlighForegroundColor =&#34; Blue&#34;
  2. 设置属性UnfocusedHighlighBackgroundColor =&#34; White&#34;
  3. 设置属性UserCustomSelectionColors = true
  4. 祝你好运:)