Вопрос

I am creating a Context Menu Strip once a Rich Text Box is right clicked. There are 2 options, one to change the font and one to change the background color. However, once I click one of the menu options, the Context Menu Strip doesn't close and overlays dialogs that are displayed. I know I can make it "global" and force it to close, but I would rather not. What is the best way to handle this?

// If the console is right clicked then show font options
private void rtb_console_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
    {
        ContextMenuStrip menu = new ContextMenuStrip();
        menu.Items.Add("Change Font");
        menu.Items.Add("Change Background Color");
        menu.Show(this, new Point(e.X, e.Y));
        menu.ItemClicked += new ToolStripItemClickedEventHandler(menu_ItemClicked_ChangeFont);
    }
}  

// Determine whether to change the font or the font background color
void menu_ItemClicked_ChangeFont(object sender, ToolStripItemClickedEventArgs e)
{
    Application.DoEvents();  // Read that this might help, but it doesn't
    if (e.ClickedItem.Text == "Change Font")
    {
        FontDialog font = new FontDialog();

        font.ShowColor = true;
        font.Font = rtb_console.Font;
        font.Color = rtb_console.ForeColor;

        if (font.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            rtb_console.Font = font.Font;
            rtb_console.ForeColor = font.Color;
        }
    }
    else if (e.ClickedItem.Text == "Change Background Color")
    {
        ColorDialog color = new ColorDialog();
        color.Color = rtb_console.BackColor;

        if (color.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            rtb_console.BackColor = color.Color;
        }
    }
}  

So this is what happens:
ContextMenuStrip Persisting

Это было полезно?

Решение

You don't want to create the ContextMenuStrip and show it manually each time. The better way to do this is to create the ContextMenuStrip once. Then assign it for the RichTextBox by assigning it to the ContextMenuStrip property of the RichTextBox. Doing this, you will no longer need to manually launch the ContextMenuStrip everytime a user clicks on it. It will occur automagically. It will also hide itself automagically in the way you would expect upon clicking on it.

Do this once and then remove your event handler for the MouseUp event:

ContextMenuStrip menu = new ContextMenuStrip(); 
menu.Items.Add("Change Font"); 
menu.Items.Add("Change Background Color"); 
menu.ItemClicked += new ToolStripItemClickedEventHandler(menu_ItemClicked_ChangeFont);
rtb_console.ContextStripMenu = menu;

Also, please please please don't use Application.DoEvents(); to try and force the UI to update itself. Head over to here and read the top answer. In general, if you are using Application.DoEvents(), you are doing something wrong and should considering changing your approach.

One thing you may also consider doing, but it is really just a matter of preference... If you are using Visual Studio, consider creating you ContextMenuStrip in the designer. That way, you can add your items, icons, and individual callbacks for each item very easily and visually. Just something I like to do out of pure personal preference.

Другие советы

In ToolStripItemClickedEventArgs just declare:

ContextMenuStrip menu = (ContextMenuStrip)(Sender) 

if (e.ClickedItem.Text == "Change Font")
{
    menu.hide();
    /* and your code here*/...
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top