Creating a context menu on drag complete in WPF - c#

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

Related

How to get what form control a context menu was over when clicked one of its items

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);
}

Why the ContextMenu right mouse click on ListView items is not working?

At the top of form1:
private ContextMenuStrip contextmenustrip1 = new ContextMenuStrip();
Then:
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
ListView listView = sender as ListView;
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
ListViewItem item = listView.GetItemAt(e.X, e.Y);
if (item != null)
{
item.Selected = true;
contextmenustrip1.Show(listView, e.Location);
}
}
ContextMenu contextMenu = new System.Windows.Forms.ContextMenu();
MenuItem menuItem = new MenuItem("Cut");
menuItem.Click += new EventHandler(CutAction);
contextMenu.MenuItems.Add(menuItem);
menuItem = new MenuItem("Copy");
menuItem.Click += new EventHandler(CopyAction);
contextMenu.MenuItems.Add(menuItem);
menuItem = new MenuItem("Paste");
menuItem.Click += new EventHandler(PasteAction);
contextMenu.MenuItems.Add(menuItem);
}
}
When i make click on item using a break point it's getting to the event but the right mouse click is not working but for sure it's not showing the menus the Cut Copy Paste.
I want to make that when i make right click on item in the listView it will show the menu for the current item. Not sure if i should first make mousedown first or some other event not sure what's more logic. But the idea is to show the menu per right mouse click on item.
You don't need to do anything of the above. Simply, call the Click event of the menu item.
Firstly, set the View Mode of your ListView to Details and then set the ContextMenuStrip Property of the ListView to contextMenuStrip1.
ContextMenuStrip:
The shortcut menu to display when the user right clicks the control.
So, say for Cut menu, call the Click event CutToolStripMenuItem. Similarly, call the events for Copy and Paste as well and add your code.
private void CutToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count != 0)
{
foreach (ListViewItem LItem in listView1.SelectedItems)
{
//Your code
}
}
}
                                           

How to add event on the context menu for chart in c#

I have a chart in WPF and when I right click on the chart it goes to the function Chart_mouseRightButtonDown which is described below.I want to add a context menu.I have already added two options to the context menu.but now I want some action when a user click ont hose options.How to add a handler to it ?
private void Chart_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
var originalSource = e.OriginalSource as DependencyObject;
if (originalSource is Ellipse)
{
ContextMenu contextMenu = new ContextMenu();
contextMenu.Items.Add("Lookup Details in Grid");
contextMenu.Items.Add("Lookup Defect Info");
runTrendChart.ContextMenu = contextMenu;
}
else
runTrendChart.ContextMenu = null;
}
Instead of adding just strings to ContextMenu Items collection you should add a new MenuItem element:
contextMenu.Items.Add(MenuItem()
{
Header = "Lookup Details in Grid",
Command = ANY_COMMAND_YOU_WANT
});
I don't see the reason why you are adding this MenuItems in MouseRightButtonDown handler instead of XAML, but this should solve your problem.
Edit If you don't want to use a Command the MenuItem has a Click event to which you can add an event handler.

WPF DataGrid top left select all header button doesn't focus the grid

My control uses a WPF DataGrid. If you click the empty header in the top left it selects all rows. This is a standard part of DataGrid, not anything I've added.
However, my users are having trouble because this 'button' doesn't focus the DataGrid. How can I fix this?
System.Windows.Controls.DataGrid
Edit: This is the Excel analogue of the DataGrid button I am talking about. It's not a true button, but a header of some kind:
If you look in Snoop you can notice this button.
So you can write event handler to Click event for this button and in this handler you can focus the grid.
private void myGrid_Loaded(object sender, RoutedEventArgs e)
{
DataGrid dg = sender as DataGrid;
Border border = VisualTreeHelper.GetChild(dg, 0) as Border;
ScrollViewer scrollViewer = VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
Grid grid = VisualTreeHelper.GetChild(scrollViewer, 0) as Grid;
Button button = VisualTreeHelper.GetChild(grid, 0) as Button;
if (button != null && button.Command != null && button.Command == DataGrid.SelectAllCommand)
{
button.Click += new RoutedEventHandler(button_Click);
}
}
void button_Click(object sender, RoutedEventArgs e)
{
myGrid.Focus();
}
I used an alternative that doesn't rely on the the visual tree for the control:
In the XAML:
<DataGrid.CommandBindings>
<CommandBinding Command="SelectAll" Executed="MyGrid_SelectAll"/></DataGrid.CommandBindings>
In the code:
private void MyGrid_SelectAll(object sender, ExecutedRoutedEventArgs e)
{
var myGrid = (DataGrid)sender;
myGrid.Focus();
if (myGrid.SelectedCells.Count == myGrid.Columns.Count * myGrid.Items.Count)
{
myGrid.SelectedCells.Clear();
}
else
{
myGrid.SelectAll();
}
e.Handled = true;
}
This also gave me the ability to implement deselect all if all cells are selected.

Getting the control of a context menu

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.

Categories

Resources