ตรวจสอบว่า ContextMenuStrip ใช้กับตัวควบคุมใด


85

ฉันมีสิ่งContextMenuStripที่กำหนดให้กับลิสต์บ็อกซ์ต่างๆ ฉันพยายามคิดว่าเมื่อไหร่ที่ContextMenuStripคลิกสิ่งที่ListBoxมันถูกใช้ ฉันลองใช้รหัสด้านล่างเพื่อเริ่มต้น แต่ใช้งานไม่ได้ senderมีค่าที่ถูกต้อง แต่เมื่อฉันพยายามที่จะกำหนดให้menuSubmittedมันเป็นโมฆะ

private void MenuViewDetails_Click(object sender, EventArgs e)
{
    ContextMenu menuSubmitted = sender as ContextMenu;
    if (menuSubmitted != null)
    {
        Control sourceControl = menuSubmitted.SourceControl;
    }
}

ความช่วยเหลือใด ๆ จะดีมาก ขอบคุณ.

เมื่อใช้ความช่วยเหลือด้านล่างฉันพบว่า:

private void MenuViewDetails_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            if (menuItem != null)
            {
                ContextMenuStrip calendarMenu = menuItem.Owner as ContextMenuStrip;

                if (calendarMenu != null)
                {
                    Control controlSelected = calendarMenu.SourceControl;
                }
            }
        }

ขอบคุณสำหรับวิธีแก้ปัญหาที่ฉันกำลังมองหา ผมมีปัญหาเดียวกัน. แต่ฉันขอแนะนำว่าอย่าซ้อนifคำสั่งเหล่านั้นทั้งหมดและใช้if (menuItem == null) return;ถ้าคุณเป็นเหมือนฉันและไม่ต้องการให้โค้ดของคุณที่จัดการมันซ้อนกันเป็น 2 ระดับที่ไม่จำเป็น
Shawn Kovac

คำตอบ:


126

สำหรับContextMenu:

ปัญหาคือsenderพารามิเตอร์ชี้ไปที่รายการบนเมนูบริบทที่ถูกคลิกไม่ใช่เมนูบริบท

มันเป็นวิธีแก้ไขง่ายๆเพราะแต่ละวิธีจะMenuItemแสดงGetContextMenuวิธีการที่จะบอกคุณContextMenuว่ารายการใดมีรายการเมนูนั้น

เปลี่ยนรหัสของคุณดังต่อไปนี้:

private void MenuViewDetails_Click(object sender, EventArgs e)
{
    // Try to cast the sender to a MenuItem
    MenuItem menuItem = sender as MenuItem;
    if (menuItem != null)
    {
        // Retrieve the ContextMenu that contains this MenuItem
        ContextMenu menu = menuItem.GetContextMenu();

        // Get the control that is displaying this context menu
        Control sourceControl = menu.SourceControl;
    }
}

สำหรับContextMenuStrip:

มันจะเปลี่ยนสิ่งต่าง ๆ เล็กน้อยถ้าคุณใช้ a ContextMenuStripแทนContextMenu. การควบคุมทั้งสองไม่เกี่ยวข้องกันและไม่สามารถส่งอินสแตนซ์ของตัวหนึ่งไปยังอินสแตนซ์ของอีกตัว

เช่นเดิมรายการที่คลิกจะยังคงส่งคืนในsenderพารามิเตอร์ดังนั้นคุณจะต้องพิจารณาContextMenuStripว่าเป็นเจ้าของรายการเมนูแต่ละรายการนี้ คุณทำอย่างนั้นกับคุณสมบัติOwner สุดท้ายคุณจะใช้SourceControlคุณสมบัติเพื่อกำหนดว่าตัวควบคุมใดกำลังแสดงเมนูบริบท

แก้ไขรหัสของคุณดังนี้:

private void MenuViewDetails_Click(object sender, EventArgs e)
{
     // Try to cast the sender to a ToolStripItem
     ToolStripItem menuItem = sender as ToolStripItem;
     if (menuItem != null)
     {
        // Retrieve the ContextMenuStrip that owns this ToolStripItem
        ContextMenuStrip owner = menuItem.Owner as ContextMenuStrip;
        if (owner != null)
        {
           // Get the control that is displaying this context menu
           Control sourceControl = owner.SourceControl;
        }
     }
 }

@bluefeet: แล้วคุณมีอะไรผิดปกติ ฉันเพิ่งทดสอบรหัสนี้กับสามกล่องรายการที่แตกต่างกันและทุกอย่างทำงานได้ตามที่คาดไว้ โพสต์รหัส repro เพิ่มเติม
โคดี้เกรย์

2
@bluefeet: ฉันได้อัปเดตรหัสในคำตอบของฉันแล้ว มีความแตกต่างใหญ่ระหว่างเป็นและContextMenu ContextMenuStrip(อ่าฉันเห็นว่าคุณคิดออกแล้วยิ่งดีที่จะเรียนรู้สิ่งต่างๆด้วยตัวคุณเอง!)
โคดี้เกรย์

1
ฉันใช้เหตุการณ์การเปิดเพื่อบันทึก SourceControl ที่เปิดเมนูไปยังตัวแปรโลคัลจากนั้นอ้างอิงสิ่งนั้นเมื่อจัดการกับการคลิกรายการ
QuickDanger

1
@QuickDanger ใช่SourceControlเป็นโมฆะอย่างน่าเศร้าในขณะที่Clickเหตุการณ์ของToolStripItemรายการย่อยContextMenuStripถูกไล่ออก ดูเหมือนว่าContextMenuStrip's Closedเหตุการณ์ fires ก่อนที่Clickเหตุการณ์ซึ่งอาจจะเป็นสิ่งที่ทำให้เกิดปัญหานั้น ฉันถือว่าคุณสมบัติถูกล้างหลังจากเมนู 'ปิด'
Nyerguds

1
@CodyGray ที่จริงถ้าต้นไม้เป็นลึกคุณต้องห่วงโซ่ของOwnerItemคุณสมบัติจนกว่าคุณจะพบToolStripItemว่ามีContextMenuStripในของOwnerสถานที่ให้บริการ แต่อย่างที่ฉันแสดงความคิดเห็นมันไม่ได้ผล SourceControlในเมนูบริบทจะเป็นโมฆะ คุณบอกว่าคุณทำซ้ำไม่ได้ ... บางทีปัญหาอาจเกิดขึ้นกับเมนูที่ลึกกว่าหนึ่งระดับเท่านั้น? ของฉันลึกลงไปสองระดับ
Nyerguds

4

โพสต์ที่เก่ากว่า แต่ในกรณีที่มีคนอย่างฉันเจอ:

สำหรับ ContextMenuStrip ข้างต้นไม่ได้ผลสำหรับฉัน แต่มันนำไปสู่การค้นหาสิ่งที่ทำ

void DeleteMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
    ContextMenuStrip menu = sender as ContextMenuStrip;
    Control sourceControl = menu.SourceControl;
    MessageBox.Show(sourceControl.Name);
}

สิ่งนี้ทำให้ฉันมีชื่อตัวควบคุมที่คาดหวัง คุณสามารถใส่การตรวจสอบความถูกต้อง ฯลฯ ด้วย if statement ฉันแค่โพสต์เพื่อให้ตรงประเด็น


ใช้ได้เฉพาะกับรายการโดยตรงในไฟล์ContextMenu. ปัญหาคือว่าItemClickedไม่ยิงเมื่อคลิกรายการเมนูย่อย ; พวกเขาต้องการClickกิจกรรมของตัวเองซึ่งจะมีรายการเป็นผู้ส่งไม่ใช่เมนู
Nyerguds

3

ฉันมีปัญหาอย่างมากในการทำให้รหัสนี้ใช้งานได้ นี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุดที่ฉันสามารถหาได้:

สำหรับ ContextMenuStrip:

    Control _sourceControl = null;
    private void contextMenuStrip_Opened(object sender, EventArgs e)
    {
        _sourceControl = contextMenuStrip.SourceControl;
    }

    private void contextMenuItem_Click(object sender, EventArgs e)
    {
        var menuItem = (ToolStripMenuItem)sender;

        _sourceControl.Text = menuItem.Text;
        MessageBox.Show(menuItem.Name);
        MessageBox.Show(sourceControl.Name);
    }

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