WinForms ContextMenu stays open when MenuItem is clicked - c#

So I have a form DataGridView and when I right click on the grid I want to display a context menu that has one menu item in it. The menu item will open a second form that will provide some configuration options for the DataGridView.
Now all of this works absolutely fine, the context menu displays correctly and the second form opens correctly and all of the functionality on that form works correctly.
The only issue is that the context menu will only close if I click anywhere other than the menu item. No matter how many times I click on the menu item the context menu does not close.
I have tried looking for work arounds but as far as I can tell there is no way to programatically close the context menu.
Any help would be greatly appreciated. Below are copies of the click events for opening the context menu and for the menu item click event.
private void DataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
DataGridView dgv = (DataGridView)sender;
if (dgv.CurrentCell == null)
{
return;
}
else
{
Rectangle r = dgv.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
Point p = new Point(r.X + e.X, r.Y + e.Y);
ContextMenu cm = new ContextMenu();
cm.MenuItems.Add(new MenuItem("Item", Item_Click));
cm.Show(dgv, p);
}
}
}
private void Item_Click(object sender, EventArgs e)
{
new SecondForm().Show();
}
UPDATE:
I solved the issue by replacing the ContextMenu class with the ContextMenuStrip class, removing the MouseClick event handler and assigning the ContextMenuStrip object to DataGridView.ContextMenuStrip. It appears as though the ContextMenuStrip class deals with showing the menu when it's relevant control is right clicked, so if you add a click event handler to deal with opening the menu it will repeatedly try to render the menu making it flicker several times before it is eventually rendered

in your class add a private variable
private bool CloseMenu = true;
on mouse down of your Context Menu
private void Item_Click(object sender, EventArgs e)
{
CloseMenu = false;
new SecondForm().Show();
}
add context menu closing event
private void contextMenuStripMy_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
e.Cancel = !CloseMenu;
CloseMenu = true;
}

I found some workdaround on this problem after many trials.
Firstly, this is about ContextMenu and not ContextMenuStrip.
This is not perfect solution but it works good if you do not have other alternative solution.
Here is how.
Just Set Visiable = false for all MenuItems under the Context Menu.
Only one problem with this is that it shows small square around the mouse.
I think this small square is the empty context menu box.
However, this small square will be removed quickly if user clicks anywhere and if the context menu lose focus.
It is really small and not bothering.
In code, this will look something like this in case you have only one menu item.
if (cm != null)
{
if (cm.MenuItems.Count > 0) cm.MenuItems[0].Visible = false;
}
If you have multiple of items, then just loop through all menu items.
if (cm != null)
{
for(int i = 0; i < cm.MenuItems.Count ; i++)
cm.MenuItems[i].Visible = false;
}
Hope this helps.
It worked for my case.
So I did not have to swtich to ContextMenuStrip from ContextMenu.

Related

WPF ContextMenu Closed Event, how to differentiate closing method

Inside my Canvas I have a ContextMenu with the expected functionality of closing when you select an option in the menu, or when you click outside of it. However I want my program to respond differently based on which of those methods was used to close the ContextMenu. From what I can tell the Closed Event on the ContextMenu fires in both scenarios. Is there any way to make that distinction?
Could you please explain more about problem?
I think it's obvious that you have to scenario. 1: click on ContexMenu options you created which will invoke an event fore sure and clicking outside it which will cancel the context Menu. by the way I made an answer base on my understanding of you problem. If I got it wrong please tell me.
The bellow code is Just a demo code , The logic Behind it is important.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Windows Load event
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
// Very Important Because by default it's null
this.ContextMenu = new ContextMenu();
// Making 3 sample Menu Item for ContextMenu
MenuItem firstMenuItem = new MenuItem()
{
Header = "FirsMenu"
};
//1st of three way to give event to Controls.
// Giving click Event to firstMenuItem to seprate it's click behavior from Other Menu Items
firstMenuItem.Click += (s, e) =>
{
// if Tag be Null on context Menu closing it's get that non of item selected so the click must be out side or lost focused
this.ContextMenu.Tag = 1;
MessageBox.Show("First Menu Clicked");
};
MenuItem secondMenuItem = new MenuItem()
{
Header = "SecondMenu"
};
//2nd of three way to give event to Controls.
// Giving click Event to secondMenuItem to seprate it's click behavior from Other Menu Items
secondMenuItem.Click += delegate
{
// if Tag be Null on context Menu closing it's get that non of item selected so the click must be out side or lost focused
this.ContextMenu.Tag = 1;
MessageBox.Show("Second Menu Clicked");
};
MenuItem thirdMenuItem = new MenuItem()
{
Header = "ThirdMenu"
};
//3rd of three way to give event to Controls.
// Giving click Event to thirdMenuItem to seprate it's click behavior from Other Menu Items
thirdMenuItem.Click += ThirdMenuOnClick;
this.ContextMenu.Items.Add(firstMenuItem);
this.ContextMenu.Items.Add(secondMenuItem);
this.ContextMenu.Items.Add(thirdMenuItem);
this.ContextMenu.Closed += ContextMenuOnClosed;
}
private void ThirdMenuOnClick(object sender, RoutedEventArgs e)
{
// if Tag be Null on context Menu closing it's get that non of item selected so the click must be out side or lost focused
this.ContextMenu.Tag = 1;
MessageBox.Show("Third Menu Clicked");
}
// Event for opening contextmenu on right mouse button click
private void MainWindow_OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
this.ContextMenu.IsOpen = true;
}
private void ContextMenuOnClosed(object sender, RoutedEventArgs e)
{
// if null means click must be out side or lost focused
if (((ContextMenu)sender).Tag == null)
{
MessageBox.Show("You Clicked OutSide");
}
// very Importnt code , because it will reset the context menu tag logically
((ContextMenu)sender).Tag = null;
}
}
Wish You bests, Heydar.

Is there a way to stop a Menu from closing when you click on it?

We have a form in our program that allows a user to determine what a user can see when setting privileges, by using a menu bar. When a user clicks on an item, that item then is "selected" (gets a tick next to it). However, this also closes the menu.
Is there a way to stop this menu from closing (without affecting any other menu's in the program) when a user clicks on it? So far I have not found anything in the settings, and any _click methods are not affecting it either.
Listen the ToolStripDropDownClosingEventHandler present in ToolStripDropDown. To do this just access the ToolStripMenuItem.DropDown Property, and so, add a listener that will handle the Closing event. We just need to check if the mouse pointer it's inside of toolStrip rectangle and this can be done with this piece of code:
private void ListenToolStripMenuItems(IEnumerable<ToolStripMenuItem> menuItems)
{
// listen all menuItems
foreach (ToolStrip menuItem in menuItems)
menuItem.DropDown.Closing += OnToolStripDropDownClosing;
}
private void OnToolStripDropDownClosing(object sender, ToolStripDropDownClosingEventArgs e)
{
var tsdd = (ToolStripDropDown)sender;
// checking if mouse cursor is inside
Point p = tsdd.PointToClient(Control.MousePosition);
if (tsdd.DisplayRectangle.Contains(p))
e.Cancel = true; // cancel closing
}
This way the AutoClose still working and the toolStrip will close properly.
I'm a hack, but I would do this for each item you can click:
sampleNameToolStripMenuItem.ShowDropDown();
That way whenever you click something, it will also drop the menu down again right after.
I had a similar issue. The Items to be checked was a Level down in my case.
I solved it by adding a MouseEnter and MouseLeave Event to the ToolStripMenuItems that can be checked/unchecked.
In the MouseEnter I set AutoClose of both menuItems to false - in the MouseLeave I set it back to true.
Visualization of the issue I had
private void AddEventToToolStripMenuItems(IEnumerable<ToolStripMenuItem> menuItems)
{
// listen all menuItems
foreach (ToolStripMenuItem menuItem in menuItems)
{
menuItem.MouseEnter += OnToolStripMouseEnter;
menuItem.MouseLeave += OnToolStripMouseLeave;
}
}
private void OnToolStripMouseEnter(object sender, EventArgs e)
{
firstLevelTooStipMenuItem.DropDown.AutoClose = false;
secondLevelTooStipMenuItem.DropDown.AutoClose = false;
}
private void OnToolStripMouseLeave(object sender, EventArgs e)
{
firstLevelTooStipMenuItem.DropDown.AutoClose = true;
secondLevelTooStipMenuItem.DropDown.AutoClose = true;
}
Get the ToolStripMenuItem
Get the DropDown from ToolStripMenuItem
Set AutoClose as false
Ref:
https://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripmenuitem(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripdropdown(v=vs.110).aspx

Do not close ToolStripMenu on clicking in winforms

I work on a c# winform project that the main toolstripmenu have not to be hide after user clicks on its item, how can I do that?
Set the AutoClose property of the parent menu item to prevent the menu strip from closing.
To demonstrate:
ToolStripMenuItem file = new ToolStripMenuItem("File");
file.DropDown.AutoClose = false;
file.DropDownItems.Add("New");
file.DropDownItems.Add("Open");
file.DropDownItems.Add("Exit");
MenuStrip ms = new MenuStrip();
ms.Items.Add(file);
this.Controls.Add(ms);
Now the responsibility is on you to close the menu yourself:
file.DropDown.Close();
I found better answer on MSDN forum. Dropdown doesn't close on click, but closes in other cases:
DropDown.Closing += new ToolStripDropDownClosingEventHandler(DropDown_Closing);
...
private void DropDown_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
{
e.Cancel = true;
}
}

ContextMenuStrip not closing once clicked

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:
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*/...
}

Context menu related problem

suppose my context menu is associated with 3 label control. when i will right click on those label then context menu will appear. i want to capture from the context menu click event that on which label the context menu click event called. i tried but failed.
void MyContextMenu_Click(object sender, EventArgs e)
{
if (sender.GetType() == typeof(Label))
{
if (((Label)sender).Name.ToUpper() == "LBLACCOUNTREFERENCE")
{
Clipboard.Clear();
Clipboard.SetData(DataFormats.OemText, (object)((Label)sender).Text);
}
}
else
{
Clipboard.Clear();
Clipboard.SetData(DataFormats.OemText, (object)this.localJob.JobPart.OEReference);
}
}
please guide me.
The sender parameter specifies the menu item that was clicked.
You're looking for the SourceControl property, which gives you the control that opened the ContextMenuStrip.
Check contextMenu.SourceControl.Text.

Categories

Resources