Cách tốt nhất để thực hiện các phím tắt trong ứng dụng Windows Forms?


280

Tôi đang tìm kiếm một cách tốt nhất để triển khai các phím tắt Windows phổ biến (ví dụ Ctrl+ F, Ctrl+ N) trong ứng dụng Windows Forms của tôi trong C #.

Ứng dụng này có một biểu mẫu chính lưu trữ nhiều biểu mẫu con (mỗi lần một biểu mẫu). Khi người dùng nhấn Ctrl+ F, tôi muốn hiển thị một hình thức tìm kiếm tùy chỉnh. Mẫu tìm kiếm sẽ phụ thuộc vào mẫu con mở hiện tại trong ứng dụng.

Tôi đã nghĩ đến việc sử dụng một cái gì đó như thế này trong sự kiện ChildForm_KeyDown :

   if (e.KeyCode == Keys.F && Control.ModifierKeys == Keys.Control)
        // Show search form

Nhưng điều này không làm việc. Sự kiện thậm chí không kích hoạt khi bạn nhấn một phím. Giải pháp là gì?


Thật kỳ lạ khi Winforms dường như không có chức năng cụ thể cho việc này giống như API Windows gốc.
Stewart

Câu trả lời:


460

Có lẽ bạn đã quên đặt thuộc tính KeyPreview của biểu mẫu thành True. Ghi đè phương thức ProcessCmdKey () là giải pháp chung:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    MessageBox.Show("What the Ctrl+F?");
    return true;
  }
  return base.ProcessCmdKey(ref msg, keyData);
}

Điều này hoạt động tốt, nhưng chỉ phát hiện nó cho tôi nếu biểu mẫu là cửa sổ hoạt động. Bất cứ ai cũng biết làm thế nào để liên kết nó để trong bất kỳ cửa sổ xem nó là có thể?
Gaʀʀʏ

Trong một số tình huống KeyPreviewlà khá cần thiết. Ví dụ: khi nhấn một phím tắt là bắt buộc để chặn đầu vào nhưng tuy nhiên để cho phép một MenuStripsự kiện riêng biệt phát sinh. ProcessCmdKeycách tiếp cận sẽ buộc sự trùng lặp của logic bắn sự kiện.
Saul

1
Hmm, không, trình xử lý sự kiện KeyDown của Form khá khác biệt với trình xử lý sự kiện Click của một mục menu. Bạn vẫn thực hiện chính xác theo cách tương tự, gọi trực tiếp phương thức xử lý sự kiện (không cần gọi riêng cho sự kiện) hoặc cấu trúc lại logic chung thành một phương thức riêng.
Hans Passant

14
"Ctrl + F là gì?" LOL
kchad

73

Trên mẫu chính của bạn

  1. Đặt KeyPreviewthành Đúng
  2. Thêm trình xử lý sự kiện KeyDown với mã sau

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }

4
+ cho, Đặt KeyPreview thành True .. đã bỏ lỡ điều đó
Usman Younas

20

Cách tốt nhất là sử dụng tính năng ghi nhớ menu, tức là có các mục menu ở dạng chính của bạn được gán phím tắt bạn muốn. Sau đó, mọi thứ khác được xử lý nội bộ và tất cả những gì bạn phải làm là thực hiện hành động thích hợp được thực thi trong Clicktrình xử lý sự kiện của mục trình đơn đó.


1
Vấn đề là hình thức chính không sử dụng các menu windows phổ biến. Nó sử dụng bảng điều hướng tùy chỉnh được sử dụng để hiển thị các biểu mẫu con. Các hình thức tìm kiếm được gọi bằng cách nhấp vào ToolStripButton trên biểu mẫu con.
Rockcoder

menu mnemonicsmẫu thật?
Kiquenet

1
@Kiquenet docs.microsoft.com/en-us/dotnet/api/ Kẻ
Konrad Rudolph

1
Mnemonics là một khái niệm khác biệt với các phím tắt và có những khác biệt quan trọng trong cách chúng hoạt động. Nói tóm lại, mnemonics là các ký tự được gạch chân được sử dụng để truy cập các menu, lệnh menu và điều khiển hộp thoại bằng bàn phím. OTOH, các phím tắt là một cách để truy cập các lệnh mà không cần thông qua các menu và hơn nữa chúng có thể là các phím bấm tùy ý như Ctrl + F hoặc F5, không bị hạn chế đối với các phím ký tự.
Stewart

1
@Stewart Đúng vậy! Câu trả lời của tôi đã không cố gắng ám chỉ rằng tất cả các phím tắt trên bàn phím là ghi nhớ, chỉ đơn thuần là việc ghi nhớ trình đơn là cách dễ nhất để có được chức năng này. Thật không may, như nhận xét của Rockcoder, giải pháp này có vẻ không phù hợp ở đây. Tôi vẫn đề nghị nó như là giải pháp thích hợp hơn, nếu có thể. Đối với một giải pháp chung, câu trả lời được chấp nhận của Hans là con đường phía trước.
Konrad Rudolph

11

Bạn thậm chí có thể thử ví dụ này:

public class MDIParent : System.Windows.Forms.Form
{
    public bool NextTab()
    {
         // some code
    }

    public bool PreviousTab()
    {
         // some code
    }

    protected override bool ProcessCmdKey(ref Message message, Keys keys)
    {
        switch (keys)
        {
            case Keys.Control | Keys.Tab:
              {
                NextTab();
                return true;
              }
            case Keys.Control | Keys.Shift | Keys.Tab:
              {
                PreviousTab();
                return true;
              }
        }
        return base.ProcessCmdKey(ref message, keys);
    }
}

public class mySecondForm : System.Windows.Forms.Form
{
    // some code...
}

8

Nếu bạn có một menu sau đó thay đổi ShortcutKeysthuộc tính ToolStripMenuItemnên làm thủ thuật.

Nếu không, bạn có thể tạo một cái và đặt thuộc tính của nó visiblethành false.


Không, tôi không có thực đơn. ToolStripButton cho tìm kiếm thực sự nằm trên điều khiển BindingNavigator, vì vậy việc thêm một menu có lẽ không phải là một tùy chọn.
Rockcoder

6

Từ Mẫu chính, bạn phải:

  • Hãy chắc chắn rằng bạn đặt KeyPreview thành true (TRUE theo mặc định)
  • Thêm MainForm_KeyDown (..) - theo đó bạn có thể đặt ở đây bất kỳ phím tắt nào bạn muốn.

Ngoài ra, tôi đã tìm thấy điều này trên google và tôi muốn chia sẻ điều này với những người vẫn đang tìm kiếm câu trả lời. (cho toàn cầu)

Tôi nghĩ bạn phải sử dụng user32.dll

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (m.Msg == 0x0312)
    {
        /* Note that the three lines below are not needed if you only want to register one hotkey.
         * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */

        Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);                  // The key of the hotkey that was pressed.
        KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);       // The modifier of the hotkey that was pressed.
        int id = m.WParam.ToInt32();                                        // The id of the hotkey that was pressed.


        MessageBox.Show("Hotkey has been pressed!");
        // do something
    }
}

Đọc thêm http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/


4

Câu trả lời của Hans có thể được thực hiện dễ dàng hơn một chút đối với người mới biết điều này, vì vậy đây là phiên bản của tôi.

Bạn không cần phải đánh lừa KeyPreview, hãy đặt nó thành false. Để sử dụng mã bên dưới, chỉ cần dán mã bên dưới của bạn form1_loadvà chạy với F5để xem nó hoạt động:

protected override void OnKeyPress(KeyPressEventArgs ex)
{
    string xo = ex.KeyChar.ToString();

    if (xo == "q") //You pressed "q" key on the keyboard
    {
        Form2 f2 = new Form2();
        f2.Show();
    }
}

7
Đầu tiên, ghi đè ProcessCmdKey là cách xử lý được khuyến nghị sử dụng tổ hợp phím nhằm thực hiện một số thao tác giống như lệnh, đó là những gì OP đã hỏi về. Thứ hai, bạn đã hiểu nhầm nhận xét của Hans về việc đặt KeyPreview thành đúng; anh ta chỉ nói với OP tại sao kỹ thuật của anh ta không hoạt động. Không cần thiết lập KeyPreview thành true khi sử dụng ProcessCmdKey.
RenniePet

2

Trong WinForm, chúng ta luôn có thể nhận trạng thái Khóa điều khiển bằng cách:

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
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.