Как изменить ListView выбранную строку backcolor, даже если сосредоточиться на другом элементе управления?

у меня есть программа, которая использует сканер штрих-кода в качестве устройства ввода, поэтому мне нужно сосредоточиться на текстовом поле.

программа имеет элемент управления listview, и я выбираю один из элементов программно при сканировании определенного штрих-кода. Я задать цвет фона строки:

listviewitem.BackColor = Color.LightSteelBlue;

вещи, которые я пробовал:

  • listview.HideSelection значение false
  • вызов listview.Focus() после установки цвет
  • listviewitem.Focused установить в правда
  • вызов listview.Invalidate
  • вызов listview.Update()
  • вызов listview.Refresh()
  • различные комбинации выше

Я также делал комбинации выше вещей в таймере, чтобы они вызывались в другом потоке, но все равно не имели успеха.

какие идеи?

Подробнее:

  • ключ здесь фокус управления. The элемент управления listview не имеет фокуса когда я выберите один из элементов.
  • Я выбираю один пункт, делая:

    listView1.Items[index].Selected = true;
    
  • фокус всегда находится в текстовом поле.

  • компьютер не имеет клавиатуру или мышь, только считыватель штрих-кодов.

у меня есть этот код, чтобы сосредоточиться на текстовом поле:

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

вам нужно, чтобы текстовое поле добавило этот код для имитации моей проблемы.

6 ответов


то, что вы описали работает ровно как и ожидалось, предполагая, что вы установили HideSelection свойства ListView управление в False. Вот скриншот для демонстрационных целей. Я создал пустой проект, добавил ListView управления и TextBox управление в форму, добавлены некоторые элементы образца в ListView, установите его представление в "детали" (хотя это работает в любом представлении) и установите 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, Я ровно то же самое, как показано выше. Цвет фона элемента не изменяется, пока вы не установите фокус на управление. Это ожидается поведение, поскольку выбранные элементы выглядят иначе, когда они имеют фокус, чем когда их родительский элемент управления расфокусирован. Выбранные элементы сосредоточены элементы окрашены с цвета выделения системы; выбранные элементы на нецеленаправленных элементы окрашены с системой 3D цвет. В противном случае было бы невозможно сказать, является ли ListView контроль имел фокус. Более того, любой обычай BackColor недвижимость полностью игнорируется by операционная система, когда ListView управления имеет фокус. Фон окрашивается в цвет подсветки системы по умолчанию.

явная установка фокуса на ListView управление, конечно, вызывает пользовательский цвет фона, который будет применяться к ListViewItem, и вещи рендеринга с цветом, который очень контрастирует с цветовой схемой, которую я выбрал на своем компьютере (помните, не все используют значения по умолчанию). Проблема, однако, сразу становится очевидной:вы не удается установить фокус на ListView управление из-за кода, который вы написали в TextBox.Leave метод обработчика событий!

я могу сказать вам прямо сейчас, что установка фокуса в событии изменения фокуса-это неправильно. Это жесткое правило в Windows, вам не разрешено делать такие вещи, и документация даже предупреждает вас явно не делать этого. Предположительно, ваш ответ будет чем-то вроде "Я должен", но это никакое оправдание. Если все работает, как ожидалось, вы бы не задавали этот вопрос в первую очередь.

Итак, что теперь? дизайн вашего приложения сломан. Я предлагаю починить его. не пытайтесь и обезьяна с установкой BackColor свойство, чтобы указать, что элемент выбран. Он конфликтует с способом по умолчанию, который Windows выделяет выбранные элементы. Кроме того, не пытайтесь установить фокус в событии изменения фокуса. Windows явно запрещает это, и документация ясна, что вы не должны этого делать. Если целевой компьютер не имеет мыши или клавиатуры, неясно, как пользователь собирается установить фокус на что-либо еще в первую очередь, если вы не пишете код для этого, что вы не должны делать.

но у меня на удивление мало веры в то, что вы захотите исправить свое приложение. Люди, которые игнорируют предупреждения в документации, как правило, те же люди, которые не слушают благонамеренные советы на сайтах Q&A. Так что я ... бросьте вам кость и скажите, как получить желаемый эффект. ключ лежит в не установка ListViewItem ' s Selected свойство, которое позволяет избежать конфликта между вашими пользовательскими BackColor и цвет подсветки системы по умолчанию. это также освобождает вас от необходимости явно устанавливать фокус на ListView контроль и обратно (что, как мы установили выше, на самом деле не происходит, учитывая ваш Leave метод обработчика событий). Делает, что производит следующие результат:

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

а вот код-это не очень красиво, но это просто доказательство концепции, не образец лучшей практики:

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 не позволяет установить цвет фона избранные row. Цвета фона (и переднего плана) выбранной строки всегда контролируются темой ОС.

вы должны владелец нарисовать свой 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


On 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
    • Leave (вызывается, когда фокус ListView теряется)
  2. объявить глобальную переменную int (т. е. член формы, содержащей ListView, в этом примере он называется 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, чтобы вы можно изменить защищенное свойство свойство управляет значение true.

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

вы не можете установить фокус на элемент управления ListView в этой ситуации. txtBarcode_Leave метод предотвратить это. Но если вы хотите иметь возможность выбирать элементы listview, нажав на них, просто добавьте код ниже в MouseClick обработчик событий listview:

    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 = "синий"
  2. установить свойство UnfocusedHighlighBackgroundColor = "Белый"
  3. задать свойство UserCustomSelectionColors = true

удачи :)