Подтвердить что ты не робот

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

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

Программа имеет элемент управления 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();
}

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

4b9b3361

Ответ 1

То, что вы описываете, работает точно так, как ожидалось, предполагая, что для свойства HideSelection элемента управления ListView установлено значение False. Вот скриншот для демонстрационных целей. Я создал пустой проект, добавил элемент управления ListView и элемент управления TextBox в форму, добавил некоторые примеры элементов в ListView, установил его представление в "Детали" (хотя это работает в любом представлении) и установил HideSelection в значение false. Я обработал событие TextBox.Leave так же, как вы показали в вопросе, и добавил некоторую простую логику, чтобы выбрать соответствующий ListViewItem, когда его имя было введено в TextBox. Обратите внимание, что "Test Item Six" выбран в 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 полностью игнорируется операционной системой, когда элемент управления ListView имеет фокус. Фон окрашивается в цвет подсветки системы по умолчанию.

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

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

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

Но у меня удивительно мало веры, что вы захотите исправить свое приложение. Люди, которые игнорируют предупреждения в документации, как правило, являются теми же людьми, которые не прислушиваются к советам по вопросам Q & A. Поэтому я брошу вам кость и расскажу вам, как добиться желаемого эффекта. Ключ заключается в том, что вы не устанавливаете свойство ListViewItem 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();
   }
}

Ответ 2

Стандарт 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

Ответ 3

Вкл 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;
            }
        }

    }

Ответ 4

Здесь решение для ListView, которое не допускает множественных выборов и не имеет изображений (например, флажков).

  • Установите обработчики событий для ListView (в этом примере он называется listView1):
    • DrawItem
    • Оставить (вызывается, когда фокус ListView потерян)
  • Объявить глобальную переменную int (т.е. член формы, которая содержит ListView, в этом примере он называется 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;
    }
}

Ответ 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
            }
        }
    }

Ответ 6

Просто выполните следующие действия:

  • Установить свойство UnfocusedHighlighForegroundColor = "Синий"
  • Установить свойство UnfocusedHighlighBackgroundColor = "White"
  • Установить свойство UserCustomSelectionColors = true

Удачи:)