I have a context menu that looks like this
A
|--1
|--2
|--3
I need to access the object that the context menu is called from, after selecting 1 2 or 3
meaning if this is a context menu of a textbox1 then I need to access that object, how do I do that?
Forgot to mention, this is a WPF application. so Im using the System.Windows.Controls
and the ContextMenu is created programmatically
You can walk up the tree and get the control from the ContextMenu.PlacementTarget, e.g.
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuItem;
while (item.Parent is MenuItem)
{
item = (MenuItem)item.Parent;
}
var menu = item.Parent as ContextMenu;
if (menu != null)
{
var droidsYouAreLookingFor = menu.PlacementTarget as TextBox;
//...
}
}
You can look at the SourceControl property of the ContextMenuStrip that owns the context menu item that was clicked.
For example, in the Click handler for the menu item:
private void aToolStripMenuItem_Click(object sender, EventArgs e)
{
var control = ((sender as ToolStripMenuItem).Owner as ContextMenuStrip).SourceControl;
...
}
Of course if you only have one ContextMenuStrip on the form, you can just reference it directly
var control = myContextMenuStrip.SourceControl;
Slight tweak to HB's answer. HB deserves the credit. Helped me find a DataGrid.
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
ContextMenu cm = (ContextMenu)item.Parent;
Popup popup = (Popup)cm.Parent;
var finalGoal = popup.PlacementTarget as DataGrid;
}
use the
ContextMenu.SourceControl
that's the variable that calls the context menu. all you need to do is cast the control
found the answer from a similar question
Get owner of context menu in code
viky's code works, but I had to cast it twice.
I guess looping the casting of the Parent is possible for better flexibility
(more casts depends on how deep the clicked item is)
Ugly Solution
I am searching for a better way to do the same thing. For now, the code below works:
TextBlock tb = ((sender as MenuItem).Parent as ContextMenu).PlacementTarget as TextBlock;
Replace TextBlock with your control's type.
Related
I‘ve one ContextMenuStrip attached to two controls (DataGridView).
In the ToolStripMenuItem click event, currently I’ve used:this.ActiveControl.Name to get the active GridView control name;
This is fine if I first select the GridView cell and than Rt. click on it to invoke the ContextMenu
Case: sometime if GridView control is not a active control and cell is pre-selected, than context menu Item click not worked accordingly.
Is there any way to get the owner name that initiate the context menu Item click event?
Currently, In the ToolStripMenuItem click event, I've manage to get the original caller (i.e. DataGridView) with this code:
private void CopytoolStripMenuItem1_Click(object sender, EventArgs e)
{
var grid = new DataGridView();
switch (this.ActiveControl.Name)
{
case "dGVEL1":
{
grid=dGVEL1;
break;
}
case "dGVEL2":
{
grid=dGVEL2;
break;
}
}
if (grid == null) return;
DataObject data = grid.GetClipboardContent();
Clipboard.SetDataObject(data);
}
Finally I've Resolved the issue..
The complete solution is
private void CopytoolStripMenuItem1_Click(object sender, EventArgs e)
{
ToolStripDropDownItem item = sender as ToolStripDropDownItem;
if (item == null) // Error
return;
ContextMenuStrip strip = item.Owner as ContextMenuStrip;
var grid = strip.SourceControl as DataGridView;
if (grid == null) // Control wasn't a DGV
return;
switch (grid.Name)
{
case "dGVEL1":
{
grid=dGVEL1;
break;
}
case "dGVEL2":
{
grid=dGVEL2;
break;
}
}
if (grid == null) return;
DataObject data = grid.GetClipboardContent();
Clipboard.SetDataObject(data);
}
Is there any way to get the owner name that initiate the context menu Item click event?
I worked off of the solution you found and simplified it down. Hopefully, this can help some future readers who are looking for a more general solution.
It looks like you go through quite a bit to get ahold of the ContextMenuStrip which is already being passed as sender (granted you will still need to cast it). The following is a more general solution to this issue and it's a bit more simple.
private void contextMenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e) {
//Cast the parent as a context menu strip so we can access 'sourceControl' attribute
ContextMenuStrip strip = (ContextMenuStrip) sender;
var stripParent = strip.SourceControl;
//print the name of the 'parent' (Control that called the context menu)
System.Diagnostics.Debug.WriteLine("Called From: " + stripParent.Name);
}
There is a ContextMenuStrip in a grid control.
I have named it as GridContextMenu.
The GridContextMenu is populated with 4 - 5 items using the following code :
gridcontextMenu.Items.Add(new ToolStripMenuItem
{
Name = Plants,
Text = Plants,
Tag = Plants,
Width = 100,
Image = <image source is put here>
});
gridcontextMenu.Items.Add(new ToolStripMenuItem
{
Name = Animals,
Text = Animals,
Tag = Animals,
Width = 100,
Image = <image source is put here>
});
For the animal menu in tool strip, i added submenu in the following way
(gridcontextMenu.Items[1] as ToolStripMenuItem).DropDownItems.Add("Tiger", image_source, new EventHandler(SubmenuItem_Click));
(gridcontextMenu.Items[1] as ToolStripMenuItem).DropDownItems.Add("Lion", image_source, new EventHandler(SubmenuItem_Click));
(gridcontextMenu.Items[1] as ToolStripMenuItem).DropDownItems.Add("Elephant", image_source, new EventHandler(SubmenuItem_Click));
In the SubmenuItem_Click event handler i need to know which animal submenu was clicked.
How to achieve this ?
currently i have the code for event handler in the following way :
private void SubmenuItem_Click(object sender, EventArgs e)
{
}
How to check condition in this event that which animal submenu was selected ?
Kindly share the answer.
You can do something like this:
private void SubmenuItem_Click(object sender, EventArgs e)
{
var clickedMenuItem = sender as MenuItem;
var menuText = clickedMenuItem.Text;
switch(menuText) {
case "Tiger":
break;
case "Lion":
break;
. ...
}
}
As I found that none of the other answers worked here, I went digging and found the proper solution. This may have been applicable only in .NET Framework 4+ but here is what I found to work.
Essentially, the ItemClicked event in the ContextMenuStrip control passes itself as the sender and a ToolStripItemClickedEventArgs object when the event is raised. As you can't obtain the clicked item from the ContextMenuStrip itself, the only way to obtain this information is to interrogate the ToolStripItemClickedEventArgs object and the clicked item resides in there as a ToolStripItem object. This can then be used to extract the name of the option to use in an if/switch statement as appropriate. See below:
To configure the EventHandler:
...
contextMenuStrip1.ItemClicked += OnContextMenuItem_Clicked;
...
To handle the event and retrieve the text of the clicked item:
private void OnContextMenuItem_Clicked(object sender, ToolStripMenuItemClickedEventArgs e)
{
ToolStripItem clickedItem = e.ClickedItem;
string itemName = clickedItem.Text;
...
}
Hopefully this helps someone looking for this answer in future :)
You can use Tag for this purpose in case when your should localize your application.
Moreover Tag is an object so you can put any tapy of data there. For example Enum type.
private void SubmenuItem_Click(object sender, EventArgs e)
{
var clickedMenuItem = sender as MenuItem;
EnumType item = (EnumType)clickedMenuItem.Tag;
switch(item) {
case TigeItem:
break;
case LionItem:
break;
...
}
}
This is a way to retrieve the ToolStripMenuItem's index if you have created the ContextMenuStrip Dynamically. It is really helpful with getting Enum values. My Context menu is dynamically created and filled with the Enum Names. I hope it helps someone. Sorry for the formatting still new to posting.
`private void DynamiallyCreatedContextMenu_Click(object sender, EventArgs e)
{
ToolStripMenuItem item = sender as ToolStripMenuItem;
var parent = (item.Owner as ContextMenuStrip);
for (int i = 0; i < parent.Items.Count; i++)
{
if (item == parent.Items[i])
{
index = i;
break;
}
}
}`
private void SubmenuItem_Click(object sender, EventArgs e)
{
string clickedItemName=e.ClickedItem.Text;
}
I have a ContextMenu assigned to two ListViews. How to know which ListView it was used with so I can apply correct method? I guess sender is important here but how do I use it? How to know what sender is at this very moment?
private void contextMenuDokumentyDodaj_Click(object sender, EventArgs e) {
var dokumenty = new DocumentsGui(varKlienciID, varPortfelID);
dokumenty.Show();
dokumenty.FormClosed += varDocumentsGui_FormClosed;
}
ContextMenu.SourceControl
is your ticket.
http://msdn.microsoft.com/en-us/library/system.windows.forms.contextmenu.sourcecontrol.aspx
EDIT
ContextMenuStrip, you say?
http://msdn.microsoft.com/en-us/library/system.windows.forms.contextmenustrip.sourcecontrol.aspx
Did you try the following?
ListView listViewClicked = (ListView) sender;
EDIT (after comments)
The sender is the ToolStripMenuItem, so use a cast to get it, then use GetCurrentParent method to get the ContextMenuStrip containing the item, then use the SourceControl property to get the control displaying your menu, as suggested by #sq33G:
ListView lv = ((ToolStripMenuItem) sender).GetCurrentParent().SourceControl;
Maybe you'll need also to cast the GetCurrentParent return value to a ContextMenuStrip.
I have a tab control in a window. The tabs all have simple context menus which (are supposed to) allow the user to close them. However, when I click close, nothing happens.
Here is the event handler
void closeTab_Click(object sender, RoutedEventArgs e)
{
Tabs.Items.Remove((MenuItem)sender);
}
I've looked around about closing tabs, but none of the articles I found went into much detail about how to actually close the tab.
New problem:
void closeTab_Click(object sender, RoutedEventArgs e)
{
MenuItem close = (MenuItem)sender;
Tabs.Items.Remove(Convert.ToInt32(close.Name.Remove(0,3)));
}
The context menu item is named thusly:
Name = "Tab" + Tabs.Items.Count.ToString(),
It still does nothing
The menu item is not the tab. You cannot remove it from the TabControl. You need a reference to the tab to which the MenuItem belongs. This can be done in various ways.
I see you tried some rather hacky things there with names and string manipulation, here would be a more clean approach which does not require any of that:
var target = (FrameworkElement)sender;
while (target is ContextMenu == false)
target = (FrameworkElement)target.Parent;
var tabItem = (target as ContextMenu).PlacementTarget;
Tabs.Items.Remove(tabItem);
This gets the parent until it finds the ContextMenu and gets the TabItem from the PlacementTarget.
I am working on a node-graph-view similar to Maya's HyperGraph in which I can connect Nodes with drag and drop. Because the target-node can have several Inputs, I want to create a temporary ContextMenu to select the input as suggesting in the following mock-up:
http://www.pixtur.org/images/uploaded/0000/0696/large.jpg
I tried for quite a time to trigger the creation or opening of a context-menu. It looks like the Win32 TrackPopupMenu does roughly, what I'm looking for. Is there an WPF / C# equivalent?
Thanks
pixtur
I would suggest another solution:
In this example a button will raise a context menu with one entry ("Copy") on right click. If the "Copy" context menu item is clicked, a console output is generated.
[..]
var button = new Button();
button.Content = "SomeButtonName";
button.MouseUp += HandleMouseUp;
[..]
private void HandleMouseUp(object sender, MouseButtonEventArgs e)
{
var senderUIControl = sender as Control;
var contextMenu = new ContextMenu();
var item = new MenuItem();
item.Header = "Copy";
item.Click += (o, a) => {
Console.WriteLine("Copy item clicked");
};
contextMenu.Items.Add(item);
senderUIControl.ContextMenu = contextMenu;
}
I use the following code to attach a contextmenu to a listview gricolumn header:
<ListView ... MouseUp="ListView_MouseUp">
In the codebehind i set the ContextMenu property of the list on the mouse up event, in order to show the context menu:
private void ListView_MouseUp(object sender, MouseButtonEventArgs e)
{
DependencyObject depObj = e.OriginalSource as DependencyObject;
while (depObj != null && (!(depObj is GridViewColumnHeader)))
{
depObj = VisualTreeHelper.GetParent(depObj);
}
if (depObj is GridViewColumnHeader && e.ChangedButton == MouseButton.Left)
{
((GridViewColumnHeader)depObj).ContextMenu = ContextMenu;
}
}
The variable ContextMenu refers to a contextmenu instance that i created bfeorehand, you could also create the ContextMenu in the Mouse event handler.
I'm not sure if this helps as I dont know how you do the drag/drop, but it is worth a try