Question

I'm tring to implement a button which have a dropdown menu when checked and this menu is gone when unchecked. My problem is I cannot uncheck the checkbox when it or its menu lost focus.

The checkbox's appearance mode is button.

enter image description here

My code:

private void cbSettings_CheckedChanged(object sender, EventArgs e)
{
    if (cbSettings.Checked) {cmsSettings.Show(cbSettings, 0, cbSettings.Height);}
    else {cmsSettings.Hide();}
}

I've tried to uncheck the checkBox on contextMenuStrip's VisibleChanged / Closed event but this caused menu not to hide (or hide and show immediately).

Was it helpful?

Solution

The example below does not, of course, include the code you would need for swapping BackGroundImage of the CheckBox to indicate CheckState. The events to "wire-up" should be obvious. Hope this is helpful.

// tested in VS 2010 Pro, .NET 4.0 FrameWork Client Profile
// uses:
// CheckBox named 'checkBox1
// ContextMenuStrip named 'contextMenuStrip1
// TextBox named 'cMenuSelectionInfo for run-time checking of results

    // used to position the ContextMenuStrip    
    private Point cPoint;

    // context click ? dubious assumption that 'right' = context click
    private bool cmOpenedRight;

    // the clicked ToolStripMenuItem
    private ToolStripMenuItem tsMIClicked;

    private void checkBox1_MouseDown(object sender, MouseEventArgs e)
    {
        cmOpenedRight = e.Button == MouseButtons.Right;
    }

    private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        // positioning the CheckBox like this
        // is something in a 'real-world' example
        // you'd want to do in the Form.Load event !
        // unless, of course, you'd made the CheckBox movable
        if(checkBox1.Checked)
        {
            contextMenuStrip1.Show();
            cPoint = PointToScreen(new Point(checkBox1.Left, checkBox1.Top + checkBox1.Height));
            contextMenuStrip1.Location = cPoint;
        }
        else
        {
            contextMenuStrip1.Hide();
        }
    }

    private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
    {
        // assume you do not have to check for null here ?
        tsMIClicked = e.ClickedItem as ToolStripMenuItem;

        tbCbMenuSelectionInfo.Text = tsMIClicked + " : " + ! (tsMIClicked.Checked);
    }

    private void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
    {
        e.Cancel = checkBox1.Checked;
    }

    private void contextMenuStrip1_Closed(object sender, ToolStripDropDownClosedEventArgs e)
    {
        if (cmOpenedRight)
        {
            tbCbMenuSelectionInfo.Text += " : closed because : " + e.CloseReason.ToString();
        }
    }

OTHER TIPS

I think your approach of unchecking the check box on the context menu's closed event is a good one, what you need is a bit of "event cancelling logic"(c), like this:

private void OnContextClosing(object sender, EventArgs e)
{
    _cancel = true;
    cbSettings.Checked = false;
    _cancel = false;
}

private void cbSettings_CheckedChanged(object sender, EventArgs e)
{
    if(_cancel)
       return;

    if (cbSettings.Checked) {cmsSettings.Show(cbSettings, 0, cbSettings.Height);}
    else {cmsSettings.Hide();}
}

This will keep your CheckChanged event from re-checking your checkbox.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top