【问题标题】:ComboBox - Detect if change is by Human or ProgrammaticallyComboBox - 检测更改是由人为还是以编程方式进行
【发布时间】:2023-02-22 04:49:44
【问题描述】:

如何检测更改事件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?");
}

笔记

  • 单击事件does not get fired on ComboBox items,但仅当您单击 ComboBox 本身时。
  • 我有数百个以编程方式更改 ComboBox 的函数调用,因此很难在每个调用上添加一个标志。

如何知道事件 SelectedIndexChanged() 是人为还是程序化?

【问题讨论】:

  • 究竟为什么您需要区分更改是如何进行的?你想回答什么问题?
  • 有一个 UpdateServer() 函数在 IndexChanged 事件被触发时被调用,问题是我们不希望在人类进行更改时调用该函数。
  • 这些 ComboBoxes 是否在屏幕上出现表单后以编程方式更改?如果没有,那么您可以在加载表单后设置一个标志。
  • “以编程方式”到底是什么意思?应用程序将运行,项目将加载到组合框,并且选定的索引将以编程方式更改而无需人工交互?
  • SelectionChangeCommittedSelectedIndexChanged 之前被调用。您可以在调用前者时设置一个标志,这样您就知道更改是由用户操作引起的。没有设置标志,在代码中完成

标签: c# winforms


【解决方案1】:

对我有用的是在 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 是做到这一点的方法。感谢您提供屏幕截图和解释。
【解决方案2】:

捕获EnterLeave 事件。不先进入就不能进行人为改变。设置和清除标志,如bool my_cb_focus;

【讨论】:

  • 该解决方案的问题在于,当鼠标悬停在组合框上时是否可能发生任何编程函数调用。
  • 我明白了,我现在就试一试。我希望 Leave 事件在 Changed 事件之后被触发,否则将无法工作。如果用户使用键盘进行导航,此解决方案也将不起作用。
  • @AlbertShown 我尝试了向上/向下箭头键,它们在离开之前触发了索引更改。
  • 另见GetLastInputInfoWin32 API。
【解决方案3】:

您可以使用 bool 值来告诉事件立即返回,如下所示:

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 Documentation 上读到的内容来看,我不认为在不通知对象触发它的事件的情况下更改索引是不可能的。您可以从对象中删除事件,或者为一个或多个框设置布尔值或任何数据类型,以确定它是如何触发的
  • @WinjasForce,你的评论是对的,这是不可能的(隐含的)但至少我们应该对那个事件有更多的优先级,知道它是通过点击还是通过 API 调用等等......
猜你喜欢
  • 2014-03-25
  • 2014-09-06
  • 1970-01-01
  • 2013-10-30
  • 2012-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多