簡體   English   中英

WinForms ComboBox SelectedIndexChanged在鍵入少量字符后跟Alt + Down時不觸發

[英]WinForms ComboBox SelectedIndexChanged not firing when typing few chars followed by Alt+Down

簡而言之

當我在ComboBox中鍵入一個字符時,按Alt +向下鍵,然后按Enter鍵或Tab鍵,即使SelectedIndex值確實發生更改,也不會觸發SelectedIndexChanged事件! 為什么事件沒有發生?

更新如果鍵入字符,則按Alt +向下鍵,然后鍵入Esc,則會出現相同的錯誤。 您可能希望Esc取消更改。 但是,SelectedIndex 更改,並且不會觸發SelectedIndexChanged事件。

如果只鍵入Alt + Down,使用箭頭鍵瀏覽條目, 然后鍵入Esc,會發生什么? 是否應將所選索引設置回其原始值?


不是那么短暫

我有一個帶有ComboBox的WinForm應用程序。 ComboBox的SelectedIndexChanged事件連接到一個事件處理程序,該事件處理程序顯示Label控件中的SelectedItem。 ComboBox的Items集合有三個值:“One”,“Two”和“Three”。

  • 當我用鼠標選擇項目時,事件將觸發。
  • 滾動鼠標時,事件會觸發。
  • 當我使用Alt + Down擴展組合框並使用向上和向下遍歷項目時,事件將觸發。
  • 但是......當我輸入值的第一個字符時, 然后按Alt + Down,然后按Enter或Tab,值將被選中並顯示在組合框中,但事件不會觸發。

我還添加了一個顯示SelectedIndex的按鈕。 它顯示SelectedIndex 更改。 因此,即使SelectedIndex確實發生了變化,SelectedIndexChanged事件也不會觸發!

如果我只輸入一個有效值,如 One 則事件也不會觸發,但在這種情況下單擊按鈕會顯示SelectedIndex確實沒有更改。 所以在這種情況下行為是正常的。


要重現,請創建一個表單並添加一個ComboBox,一個Label和一個Button。 將以下代碼放在Form1.cs中:

using System;
using System.Windows.Forms;

namespace ComboBoxSelectedIndexChanged
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            comboBox1.Items.AddRange(new object[] {
                "One",
                "Two",
                "Three"
            });
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            label1.Text = "Selected index: " + comboBox1.SelectedIndex;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Selected item: " + comboBox1.SelectedItem +
                "\nSelected index: " + comboBox1.SelectedIndex);
        }
    }
}

我已經嘗試了幾次谷歌搜索,以便找到一個明確的答案,但之前沒有找到。 剛才我找到了一個線程,實際上是指有關該問題的Microsoft知識庫文章。 文章KB948869描述了該問題。

知識庫文章建議創建自己的組合框並覆蓋ProcessDialogKey方法。

using System.Windows.Forms;

public class MyComboBox : ComboBox
{
    protected override bool ProcessDialogKey(Keys keyData)
    {
        if (keyData == Keys.Tab)
            this.DroppedDown = false;
        return base.ProcessDialogKey(keyData);
    }
}

我試過了,但不幸的是,它似乎沒有任何影響。 這有點奇怪。 我希望知識庫文章中描述的解決方法是准確的。

我找到了另一種解決方法,即使用DropDownClosed事件代替。

private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
    label1.Text = "DroDownClosed Selected index: " + comboBox1.SelectedIndex;
}

似乎工作,但使用DropDownStyle.DropDown時只。 當您將DropDownStyle設置為DropDownList時,鍵入一個字符不會觸發DropDownClosed(因為在這種情況下沒有實際的下拉)。 只有當您實際打開下拉列表並選擇一個值時才會觸發DropDownClosed事件。

所以,這兩個選項都不是一個好的答案。

更新我甚至嘗試覆蓋MyComboBox中的屬性SelectedIndex,讓它調用OnSelectedIndexChanged(EventArgs.Empty) 鍵入字符並按Alt + Down后,執行setter,但它將值設置為-1,它已經是。 按下Tab后,不會再次執行setter,盡管SelectedIndex值以某種方式更改。 看起來ComboBox正在直接更改SelectedIndex的支持字段,繞過設置。 我相信這樣的事情也可能發生在真正的ComboBox中。

這里適當的DropDown屬性值是DropDownList。 它沒有這個問題。

針對DropDown樣式設置為DropDown的特定問題的解決方法非常困難。 它允許用戶鍵入任意文本,甚至與其中一個下拉項完美匹配也不會更改SelectedIndex。 您必須實現Validating事件並自己查找匹配項。 DropDownClosed事件對您的特定場景有用。 但實際上,如果你想完美匹配,總是使用DropDownList。

我在DropDownList風格的組合框中遇到了ESC問題。 我略微修改了適合我的工作:

public class MyComboBox : System.Windows.Forms.ComboBox
{
  private bool _sendSic;

  protected override void OnPreviewKeyDown(System.Windows.Forms.PreviewKeyDownEventArgs e)
  {
    base.OnPreviewKeyDown(e);

    if (DroppedDown)
    {
      switch(e.KeyCode)
      {
        case System.Windows.Forms.Keys.Escape:
          _sendSic = true;
          break;
        case System.Windows.Forms.Keys.Tab:
        case System.Windows.Forms.Keys.Enter:
          if(DropDownStyle == System.Windows.Forms.ComboBoxStyle.DropDown)
            _sendSic = true;
          break;
      }
    }
  }

  protected override void OnDropDownClosed(System.EventArgs e)
  {
    base.OnDropDownClosed(e);

    if(_sendSic)
    {
      _sendSic = false;
      OnSelectedIndexChanged(System.EventArgs.Empty);
    }
  }
}

這樣做是聽下拉打開時進來的擊鍵。 如果是ESC,TAB輸入一個DropDown式的組合框或ESCDropDownList風格的組合框,一個SelectedIndexChanged當下拉關閉-活動被觸發。
我從來沒有使用過ComboBoxStyle.Simple ,也不知道它是如何工作的,但是因為據我所知,它永遠不會顯示DropDown,即使對於那種風格也應該是安全的。

如果您不想從ComboBox派生來構建自己的控件,您還可以通過訂閱它的PreviewKeyDownDropDownClosed事件將類似的邏輯應用於表單上的ComboBox。

如我錯了請糾正我。 這是我用過的代碼。

comboBox1.Items.AddRange(new object[] {
                "One",
                "Two",
                "Three"
});

comboBox1.SelectedIndexChanged+=(sa,ea)=>
 {
   label1.Text = "Selected index: " + comboBox1.SelectedIndex;
 };
comboBox1.TextChanged+= (sa, ea) =>
 {
 comboBox1.SelectedIndex = comboBox1.FindStringExact(comboBox1.Text);

 //OR
 //comboBox1.SelectedIndex = comboBox1.Items.IndexOf(comboBox1.Text);
  comboBox1.SelectionStart  = comboBox1.Text.Length;
};

我最終從ComboBox派生出我自己的類:

public class EditableComboBox : ComboBox
{
    protected int backupIndex;
    protected string backupText;

    protected override void OnDropDown(EventArgs e)
    {
        backupIndex = this.SelectedIndex;
        if (backupIndex == -1) backupText = this.Text;
        else backupText = null;
        base.OnDropDown(e);
    }

    protected override void OnSelectionChangeCommitted(EventArgs e)
    {
        backupIndex = -2;
        base.OnSelectionChangeCommitted(e);
    }

    protected override void OnSelectionIndexChanged(EventArgs e)
    {
        backupIndex = -2;
        base.OnSelectionIndexChanged(e);
    }

    protected override void OnDropDownClosed(EventArgs e)
    {
        if (backupIndex > -2 && this.SelectedIndex != backupIndex)
        {
            if (backupIndex > -1)
            {
                this.SelectedIndex = backupIndex;
            }
            else
            {
                string oldText = backupText;
                this.SelectedIndex = -1;
                this.Text = oldText;
                this.SelectAll();
            }
        }
        base.OnDropDownClosed(e);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM