2011-01-21 48 views
13

Nói tóm lạiWinForms ComboBox SelectedIndexChanged không bắn khi gõ vài ký tự sau đó Alt + Down

Khi tôi gõ một nhân vật trong một ComboBox, nhấn Alt + Down sau đó Enter hoặc Tab, sự kiện SelectedIndexChanged không lửa, mặc dù giá trị SelectedIndex thực hiện thay đổi! Tại sao sự kiện không cháy?

Cập nhật Lỗi tương tự xảy ra nếu bạn nhập ký tự, nhấn Alt + Down và sau đó nhập Esc. Bạn sẽ mong đợi Esc để hủy thay đổi. Tuy nhiên, SelectedIndex thực hiện thay đổi và sự kiện SelectedIndexChanged không kích hoạt.

Điều gì sẽ xảy ra nếu bạn chỉ cần nhập Alt + Down, sử dụng các phím mũi tên để duyệt đến mục nhập và sau đó loại Esc? Liệu chỉ mục đã chọn có được đặt trở lại giá trị ban đầu của nó không?


Không quá ngắn

Tôi có một ứng dụng WinForm với một ComboBox trên đó. Sự kiện SelectedIndexChanged của ComboBox được kết nối với một trình xử lý sự kiện hiển thị SelectedItem trong một điều khiển Label. Bộ sưu tập các mục của ComboBox có ba giá trị: "Một", "Hai" và "Ba".

  • Khi tôi chọn một mục bằng chuột, sự kiện sẽ kích hoạt.
  • Khi tôi di chuyển chuột, sự kiện sẽ kích hoạt.
  • Khi tôi sử dụng Alt + Down để mở rộng hộp tổ hợp và đi qua các mục có Lên và Xuống, sự kiện sẽ kích hoạt.
  • Nhưng ... Khi tôi nhập ký tự đầu tiên của giá trị, rồi nhấn Alt + Down, sau đó nhấn Enter hoặc Tab, giá trị sẽ được chọn và được hiển thị trong hộp tổ hợp, nhưng sự kiện không ngọn lửa.

Tôi cũng đã thêm nút hiển thị SelectedIndex. Nó cho thấy SelectedIndex đã thay đổi. Vì vậy, mặc dù SelectedIndex không thay đổi, sự kiện SelectedIndexChanged không kích hoạt!

Nếu tôi chỉ nhập giá trị hợp lệ nhưOnesự kiện này không kích hoạt, nhưng trong trường hợp đó, nhấp vào nút cho thấy thực tế SelectedIndex chưa thay đổi. Vì vậy, trong trường hợp đó, hành vi là bình thường.


Để tái tạo, tạo Biểu mẫu và thêm ComboBox, Nhãn và nút. Đặt mã sau vào 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); 
     } 
    } 
} 
+0

tôi muốn cùng một vấn đề và vì vậy tôi xử lý sự kiện TextChanged. Theo trang MSDN - sự kiện SelectedIndexChanged sẽ được kích hoạt khi giá trị ** của thuộc tính SelectedIndex thay đổi. – adatapost

+0

@adatapost: Cách tôi mô tả mọi thứ ở đây (nhập char đầu tiên, sau đó nhấn Alt + Down) sau đó nhấp vào nút) cho thấy rằng SelectedIndex thực sự * không * thay đổi. – comecme

Trả lời

4

Giá trị thuộc tính DropDown thích hợp ở đây là DropDownList. Nó không có vấn đề này.

Đưa ra giải pháp cho vấn đề cụ thể của bạn với kiểu DropDown được đặt thành DropDown khá khó khăn. Nó cho phép người dùng gõ văn bản tùy ý và thậm chí là một kết hợp hoàn hảo với một trong các mục thả xuống không thay đổi SelectedIndex. Bạn sẽ phải triển khai sự kiện Xác thực và tìm kiếm chính bạn.Sự kiện DropDownClosed sẽ tốt cho kịch bản cụ thể của bạn. Nhưng thực sự, luôn luôn sử dụng DropDownList nếu bạn muốn kết hợp hoàn hảo.

+0

Tình huống của tôi không phải là người dùng nhập vào mục nhập hoàn chỉnh, chỉ là ký tự đầu tiên, sau đó nhấn Alt + Down. Và như nút của tôi cho thấy, theo cách này nó * * thay đổi SelectedIndex. Đó chính là điều làm tôi bực mình. SelectedIndex * có * thay đổi, nhưng sự kiện không kích hoạt. – comecme

+2

Yup, buồn phải không? Quan điểm của tôi là bạn không bao giờ có thể dựa vào SelectedIndex trừ khi bạn thiết lập kiểu DropDown thành DropDownList. Bạn đã thử chưa? –

+0

Vâng tôi có. Nhưng bằng cách sử dụng DropDownStyle nó không thực sự là một combobox nữa. Nó vô hiệu hóa khả năng nhập vào một giá trị không có trong danh sách. Nó cũng làm cho nó không thể nhập nhiều ký tự của giá trị bạn muốn chọn. Nếu bạn gõ AB để có được một mục bắt đầu với AB, bạn thực sự di chuyển đến mục nhập đầu tiên bắt đầu với B. – comecme

5

Tôi đã thử một số tìm kiếm trên google để tìm câu trả lời cuối cùng về điều này nhưng không tìm thấy câu trả lời trước đây. Ngay bây giờ tôi đã tìm thấy một chủ đề thực sự đề cập đến một bài viết cơ sở tri thức Microsoft về vấn đề này. Điều KB948869 mô tả sự cố.

Bài viết cơ sở kiến ​​thức đề xuất để tạo combobox của riêng bạn và ghi đè lên phương thức 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); 
    } 
} 

Tôi đã thử, nhưng rất tiếc, dường như nó không có hiệu lực. Đó là một chút lạ. Tôi mong chờ một giải pháp được mô tả trong bài viết cơ sở tri thức là chính xác.

Tôi đã tìm thấy một cách giải quyết khác, đó là sử dụng sự kiện DropDownClosed thay thế.

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

này dường như để làm việc, nhưng chỉ khi sử dụng DropDownStyle.DropDown. Khi bạn đặt DropDownStyle thành DropDownList, nhập một ký tự không kích hoạt DropDownClosed (vì không có thả xuống thực tế trong trường hợp đó). Chỉ khi bạn thực sự mở danh sách thả xuống và chọn một giá trị, sự kiện DropDownClosed được kích hoạt.

Vì vậy, cả hai tùy chọn không thực sự là câu trả lời hay.

Cập nhật Tôi thậm chí đã cố gắng ghi đè thuộc tính SelectedIndex trong MyComboBox, có gọi là OnSelectedIndexChanged(EventArgs.Empty). Sau khi nhập một ký tự và nhấn Alt + Down, trình thiết lập được thực hiện, nhưng nó sẽ đặt giá trị thành -1, mà nó đã có. Sau khi nhấn Tab, trình cài đặt không được thực hiện lại, mặc dù bằng cách nào đó giá trị SelectedIndex thực hiện thay đổi. Dường như ComboBox trực tiếp thay đổi trường sao lưu cho SelectedIndex, bỏ qua cài đặt. Tôi tin rằng một cái gì đó như thế này có lẽ cũng xảy ra trong ComboBox thực sự.

2

Sửa lỗi nếu tôi sai. Đây là mã tôi đã sử dụng.

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; 
}; 
+1

Nếu tôi nhập vào một mục nhập hiện có hoàn chỉnh, điều này thực sự kích hoạt SelectedIndexChanged và hiển thị chỉ mục trên nhãn. Nhưng nếu tôi nhập một ký tự (ví dụ: T) thì nhấn Alt + Down, sau đó nhấn Tab, mục nhập trong combobox thay đổi thành Hai, sự kiện TextChanged kích hoạt, mã của bạn sẽ đặt SelectedIndex thành 1, nhưng SelectedIndexChanged không kích hoạt. Điều này là do nhấn Tab đã thay đổi SelectedIndex thành 1 trước khi sự kiện TextChanged kích hoạt. Thiết lập SelectedIndex từ bên trong TextChanged sau đó không thực sự thay đổi chỉ mục, vì vậy SelectedIndexChanged không kích hoạt. – comecme

+1

Điều gì đó khác cũng sai. Sau khi gõ 'Hai' kết hợp được thực hiện bởi TextChanged, dẫn đến một sự thay đổi trong SelectedIndex, dẫn đến việc bắn SelectedIndexChanged, đặt nhãn để hiển thị chỉ mục. Nhưng ... khi tôi rời khỏi combobox, SelectedIndex thực tế được đặt thành -1! Điều này không kích hoạt SelectedIndexChanged, nhưng nếu bạn kiểm tra giá trị trong trình gỡ rối, bạn sẽ thấy nó được đặt thành -1. – comecme

+2

Đồng ý! Bạn có thể thử tính năng tự động hoàn thành và tính năng này sẽ hoạt động. Theo trang MSDN xã hội - SelectedIndexChanged Event: "Xảy ra khi thuộc tính SelectedIndex đã thay đổi." Nó không phải là một lỗi, đó là một tính năng. Chủ đề - http://social.msdn.microsoft.com/Forums/en/winforms/thread/59a23260-bf7b-455e-bbf2-2ad9c4aa07e0 – adatapost

2

tôi đã có vấn đề ESC trên một combobox DropDownList kiểu. Tôi đã sửa đổi một chút những gì đã làm việc cho tôi để đáp ứng nhu cầu của bạn:

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); 
    } 
    } 
} 

Điều này làm là lắng nghe các thao tác gõ trong khi menu thả xuống được mở. Nếu đó là ESC, TAB hay ENTER cho một ComboBox kiểu DropDown hoặc ESC cho một ComboBox kiểu DropDownList, một -Event SelectedIndexChanged được kích hoạt khi thả xuống được đóng lại.
Tôi chưa bao giờ sử dụng ComboBoxStyle.Simple và không thực sự biết nó hoạt động như thế nào, nhưng vì hiểu biết tốt nhất của tôi chưa bao giờ hiển thị DropDown, điều này sẽ an toàn ngay cả đối với kiểu đó.

Nếu bạn không muốn lấy được từ ComboBox để tạo điều khiển của riêng mình, bạn cũng có thể áp dụng logic tương tự cho ComboBox trên biểu mẫu bằng cách đăng ký các sự kiện PreviewKeyDownDropDownClosed.

1

tôi đã kết thúc phát sinh lớp riêng tôi từ 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); 
    } 
} 
Các vấn đề liên quan