Windows Forms right-click menu for multiple controls - c#

I have several controls in a Windows Form and I want an identical menu to popup on each when right-clicked. However, the action should vary slightly based on which control was clicked.
The problem I'm having is that the ToolStripMenuItem doesn't have any information about which control was originally clicked to make the tool strip visible. I really don't want to need a separate context menu for each control!
Thus far my code looks something like:
private void InitializeComponent()
{
this.openMenuItem = new ToolStripMenuItem();
this.openMenuItem.Text = "Open";
this.openMenuItem.Click += new EventHandler(this.openMenuItemClick);
this.runMenuItem = new ToolStripMenuItem();
this.runMenuItem.Text = "Run";
this.runMenuItem.Click += new EventHandler(this.runMenuItemClick);
this.contextMenuStrip = new ContextMenuStrip(this.components);
this.contextMenuStrip.Items.AddRange(new ToolStripMenuItem[]{
this.openMenuItem,
this.runMenuItem});
this.option1 = new Label();
this.option1.Click += new EventHandler(this.optionClick);
this.option2 = new Label();
this.option2.Click += new EventHandler(this.optionClick);
}
void optionClick(object sender, EventArgs e)
{
MouseEventArgs mea = e as MouseEventArgs;
Control clicked = sender as Control;
if(mea==null || clicked==null) return;
if(mea.Button == MouseButtons.Right){
this.contextMenuStrip.Show(clicked, mea.Location);
}
}
void openMenuItemClick(object sender, EventArgs e)
{
//Open stuff for option1 or option2, depending on which was right-clicked.
}
void runMenuItemClick(object sender, EventArgs e)
{
//Run stuff for option1 or option2, depending on which was right-clicked.
}

Within runMenuItemClick you need to cast then sender to a ToolStripMenuItem and then cast its owner to a ContextMenuStrip. From there you can look at the ContextMenuStrip's SourceControl property to get the name of the control that clicked the item.
void runMenuItemClick(object sender, EventArgs e) {
var tsItem = ( ToolStripMenuItem ) sender;
var cms = ( ContextMenuStrip ) tsItem.Owner;
Console.WriteLine ( cms.SourceControl.Name );
}

Related

C# Forms Mouse Hover Not firing in controls?

I am trying to write a code on Mouse_Hover for Button
private void Button_MouseHover(object sender, EventArgs e){
Button b = (Button)sender;
toolTip1.Show("Click ME!!", b);
}
But toolTip1 is not showing!!
after this I try to use MouseHover In another controls and it did not work and I try To use
MessageBox , but it did not work even , and I double check Events for Button (and other controls)
in properties tab.
You don't have to wire up controls to use the mouse hover event in order to use a tooltip. MSDN has some useful guidance, the essence of which is "add a tooltip to your form, assign the tooltip to the button"
This is a way to solve your problem:
public partial class Form1 : Form
{
private System.Windows.Forms.ToolTip toolTip1;
public Form1()
{
InitializeComponent();
this.components = new System.ComponentModel.Container();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
Button myBtn = new Button();
this.Controls.Add(myBtn);
myBtn.Location = new Point(10, 10);
myBtn.MouseEnter += new EventHandler(myBtn_MouseEnter);
myBtn.MouseLeave += new EventHandler(myBtn_MouseLeave);
}
void myBtn_MouseEnter(object sender, EventArgs e)
{
Button btn = (sender as Button);
if (btn != null)
{
this.toolTip1.Show("Hello!!!", btn);
}
}
void myBtn_MouseLeave(object sender, EventArgs e)
{
Button btn = (sender as Button);
if (btn != null)
{
this.toolTip1.Hide(btn);
}
}

C# - How to find out which dynamic button was clicked?

I am writing a program where I dynamically add buttons, I do that by storing them in a Dictionary to get a certain value from them later on (the color of the background).
I need to set a Click event on every one of them, but every Click event has to be a little different, as by clicking the button, a ColorDialog pops up and changes the background of the button.
Is there a way to know which button I clicked? In the following code, the button1 click event adds the other buttons and sets the EventHandler for each of them, what should be the code for the EventHandler? Thank you so much in advance guys.
int i = 0;
Dictionary<int, Button> buttonDictionary = new Dictionary<int, Button>();
Dictionary<int, ColorDialog> colorsDictionary = new Dictionary<int ColorDialog>();
public void button1_Click(object sender, EventArgs e)
{
i++;
buttonDictionary.Add(i, new Button());
buttonDictionary[i].Click += new EventHandler(Click);
this.Controls.Add(buttonDictionary[i]);
}
public void Click(object sender, EventArgs e)
{
//Somehow get the int key of the button that was clicked???? (in this case: int j)
int j;
if (!colorsDictionary.ContainsKey(j))
{
colorsDictionary.Add(j, new ColorDialog());
}
if (colorsDictionary[j].ShowDialog() == DialogResult.OK)
{
buttonDictionary[j].BackColor = colorsDictionary[j].Color;
}
}
The code is made just for adding the buttons, I will be glad for any kind of help, thank you guys!
Well, a direct answer to your question is: cast the sender to a Button
Button pressedButton = (Button) sender;
and then check to which button of the dictionary it matches:
foreach (var entry in buttonDictionary)
{
if (entry.Value == pressedButton)
{
j = entry.Key;
break;
}
}
However, that's overly complex for what you want to achieve. It would be much easier if you had a direct relationship between the button and the color picker:
Dictionary<Button, ColorDialog> buttonDictionary = new Dictionary<Button, ColorDialog>();
Then fill it like this:
public void button1_Click(object sender, EventArgs e)
{
i++;
var button = new Button();
this.Controls.Add(button);
button.Click += new EventHandler(Click);
buttonDictionary.Add(button, null);
}
And later access it with
public void Click(object sender, EventArgs e)
{
Button pressedButton = (Button) sender;
ColorDialog dialog = buttonDictionary[pressedButton];
if (dialog == null)
{
dialog = new ColorDialog();
buttonDictionary[pressedButton] = dialog;
}
if (dialog.ShowDialog() == DialogResult.OK)
{
pressedButton.BackColor = dialog.Color;
}
}
Even more, the question is why you would need so many ColorDialgos, since it should be possible with one dialog only. You can get rid of i, j, all dictionaries and most handling as well. IMHO, the following should be sufficient:
public void button1_Click(object sender, EventArgs e)
{
var button = new Button();
Controls.Add(button);
button.Click += Click;
}
public void Click(object sender, EventArgs e)
{
Button pressedButton = (Button) sender;
ColorDialog dialog = new ColorDialog {Color = pressedButton.BackColor};
if (dialog.ShowDialog() == DialogResult.OK)
{
pressedButton.BackColor = dialog.Color;
}
}
Bonus info:
I don't exactly know what you want to achieve. But your buttons will all be in the same place, overlapping each other. To avoid this, drag a flow layout panel onto the form and then add the buttons to the flow layout:
flowLayoutPanel1.Controls.Add(button);
This will ensure that your buttons are nicely arranged.

How to create the event handler for editing dynamic labels in C#?

I have created a dynamic label on button click on Windows Form. And then on a right click on the label. I'm showing a context menu "cm". I obviously want to add functionality to the context menu items. But what I don't understand is how do I reference the "lbl" object inside the event handler? How can I edit the properties of the labels from inside the event handlers named MarkedImportant and EditLabel?
public void btnMonSub_Click(object sender, EventArgs e)
{
string s = txtMonSub.Text;
Label lbl = new Label();
lbl.Text = s;
lbl.Location = new System.Drawing.Point(205 + (100 * CMonSub), 111);
CMonSub++;
lbl.Size = new System.Drawing.Size(100, 25);
lbl.BackColor = System.Drawing.Color.AliceBlue;
this.Controls.Add(lbl);
ContextMenu cm = new ContextMenu();
cm.MenuItems.Add("Mark Important", MarkImportant);
cm.MenuItems.Add("Edit", EditLabel );
lbl.ContextMenu = cm;
}
private void MarkImportant(object sender, EventArgs e)
{
// imp..
}
private void EditLabel(object sender, EventArgs e)
{
// edit..
}
Or is there a better way to do this? Like dynamically adding the event handler itself?
Thanks in advance.
The ContextMenu has a property called SourceControl and MSDN says it
Gets the control that is displaying the shortcut menu.
So your event handler could reach the ContextMenu from the MenuItem passed as the sender parameter in this way
private void MarkImportant(object sender, EventArgs e)
{
// Convert the sender object to a MenuItem
MenuItem mi = sender as MenuItem;
if(mi != null)
{
// Get the parent of the MenuItem (the ContextMenu)
// and read the SourceControl as a label
Label lbl = (mi.Parent as ContextMenu).SourceControl as Label;
if(lbl != null)
{
....
}
}
}

Showing a Context Menu for an item in a ListView

I know how to make a contextMenu that pops up when I right click on a listView, what I want is for it to pop up when I right click on an item. I am trying to make a chat server and client, and now... Now I want to view client info when I right click on a connected client's item.
How can I do this?
private void listView1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var focusedItem = listView1.FocusedItem;
if (focusedItem != null && focusedItem.Bounds.Contains(e.Location))
{
contextMenuStrip1.Show(Cursor.Position);
}
}
}
You can put connected client information in the contextMenuStrip1. and when you right click on a item, you can show the information from that contextMenuStrip1.
You are going to have to use the ListViews Context Menu, but change it according to the ListView Item you right click on.
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
bool match = false;
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
foreach (ListViewItem item in listView1.Items)
{
if (item.Bounds.Contains(new Point(e.X, e.Y)))
{
MenuItem[] mi = new MenuItem[] { new MenuItem("Hello"), new MenuItem("World"), new MenuItem(item.Name) };
listView1.ContextMenu = new ContextMenu(mi);
match = true;
break;
}
}
if (match)
{
listView1.ContextMenu.Show(listView1, new Point(e.X, e.Y));
}
else
{
//Show listViews context menu
}
}
}
You can trigger MouseDown or MouseUp event of ListView in which if MouseButton.Right then grab the selected Item by using ListView.Hittest and give the Context menu related to that Selected Item.
For more clear info you can go through this link
Fully solution
Pops up when user right click on a item in a listView.
Avoid an exception if the list have no items.
If an item was selected, display Delete and Edit options.
Code:
private void Form1_Load(object sender, EventArgs e)
{
listView1.MouseUp += new MouseEventHandler(listView1_MouseClick);
}
private void listView1_MouseClick(object sender, MouseEventArgs e)
{
string id = "xxx";//extra value
if (e.Button == MouseButtons.Right)
{
if (listView1.FocusedItem != null && listView1.FocusedItem.Bounds.Contains(e.Location) == true)
{
ContextMenu m = new ContextMenu();
MenuItem cashMenuItem = new MenuItem("編輯");
cashMenuItem.Click += delegate (object sender2, EventArgs e2) {
ActionClick(sender, e, id);
};// your action here
m.MenuItems.Add(cashMenuItem);
MenuItem cashMenuItem2 = new MenuItem("-");
m.MenuItems.Add(cashMenuItem2);
MenuItem delMenuItem = new MenuItem("刪除");
delMenuItem.Click += delegate (object sender2, EventArgs e2) {
DelectAction(sender, e, id);
};// your action here
m.MenuItems.Add(delMenuItem);
m.Show(listView1, new Point(e.X, e.Y));
}
}
}
private void DelectAction(object sender, MouseEventArgs e, string id)
{
ListView ListViewControl = sender as ListView;
foreach (ListViewItem eachItem in ListViewControl.SelectedItems)
{
// you can use this idea to get the ListView header's name is 'Id' before delete
Console.WriteLine(GetTextByHeaderAndIndex(ListViewControl, "Id", eachItem.Index) );
ListViewControl.Items.Remove(eachItem);
}
}
private void ActionClick(object sender, MouseEventArgs e, string id)
{
//id is extra value when you need or delete it
ListView ListViewControl = sender as ListView;
foreach (ListViewItem tmpLstView in ListViewControl.SelectedItems)
{
Console.WriteLine(tmpLstView.Text);
}
}
public static string GetTextByHeaderAndIndex(ListView listViewControl, string headerName, int index)
{
int headerIndex = -1;
foreach (ColumnHeader header in listViewControl.Columns)
{
if (header.Name == headerName)
{
headerIndex = header.Index;
break;
}
}
if (headerIndex > -1)
{
return listViewControl.Items[index].SubItems[headerIndex].Text;
}
return null;
}
The topic is quite old, but I'll leave my solution for reference.
In xaml ListView definition put your context menu:
<ListView Name="m_list" >
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="menuItem1" Click="ContextMenuItem1Clicked" />
<MenuItem Header="menuItem2" Click="ContextMenuItem2Clicked" />
</ContextMenu>
</ListView.ContextMenu>
...
</ListView>
Now, in the code, define two event handlers that will fire up on clicking respective menu item:
private void ContextMenuItem1Clicked(object sender, RoutedEventArgs e)
{
// handle the event for the selected ListViewItem accessing it by
ListViewItem selected_lvi = this.m_list.SelectedItem as ListViewItem;
}
private void ContextMenuItem2Clicked(object sender, RoutedEventArgs e)
{
// handle the event for the selected ListViewItem accessing it by
ListViewItem selected_lvi = this.m_list.SelectedItem as ListViewItem;
}
ListView can accommodate objects, which means that the selected_lvi can be of type of your object. Just cast is to proper type.
I hope this helps.
Best regards,
Mike
I've found a new solution that doesn't rely on mouse event handlers.
The ContextMenu has a "Popup" event handler.
On popup, I add the relevant menu items I need depending on my context.
Example :
private MenuItem[] standardMenuItems;
private MenuItem[] selectedMenuItems;
public SomePanel() {
InitializeComponent();
// These are list of menu items (name / callback) that will be
// chosen depending on some context
standardMenuItems = new MenuItem[] { new MenuItem("New", OnNew) };
selectedMenuItems = new MenuItem[] { new MenuItem("Delete", OnDelete), new MenuItem("Edit", OnEdit) };
ContextMenu contextMenu = new ContextMenu();
// begin with "standard items"
contextMenu.MenuItems.AddRange(standardMenuItems);
listview.ContextMenu = contextMenu;
// add the popup handler
contextMenu.Popup += OnMenuPopup;
}
// Called right before the menu comes up
private void OnMenuPopup(object sender, EventArgs e) {
ContextMenu menu = sender as ContextMenu;
if (menu == null)
return;
// If an item was selected, display Delete and Edit options
if (listview.SelectedItems.Count > 0) {
menu.MenuItems.Clear();
menu.MenuItems.AddRange(selectedMenuItems);
}
// Else display only the New option
else {
menu.MenuItems.Clear();
menu.MenuItems.AddRange(standardMenuItems);
}
}
I'm not fluent enough in C# and Winforms to be sure there are no drawbacks to this technique, but it's an alternative to relying on mouse events (what if / does the context menu can appear on other keyboard or mouse event ?)
private void contextMenuStripExport_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
if (exportview.SelectedItems.Count <= 0)
{
uploadToolStripMenuItem.Visible = false;
exportToolStripMenuItem.Visible = false;
}
else
{
uploadToolStripMenuItem.Visible = true;
exportToolStripMenuItem.Visible = true;
}
}
Using DevExpress 20.2 Core... Winforms. This is similar to handling a menu item in a GridView.
Private WithEvents _menuViewLabelitem As MenuItem
Private Sub lvShipTracking_MouseClick(sender As Object, e As MouseEventArgs) Handles lvShipTracking.MouseClick
If e.Button = MouseButtons.Right Then
If lvShipTracking.FocusedItem IsNot Nothing AndAlso lvShipTracking.FocusedItem.Bounds.Contains(e.Location) = True Then
Dim m As ContextMenu = New ContextMenu()
_menuViewLabelitem = New MenuItem("View Label")
AddHandler Click, AddressOf Handle_ViewLabel
m.MenuItems.Add(_menuViewLabelitem)
m.Show(lvShipTracking, New Point(e.X, e.Y))
End If
End If
End Sub
Private Sub Handle_ViewLabel(sender As Object, e As EventArgs) Handles _menuViewLabelitem.Click
MsgBox("it worked!")
End Sub

Dynamicly added Controls [e.g Button] : How to add events and Access

At my program i dynamicly add Buttons to my form
{
...
Button bt = new Button();
bt.Text = "bla bla";
bt.MouseClick += new MouseEventHandler(bt_MouseClick);
myPanel.Controls.Add(bt);
...
}
void bt_MouseClick(object sender, MouseEventArgs e)
{
TabPage _tab = new TabPage();
_tab.Text = ??? // I want to get the Button's text ! this.Text returns me the
//main form.Text
}
How can access my dynamic Buttons properties ? How can I understand whick button is
clicked either getting its text.
Thanks.
void bt_MouseClick(object sender, MouseEventArgs e)
{
TabPage _tab = new TabPage();
_tab.Text = ((Button)sender).Text;
}
When an EventHandler delegate is invoked, the sender parameter is the component that raised the event, and the e parameter is a subclass of EventArgs that provides any additional component/event specific information for the event.
Therefore you can establish which button the event fired on by casting the sender parameter to Button:
void bt_MouseClick(object sender, MouseEventArgs e)
{
var button = (Button)sender;
TabPage _tab = new TabPage();
_tab.Text = button.Text;
}

Categories