วิธีที่ดีที่สุดในการใช้แป้นพิมพ์ลัดในแอปพลิเคชัน Windows Forms


280

ฉันกำลังมองหาวิธีที่ดีที่สุดในการใช้แป้นพิมพ์ลัดทั่วไปของ Windows (เช่นCtrl+ F, Ctrl+ N) ในแอปพลิเคชันWindows Formsใน C #

แอปพลิเคชันมีรูปแบบหลักซึ่งโฮสต์ฟอร์มลูกหลายรายการ (ทีละรายการ) เมื่อผู้ใช้กดCtrl+ Fฉันต้องการแสดงฟอร์มการค้นหาที่กำหนดเอง แบบฟอร์มการค้นหาจะขึ้นอยู่กับแบบฟอร์มลูกเปิดปัจจุบันในแอปพลิเคชัน

ฉันคิดว่าจะใช้สิ่งนี้ในกิจกรรมChildForm_KeyDown :

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

แต่มันไม่ได้ผล เหตุการณ์ไม่ทำงานแม้แต่ตอนที่คุณกดปุ่ม ทางออกคืออะไร?


มันแปลกจริงๆที่ดูเหมือนว่า Winforms จะไม่มีฟังก์ชั่นการใช้งานเฉพาะสำหรับเรื่องนี้เช่นเดียวกับ Windows API ดั้งเดิม
สจ๊วต

คำตอบ:


460

คุณอาจลืมตั้งค่าคุณสมบัติKeyPreviewของฟอร์มเป็นTrue การแทนที่เมธอดProcessCmdKey ()เป็นโซลูชันทั่วไป:

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

มันใช้งานได้ดี แต่จะตรวจหาให้ฉันถ้าแบบฟอร์มเป็นหน้าต่างที่ใช้งานอยู่ ใครรู้วิธีผูกมันดังนั้นในมุมมองหน้าต่างเป็นไปได้?
Gaʀʀʏ

ในบางสถานการณ์ที่KeyPreviewขาดไม่ได้เลยทีเดียว ตัวอย่างเช่นเมื่อกดทางลัดจะต้องระงับการป้อนข้อมูล แต่อย่างไรก็ตามเพื่อให้MenuStripเหตุการณ์แยกต่างหากเพื่อดำเนินการ ProcessCmdKeyวิธีการจะบังคับให้เกิดการทำซ้ำของตรรกะการยิงเหตุการณ์
ซาอูล

1
อืมไม่ตัวจัดการเหตุการณ์ KeyDown ของฟอร์มค่อนข้างแตกต่างจากตัวจัดการเหตุการณ์ Click ของรายการเมนู คุณยังคงทำเช่นเดียวกันไม่ว่าจะเรียกเมธอดตัวจัดการเหตุการณ์โดยตรง (ไม่จำเป็นต้องเรียกใช้โดยเหตุการณ์) หรือปรับโครงสร้างตรรกะทั่วไปลงในเมธอดแยกต่างหาก
Hans Passant

14
"Ctrl + F คืออะไร" LOL
kchad

73

ในแบบฟอร์มหลักของคุณ

  1. ตั้งค่าKeyPreviewเป็น True
  2. เพิ่มตัวจัดการเหตุการณ์ KeyDown ด้วยรหัสต่อไปนี้

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

4
+ สำหรับตั้งค่า KeyPreview เป็น True .. หายไปนั้น
Usman Younas

20

วิธีที่ดีที่สุดคือใช้ตัวช่วยจำเมนูคือมีรายการเมนูในแบบฟอร์มหลักที่กำหนดแป้นพิมพ์ลัดที่คุณต้องการ จากนั้นทุกอย่างจะได้รับการจัดการภายในและสิ่งที่คุณต้องทำคือการใช้การกระทำที่เหมาะสมที่ได้รับการดำเนินการในClickตัวจัดการเหตุการณ์ของรายการเมนูนั้น


1
ปัญหาคือว่ารูปแบบหลักไม่ได้ใช้เมนูหน้าต่างทั่วไป ใช้แผงการนำทางแบบกำหนดเองที่ใช้เพื่อแสดงฟอร์มลูก แบบฟอร์มการค้นหาถูกเรียกใช้โดยการคลิกที่ ToolStripButton บนแบบฟอร์มย่อย
Rockcoder

menu mnemonicsตัวอย่างจริง
Kiquenet


1
ตัวช่วยจำเป็นแนวคิดที่แตกต่างจากปุ่มลัดและมีความแตกต่างที่สำคัญในการใช้งาน ในระยะสั้นคำย่อเป็นตัวอักษรที่ขีดเส้นใต้ที่ใช้ในการเข้าถึงเมนูคำสั่งเมนูและตัวควบคุมการโต้ตอบโดยใช้แป้นพิมพ์ OTOH, ปุ่มลัดเป็นวิธีการเข้าถึงคำสั่งโดยไม่ผ่านเมนูและยิ่งไปกว่านั้นพวกเขาสามารถกดแป้นโดยพลการเช่น Ctrl + F หรือ F5 ไม่ จำกัด เฉพาะปุ่มตัวอักษร
สจ๊วต

1
@Startart ถูกต้องแล้ว! คำตอบของฉันไม่ได้พยายามที่จะบอกเป็นนัยว่าแป้นพิมพ์ลัดทั้งหมดเป็นตัวช่วยจำเพียงความจำในเมนูนั้นเป็นวิธีที่ง่ายที่สุดในการรับฟังก์ชั่นนี้ น่าเสียดายที่ความคิดเห็นของ Rockcoder มีความชัดเจนโซลูชันนี้อาจดูไม่เหมาะสมที่นี่ ฉันยังคงแนะนำว่ามันเป็นทางออกที่ดีกว่าถ้าเป็นไปได้ สำหรับคำตอบทั่วไปคำตอบที่ฮันส์ยอมรับก็คือหนทางข้างหน้า
Konrad Rudolph

11

คุณสามารถลองตัวอย่างนี้:

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

หากคุณมีเมนูแล้วเปลี่ยนShortcutKeysคุณสมบัติของToolStripMenuItemควรทำเคล็ดลับ

ถ้าไม่คุณสามารถสร้างและตั้งค่าvisibleคุณสมบัติเป็นเท็จ


ไม่ฉันไม่มีเมนู ToolStripButton สำหรับการค้นหาจริง ๆ แล้วอยู่บนตัวควบคุม BindingNavigator ดังนั้นการเพิ่มเมนูอาจไม่ใช่ตัวเลือก
Rockcoder

6

จากแบบฟอร์มหลักคุณต้อง:

  • ให้แน่ใจว่าคุณตั้งKeyPreviewจะเป็นจริง (TRUE ค่าเริ่มต้น)
  • เพิ่มMainForm_KeyDown (.. ) - ซึ่งคุณสามารถตั้งค่าทางลัดใด ๆ ที่คุณต้องการที่นี่

นอกจากนี้ฉันพบสิ่งนี้บน google และฉันต้องการแบ่งปันสิ่งนี้กับผู้ที่ยังค้นหาคำตอบอยู่ (สำหรับทั่วโลก)

ฉันคิดว่าคุณต้องใช้ 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
    }
}

อ่านเพิ่มเติมที่http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/


4

คำตอบของฮันส์นั้นอาจจะง่ายขึ้นสำหรับคนที่เพิ่งรู้จักสิ่งนี้ดังนั้นนี่คือเวอร์ชั่นของฉัน

คุณไม่จำเป็นต้องหลอกกับปล่อยให้มันตั้งค่าให้KeyPreview falseหากต้องการใช้รหัสด้านล่างเพียงวางรหัสใต้form1_loadและใช้F5เพื่อดูว่าใช้ได้หรือไม่:

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
ก่อนอื่นการเอาชนะ ProcessCmdKey เป็นวิธีที่แนะนำในการจัดการการกดแป้นพิมพ์ที่ตั้งใจจะทำการดำเนินการคล้ายกับคำสั่งซึ่งเป็นสิ่งที่ OP กำลังถาม ประการที่สองคุณเข้าใจผิดความคิดเห็นของฮันส์เกี่ยวกับการตั้งค่า KeyPreview เป็นจริง เขาแค่บอก OP ว่าทำไมเทคนิคของเขาถึงไม่ทำงาน การตั้งค่า KeyPreview เป็น true ไม่จำเป็นสำหรับการใช้ ProcessCmdKey
RenniePet

2

ใน WinForm เราสามารถรับสถานะ Control Key ได้เสมอโดย:

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.