Biểu mẫu không phản hồi sự kiện KeyDown


82

Tôi đã làm việc một thời gian trong dự án Windows Forms của mình và tôi quyết định thử nghiệm với các phím tắt. Sau khi đọc một chút, tôi nghĩ mình phải viết một trình xử lý sự kiện và liên kết nó với sự kiện KeyDown của biểu mẫu:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Control && e.Alt && e.KeyCode == Keys.O)
    {
        MessageBox.Show("Ctrl+Alt+O: magic!");
    }
}

Tôi đã làm điều đó theo cách tốt là mở bảng Thuộc tính của trình thiết kế Visual Studio, sau đó nhấp đúp vào sự kiện KeyDown của biểu mẫu của tôi để tạo Form1_KeyDowntrình xử lý sự kiện. Nhưng khi kiểm tra ứng dụng của tôi, biểu mẫu hoàn toàn không phản hồi với phím tắt Ctrl+ Alt+ O. Tuy nhiên, nhà thiết kế Visual Studio đã tạo mã để liên kết trình xử lý sự kiện với biểu mẫu:

private void InitializeComponent()
{
    // ...

    this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);

    // ...
}

Vì vậy, tôi đã thử thêm một Console.WriteLine()cuộc gọi vào trình xử lý để kiểm tra xem nó có đang được gọi hay không, nhưng cũng không may mắn.

Ngoài ra, tôi đã cố gắng thiết lập một điểm ngắt trên lệnh gọi ràng buộc sự kiện (được hiển thị ngay bên trên) và thấy rằng chương trình đạt đến điểm ngắt đó tốt. Nhưng bất kỳ điểm ngắt nào tôi đặt trong bản thân định nghĩa phương pháp đều không bao giờ đạt được.

Để đảm bảo rằng tôi đã thực hiện đúng một số bước đầu tiên, tôi đã thử lặp lại chúng với:

  • Một hình thức mới trong cùng một giải pháp.
    Cùng một vấn đề: hình thức không trả lời khi tôi bấm của tôi Ctrl+ Alt+ Ophím tắt và trình gỡ lỗi thậm chí không được bước vào xử lý sự kiện. Đã thử điều này một lần nữa và nó hoạt động.

  • Một giải pháp WinForms hoàn toàn mới.
    Nó hoạt động hoàn hảo: hộp thoại thông báo xuất hiện ( Console.WriteLine()cuộc gọi cũng hoạt động).

Vì vậy tôi khá lạc lõng ở đây. Điều gì ngăn tất cả các biểu mẫu trong một dự án này nhận các sự kiện KeyDown?

Câu trả lời:


173

Biểu mẫu của bạn có thuộc tính KeyPreview được đặt thành true không?

Thuộc tính Form.KeyPreview

Nhận hoặc đặt một giá trị cho biết liệu biểu mẫu có nhận được các sự kiện chính hay không trước khi sự kiện được chuyển đến điều khiển có tiêu điểm.

http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx


19
Đó là một bản hack, được tạo sẵn để giúp các lập trình viên VB6 hài lòng. Nó có vấn đề về thứ tự thực thi, thay vào đó hãy ghi đè ProcessCmdKey ().
Hans Passant

@HansPassant, tôi không thể tìm thấy bất kỳ điều gì giải thích các vấn đề về thứ tự thực hiện. KeyDown + KeyPreview sẽ không thấy tất cả các khóa, điều này đã đủ là một vấn đề, nhưng vấn đề về thứ tự thực thi là gì?
kdbanman

1
Có rất nhiều ghi đè để phát hiện tổ hợp phím tắt. Được thực thi theo thứ tự, KeyPreview + KeyDown đã chết sau cùng.
Hans Passant

54

Lời khuyên phổ biến nhất cho vấn đề này trên StackOverflow và MSDN 1 , 2 (bao gồm cả câu trả lời được chấp nhận ở đây) là nhanh chóng và dễ dàng:

KeyDownsự kiện được kích hoạt Formmiễn là thuộc tính của nó KeyPreviewđược đặt thànhtrue

Điều đó đủ cho hầu hết các mục đích, nhưng nó rủi ro vì hai lý do:

  1. KeyDownngười xử lý không nhìn thấy tất cả các phím . Cụ thể, "bạn không thể thấy loại tổ hợp phím được sử dụng để điều hướng. Như các phím con trỏ và Tab, Escape và Enter cho hộp thoại."

  2. Có một số cách khác nhau để chặn các sự kiện chính và tất cả chúng đều diễn ra theo trình tự. KeyDownđược xử lý cuối cùng . Do đó, KeyPreviewkhông có nhiều bản xem trước và sự kiện có thể bị im lặng ở một vài điểm dừng trên đường.

(Ghi có cho @HansPassant cho những điểm đó.)

Thay vào đó, ghi đè ProcessCmdKeytrong của bạn Form:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
    if (keyData == Keys.Up)
    {
        // Handle key at form level.
        // Do not send event to focused control by returning true.
        return true;
    }
  return base.ProcessCmdKey(ref msg, keyData);
}

Bằng cách đó, tất cả các khóa đều có thể nhìn thấy đối với phương thức và phương thức nằm ở dòng đầu tiên để xem sự kiện.

Lưu ý rằng bạn vẫn có quyền kiểm soát việc điều khiển tập trung có nhìn thấy KeyDownsự kiện hay không . Chỉ cần quay lại trueđể chặn KeyDownsự kiện tiếp theo , thay vì đặt KeyPressEventArgs.Handledthành truenhư bạn làm trong KeyDowntrình xử lý sự kiện. Đây là một bài báo với nhiều chi tiết hơn.


1
Đây là câu trả lời chính xác, đặc biệt nếu bạn thấy PreviewKeyDown hoàn toàn không kích hoạt với KeyPreview được đặt thành true.
Tim

23

Hãy thử đặt thuộc KeyPreviewtính trên biểu mẫu của bạn thành true. Điều này đã làm việc cho tôi để đăng ký các phím bấm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.