Как определить, выполняется ли событие изменения 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?");
}
Примечания
Как узнать, является ли событие SelectedIndexChanged() человеческим или программным?
Существует функция UpdateServer(), которая вызывается, когда запускается событие IndexChanged, проблема в том, что мы не хотим, чтобы эта функция вызывалась, если человек делает изменение.
Изменяются ли эти ComboBox программно после того, как форма появится на экране? Если нет, то вы можете просто установить флаг после загрузки формы.
Что именно вы подразумеваете под «программно»? приложение будет запущено, элементы будут загружены в поле со списком, а выбранный индекс будет изменен программно без участия человека?
SelectionChangeCommitted
вызывается перед SelectedIndexChanged
. Вы можете установить флаг, когда вызывается первый, чтобы вы знали, что изменение вызвано действием пользователя. Флаг не установлен, сделано в коде
Чтобы избежать проблемы XY -> «Программно» означает, что существует отдельный поток, который постоянно обновляет COmboBox каждые пару секунд. Когда изменение запускается, нам нужно знать, было ли оно произведено этим потоком или кликом человека.
@джими ты уверен? Я попробую прямо сейчас.
@Джими, вот оно!!! Это именно то, что мы должны делать. простой один флаг в SelectionChangeCommitted сделал свое дело. Пожалуйста, создайте ответ, чтобы другие парни в будущем могли извлечь из этого пользу. Спасибо.
Обратите внимание на это из документации для события SelectionChangeCommitted: «Однако, в зависимости от того, как настроен ComboBox и как пользователь изменяет выбранный элемент, событие SelectionChangeCommitted может не возникать». : learn.microsoft.com/en-us/dotnet/api/…
Это страшно, но в моем случае SelectionChangeCommitted срабатывает только тогда, когда пользователь вносит изменения.
Ловите Enter и Leave события. Человеческие изменения не могут быть сделаны без предварительного входа. Установите и снимите флажок, как bool my_cb_focus;
Проблема с этим решением будет заключаться в том, что любой из программных вызовов функций может произойти, когда мышь находится над полем со списком.
Понятно, сейчас попробую. Я надеюсь, что событие Leave будет запущено после события Changed, иначе не сработает. Если пользователь использует клавиатуру для навигации, это решение также не будет работать.
@AlbertShown Я попробовал клавиши со стрелками вверх / вниз, и они запускают изменение индекса перед выходом.
См. также GetLastInputInfo Win32 API.
Вы можете использовать логическое значение, чтобы событие возвращалось мгновенно, например:
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.
Из того, что я прочитал в Документации Microsoft, я не думаю, что возможно изменить индекс, не уведомляя объект о запуске его событий. Вы можете удалить событие из объекта или иметь логический или любой другой тип данных для одного или нескольких полей, чтобы выяснить, как оно было вызвано.
@WinjasForce, вы правы в своем комментарии, это невозможно (неявно), но, по крайней мере, у нас должно быть больше приоритетов в отношении этого события, что-то, чтобы знать, происходит ли это щелчком мыши или вызовом API и т. д.
Что сработало для меня, так это установить флаг для события 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 это способ сделать это. Спасибо за скриншоты и объяснение.
Почему именно вам нужно различать, как было сделано изменение? На какую проблему вы пытаетесь ответить?