Handling shortcuts from context menu - c#

I have a Windows Form shown as a model dialog. It has a context menu of class ContextMenuStrip. I set shortcuts to several items in the context menu. But this shortcuts works only when context menu is shown. How to make them work even if the context menu is not activated?
The only way I know is to handle KeyPress event of the form, iterate recursively through all the items in the context menu and compare its ShortcutKeys property with the actual key pressed. If the match, manually call OnClick event for this item. Any better ideas?

Use the ToolStripMenuItem.ShortCutKeys property, so that you no need to iterate and call the event handlers.
Sample Code:
ContextMenuStrip _contextMenuStrip = new ContextMenuStrip();
var menuItem = new ToolStripMenuItem("Copy");
menuItem.ShortcutKeys = Keys.Control | Keys.C;
_contextMenuStrip.Items.Add(menuItem);

Are you opening the ContextMenuStrip in code or is the ContextMenuStrip property of the Form set to the ContextMenuStrip you created? If it's being opened in code, are you able to set the Form property instead? That should let you do the shortcut without having to open the menu first.

Finally, I've implemented manual iteration in the KeyPressed event handler:
Action<ToolStripMenuItem> check_shortcut = null;
check_shortcut = (node) =>
{
if (node.ShortcutKeys == e.KeyData)
{
node.PerformClick();
}
foreach (ToolStripMenuItem child in node.DropDownItems)
{
check_shortcut(child);
}
};
foreach (ToolStripMenuItem item in MyContextMenuStrip.Items)
{
check_shortcut(item);
}

Related

gtksharp TextView.PopulatePopup works to add handlers to existing menu items, but doesn't work to add new menu items

I am trying to add items to the context menu of a TextView in GtkSharp (version 3.22.25.128). The context menu normally has the entries Cut/Copy/Paste/Delete/Separator/Select All/Insert Emoji. I am trying to add several more entries to the menu, starting with a separator.
To do this I am adding a handler to the PopulateMenu event, like so:
_textBox.PopulatePopup += (object source, PopulatePopupArgs args) => {
if (args.Popup is Menu menu)
{
(menu.Children[0] as MenuItem).Activated +=
(object src, EventArgs a) => {
Setting.SetRaw("This happened");
};
foreach (var item in GetPopupMenuItems())
{
menu.Add(item);
}
}
};
An abbreviated version of GetPopupMenuItems() is:
IEnumerable<MenuItem> GetPopupMenuItems()
{
yield return new SeparatorMenuItem();
var importMenuItem = new MenuItem("Import single value from text file");
importMenuItem.Activated += (object source, EventArgs args) => FileOperation(source as Window, true, false);
yield return importMenuItem;
}
The PopulatePopup handler is definitely being called; I can step through it in the debugger and see that at the end the Popup menu includes the items I'm trying to add. It's also certain that the handler and is having some effect, because the test handler I added to the first menu item is called when I select the Cut option in the right click menu. But although the behavior I add to an existing menu item is working, the new menu items I am adding are never shown.
Is there an additional step I have to do to get the items I am adding to the Menu's collection to show in the menu? I've implemented nested menus in the menubar for the same app, and I've never had to do anything but add items to the parent's collection.
If it makes a difference, I'm using Gtk# to make a cross-platform Windows/Linux app, and I'm observing this behavior on both platforms.
In PopulatePopup, you must set the Visible flag of items you are adding to "true" to get them to appear as expected.
This handler works as expected:
_textBox.PopulatePopup += (object source, PopulatePopupArgs args) => {
if (args.Popup is Menu menu)
{
foreach (var item in GetPopupMenuItems())
{
item.Visible = true;
menu.Add(item);
}
}
};

How to delete button border after clicking outside of Form C#?

I made a simple button, but when i click outside of win form my button getting a black border. By the way i set BorderSize to "0" and it works great while i clicking inside of my form.
this.button.FlatAppearance.BorderSize = 0;
That's how it looks like.
it seems a focus problem. Try to reset the focus when the cursor leave the control.
Add these lines of code to your forms load event.
btn.FlatStyle = FlatStyle.Flat;//You can also use the popup flat style
btn.FlatAppearance.BorderColor = btn.Parent.BackColor;
btn.FlatAppearance.BorderSize = 0;
One simple workaround is to set the FlatAppearance.BorderColor of the Button to its Parent.BackColor:
this.button1.FlatAppearance.BorderColor = this.button1.Parent.BackColor;
You could set this Property subscribing to the ParentChanged event (or overriding OnParentChanged, if it's a Custom Control) if the Control can be assigned to another parent at some point.
You can also perform the same operation in batch, using the HandleCreated event and have all the Buttons (with FlatStyle = FlatStyle.Flat) subscribe to the event in the Form's constructor:
public Form1()
{
InitializeComponent();
foreach (Button button in this.Controls.OfType<Button>().Where(btn => btn.FlatStyle == FlatStyle.Flat))
{
button.HandleCreated += (s, e) => {
button.FlatAppearance.BorderColor = button.Parent.BackColor;
};
}
}

Detecting changes to MDI child

Is there a way to detect changes to MDI child when one of the child is closed?
I'm trying to create a dynamic dropdown menu item in the toolstrip menu item that can be add or remove programatically from the MDI child.
Because of the instance is dispose when the child is close,i couldn't cross check with the toolstrip menu item.The adding part is successful but the removing part is a problem.
ToolStripMenuItem temp = new ToolStripMenuItem();
if(form.Visible == true)
{
this.SuspendLayout();
temp.Name = form.Text;
temp.Size = new System.Drawing.Size(112, 22);
temp.Text = form.Text;
this.windowsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { temp });
this.ResumeLayout();
}
You should use FormClosing event. It executes before disposing the instance of the form. FormClosed event fires after disposing of the form's instance.

Right click menu and menu line

Goal:
Right clicking in the listview and choose different option.
Problem:
There are two problem:
*When I'm right clicking, the left corner of the menu is not exactly located in the arrow's spot location.
*How do I create a line in the menu?
The main problem about the menu
Need support to create these two redmark.
private void lstV_Stock_MouseUp(object sender, MouseEventArgs e)
{
switch (e.Button)
{
// Right mouse click
case MouseButtons.Right:
ContextMenu myContextMenu = new ContextMenu();
MenuItem menuItem1 = new MenuItem("New product");
MenuItem menuItem2 = new MenuItem("Delete");
MenuItem menuItem3 = new MenuItem("Add quantity");
// Clear all previously added MenuItems.
myContextMenu.MenuItems.Clear();
myContextMenu.MenuItems.Add(menuItem1);
myContextMenu.MenuItems.Add(menuItem2);
myContextMenu.MenuItems.Add(menuItem3);
if (lstV_Stock.SelectedItems.Count > 0)
{
foreach (ListViewItem item in lstV_Stock.SelectedItems)
{
myContextMenu.MenuItems[1].Visible = true;
myContextMenu.MenuItems[2].Visible = true;
myContextMenu.MenuItems[0].Visible = false;
}
}
else
{
myContextMenu.MenuItems[1].Visible = false;
myContextMenu.MenuItems[2].Visible = false;
myContextMenu.MenuItems[0].Visible = true;
}
myContextMenu.Show(lstV_Stock, this.PointToClient(Cursor.Position), LeftRightAlignment.Right);
menuItem1.Click += new System.EventHandler(this.menuItem1_Click);
break;
}
For the positioning, you can replace your
myContextMenu.Show(lstV_Stock, this.PointToClient(Cursor.Position), LeftRightAlignment.Right);
to
myContextMenu.Show(lstV_Stock, e.Location(), LeftRightAlignment.Right);
or the point e.X,e.Y. Not from this.PointToClient, but from the MouseEventArgs generating the event. You can check wahat MouseEvent have here.
To create a "line" you have to create a MenuItem with text "-"
Problem
If you just set the ListView.ContextMenu property and remove all your own right-click code, the menu should show up correctly.
For the line you need a ToolStripSeparator item. The designer will create one when you type '-' as the Text. You can drag them in the designer.
So, using a ContextMenu is the way to go here. Those "Lines" you're referring to are called Separaters.
If you're creating the COntext Menu in Design View, then click the Context Menu, then right-click inside the menu, and click Insert > Separater.
You can then drag it up or down, or into a sub-menu if you wish.

Tooltips for CheckedListBox items?

Is there a straighforward way to set additional text to appear in a tooltip when a user's mouse is held over an item in a CheckedListBox?
What I would expect to be able to do in code is:
uiChkLstTables.DisplayOnHoverMember = "DisplayOnHoverProperty"; //Property contains extended details
Can anyone point me in the right direction to do this? I've already found a couple of articles that involve detecting which item the mouse is currently over and creating a new tooltip instance, but this sounds a little too contrived to be the best way.
Thanks in advance.
Add a Tooltip object to your form and then add an event handler for the CheckedListBox.MouseHover that calls a method ShowToolTip();
Add MouseMove event of your CheckedListBox which has the following code:
//Make ttIndex a global integer variable to store index of item currently showing tooltip.
//Check if current location is different from item having tooltip, if so call method
if (ttIndex != checkedListBox1.IndexFromPoint(e.Location))
ShowToolTip();
Then create the ShowToolTip method:
private void ShowToolTip()
{
ttIndex = checkedListBox1.IndexFromPoint(checkedListBox1.PointToClient(MousePosition));
if (ttIndex > -1)
{
Point p = PointToClient(MousePosition);
toolTip1.ToolTipTitle = "Tooltip Title";
toolTip1.SetToolTip(checkedListBox1, checkedListBox1.Items[ttIndex].ToString());
}
}
Alternately, you could use a ListView with checkboxes instead. This control has
builtin support for tooltips.
Contrived or not; that's what there is...
I'm not aware of an easier way than you have already described (although I'd probably re-use a tooltip instance, rather than creating new all the time). If you have articles that show this, then use them - or use a 3rd party control that supports this natively (none leap to mind).
I would like to expand upon Fermin's answer in order to perhaps make his wonderful solution slightly more clear.
In the form that you're working in (likely in the .Designer.cs file), you need to add a MouseMove event handler to your CheckedListBox (Fermin originally suggested a MouseHover event handler, but this did not work for me).
this.checkedListBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.showCheckBoxToolTip);
Next, add two class attributes to your form, a ToolTip object and an integer to keep track of the last checkbox whose tool tip was shown
private ToolTip toolTip1;
private int toolTipIndex;
Finally, you need to implement the showCheckBoxToolTip() method. This method is very similar to Fermin's answer, except that I combined the event callback method with the ShowToolTip() method. Also, notice that one of the method parameters is a MouseEventArgs. This is because the MouseMove attribute requires a MouseEventHandler, which then supplies MouseEventArgs.
private void showCheckBoxToolTip(object sender, MouseEventArgs e)
{
if (toolTipIndex != this.checkedListBox.IndexFromPoint(e.Location))
{
toolTipIndex = checkedListBox.IndexFromPoint(checkedListBox.PointToClient(MousePosition));
if (toolTipIndex > -1)
{
toolTip1.SetToolTip(checkedListBox, checkedListBox.Items[toolTipIndex].ToString());
}
}
}
Run through your ListItems in your checkbox list of items and set the appropriate text as the item 'title' attribute, and it will display on hover...
foreach (ListItem item in checkBoxList.Items)
{
//Find your item here...maybe a switch statement or
//a bunch of if()'s
if(item.Value.ToString() == "item 1")
{
item.Attributes["title"] = "This tooltip will display when I hover over item 1 now, thats it!!!";
}
if(item.Value.ToString() == "item 2")
{
item.Attributes["title"] = "This tooltip will display when I hover over item 2 now, thats it!!!";
}
}

Categories