ComboBox - определить, является ли изменение человеческим или программным

Как определить, выполняется ли событие изменения SelectedIndexChanged() человеком (клики) или программно?

private void MyComboBox_MouseDown(object sender, MouseEventArgs e)
{
   Console.WriteLine("MouseDown...");
}
private void MyComboBox_MouseUp(object sender, MouseEventArgs e)
{
   Console.WriteLine("MouseUp...");
}
private void MyComboBox_SelectionChangeCommitted(object sender, EventArgs e)
{
   Console.WriteLine("SelectionChangeCommitted...");
}
private void MyComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
   Console.WriteLine("SelectedIndexChanged... By Human or Programmatically?");
}

Примечания

  • Событие Click не запускается для элементов ComboBox, а только когда вы нажимаете на сам ComboBox.
  • У меня есть сотни вызовов функций, которые программно изменяют ComboBox, поэтому добавить флаг для каждого из них будет очень сложно.

Как узнать, является ли событие SelectedIndexChanged() человеческим или программным?

Почему именно вам нужно различать, как было сделано изменение? На какую проблему вы пытаетесь ответить?

PaulF 21.02.2023 15:43

Существует функция UpdateServer(), которая вызывается, когда запускается событие IndexChanged, проблема в том, что мы не хотим, чтобы эта функция вызывалась, если человек делает изменение.

Albert Shown 21.02.2023 15:47

Изменяются ли эти ComboBox программно после того, как форма появится на экране? Если нет, то вы можете просто установить флаг после загрузки формы.

LarsTech 21.02.2023 15:48

Что именно вы подразумеваете под «программно»? приложение будет запущено, элементы будут загружены в поле со списком, а выбранный индекс будет изменен программно без участия человека?

mehmetx 21.02.2023 16:01
SelectionChangeCommitted вызывается перед SelectedIndexChanged. Вы можете установить флаг, когда вызывается первый, чтобы вы знали, что изменение вызвано действием пользователя. Флаг не установлен, сделано в коде
Jimi 21.02.2023 16:23

Чтобы избежать проблемы XY -> «Программно» означает, что существует отдельный поток, который постоянно обновляет COmboBox каждые пару секунд. Когда изменение запускается, нам нужно знать, было ли оно произведено этим потоком или кликом человека.

Albert Shown 21.02.2023 16:26

@джими ты уверен? Я попробую прямо сейчас.

Albert Shown 21.02.2023 16:27

@Джими, вот оно!!! Это именно то, что мы должны делать. простой один флаг в SelectionChangeCommitted сделал свое дело. Пожалуйста, создайте ответ, чтобы другие парни в будущем могли извлечь из этого пользу. Спасибо.

Albert Shown 21.02.2023 16:48

Обратите внимание на это из документации для события SelectionChangeCommitted: «Однако, в зависимости от того, как настроен ComboBox и как пользователь изменяет выбранный элемент, событие SelectionChangeCommitted может не возникать». : learn.microsoft.com/en-us/dotnet/api/…

PaulF 21.02.2023 16:54

Это страшно, но в моем случае SelectionChangeCommitted срабатывает только тогда, когда пользователь вносит изменения.

Albert Shown 21.02.2023 17:12
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
0
10
76
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ловите Enter и Leave события. Человеческие изменения не могут быть сделаны без предварительного входа. Установите и снимите флажок, как bool my_cb_focus;

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

PaulF 21.02.2023 15:39

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

Albert Shown 21.02.2023 15:44

@AlbertShown Я попробовал клавиши со стрелками вверх / вниз, и они запускают изменение индекса перед выходом.

i486 21.02.2023 15:45

См. также GetLastInputInfo Win32 API.

i486 21.02.2023 15:48

Вы можете использовать логическое значение, чтобы событие возвращалось мгновенно, например:

private bool myComboBoxAllowIndexChangeEvent = true;
private void MyComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
   if (!myComboBoxAllowIndexChangeEvent)
   {
      Console.WriteLine("SelectedIndexChanged Programmatically");
      return;
   }

   Console.WriteLine("SelectedIndexChanged By Human");
}

private void SelectSomeComboBox() {
   myComboBoxAllowIndexChangeEvent = false;

   MyComboBox.SelectedIndex = MyComboBox.FindStringExact("test")

   myComboBoxAllowIndexChangeEvent = true;
}

Из вопроса: I have hundreds of function calls that change the ComboBox programmatically, so adding a flag on each one will be very hard to do.

LarsTech 21.02.2023 15:53

Из того, что я прочитал в Документации Microsoft, я не думаю, что возможно изменить индекс, не уведомляя объект о запуске его событий. Вы можете удалить событие из объекта или иметь логический или любой другой тип данных для одного или нескольких полей, чтобы выяснить, как оно было вызвано.

Winjas Force 21.02.2023 16:10

@WinjasForce, вы правы в своем комментарии, это невозможно (неявно), но, по крайней мере, у нас должно быть больше приоритетов в отношении этого события, что-то, чтобы знать, происходит ли это щелчком мыши или вызовом API и т. д.

Albert Shown 21.02.2023 16:18
Ответ принят как подходящий

Что сработало для меня, так это установить флаг для события SelectionChangeCommitted, которое запускается только тогда, когда изменение вызвано пользовательским вводом.


Пример

public MainForm()
{
    InitializeComponent();
    comboBox.Items.AddRange(
        new object[] 
        { 
            Color.Red, 
            Color.Green, 
            Color.Blue, 
        });
    comboBox.SelectedIndex = 0;

    // Programmatically change CB
    numericUpDown.Maximum = 2;
    numericUpDown.ValueChanged += (sender, e) => 
        comboBox.SelectedIndex = (int)numericUpDown.Value;

    comboBox.SelectionChangeCommitted += (sender, e) =>
    {
        _isUserChange= true;
    };

    comboBox.SelectedIndexChanged += (sender, e) =>
    {
        string msg = _isUserChange ? "USER CHANGE" : "PGM CHANGE";

        richTextBox.SelectionColor = (Color)comboBox.SelectedItem;
        richTextBox.AppendText($"{msg}{Environment.NewLine}");

        numericUpDown.Value = (int)comboBox.SelectedIndex;
        _isUserChange= false;
    };
}
bool _isUserChange = false;

Да, SelectionChangeCommitted это способ сделать это. Спасибо за скриншоты и объяснение.

Albert Shown 21.02.2023 21:36

Другие вопросы по теме