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

Нечетное поведение при переключении объекта CheckedListBox проверяется с помощью MouseClick при нажатии на один и тот же выбор

Элемент управления WinForms CheckedListBox имеет два поведения по умолчанию при нажатии мышью:

  • Чтобы проверить/снять отметку с элемента, который требуется дважды щелкнуть по элементу. Первый щелчок выбирает элемент, а второй переключает состояние проверки.
  • Кроме того, один последующий щелчок одного и того же элемента переключит это состояние элемента.

В качестве удобства я должен был позволить пользователям переключаться на выбор одним щелчком мыши. Я достиг этого, поэтому теперь поведение по умолчанию # 1 выше достигается за один клик. Проблема в том, что поведение # 2 больше не работает корректно при нажатии на тот же (то есть выбранный в данный момент) элемент. Он отлично работает при переходе между пунктами, который требуется, но для этого требуется до 4 кликов на одном и том же элементе.

Мое обходное решение для этого - дважды вызвать логику переключения, если пользователь повторно выбирает один и тот же элемент. На вопросы:

  • Это работает, но почему? Какова реальная основная проблема?
  • Есть ли лучший способ достичь этого, поэтому я могу заставить его работать как поведение по умолчанию # 2 без вызова метода дважды и отслеживания моего последнего выбора?

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

Здесь мой код:

using System.Linq;
using System.Windows.Forms;

namespace ToggleCheckedListBoxSelection
{
    public partial class Form1 : Form
    {
        // default value of -1 since first item index is always 0
        private int lastIndex = -1;

        public Form1()
        {
            InitializeComponent();
            CheckedListBox clb = new CheckedListBox();
            clb.Items.AddRange(Enumerable.Range(1, 10).Cast<object>().ToArray());
            clb.MouseClick += clb_MouseClick;
            this.Controls.Add(clb);
        }

        private void clb_MouseClick(object sender, MouseEventArgs e)
        {
            var clb = (CheckedListBox)sender;
            Toggle(clb);

            // call toggle method again if user is trying to toggle the same item they were last on
            // this solves the issue where calling it once leaves it unchecked
            // comment these 2 lines out to reproduce issue (use a single click, not a double click)
            if (lastIndex == clb.SelectedIndex)
                Toggle(clb);

            lastIndex = clb.SelectedIndex;
        }

        private void Toggle(CheckedListBox clb)
        {
            clb.SetItemChecked(clb.SelectedIndex, !clb.GetItemChecked(clb.SelectedIndex));
        }
    }
}

Чтобы воспроизвести мою проблему, прокомментируйте строки, указанные в комментариях кода, и выполните следующие действия:

  • Щелкните элемент по индексу 2 - изменения состояния на отмечены.
  • При выборе текущего элемента щелкните его еще раз - состояние не изменяется. Ожидаемый: не отмечен. Нажмите несколько раз, и он, наконец, переключится.

Спасибо за чтение!

4b9b3361

Ответ 1

В качестве удобства я должен был позволить пользователям переключаться на выбор одним щелчком мыши.

Я не уверен, что происходит с кодом, но установка CheckOnClick на true будет делать это:

CheckOnClick указывает, должен ли переключаться флажок, когда выбран элемент. Поведение по умолчанию - это изменение выбора при первом щелчке, а затем повторное нажатие кнопки, чтобы применить галочку. В некоторых случаях, однако, вы можете предпочесть, чтобы элемент был проверен сразу после его нажатия.