Closing/Removing a tab item WPF - c#

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.

Related

get name of element under mouse cursor on mouse click

I am trying to make a method where i can get the element that was clicked. In App.xaml.cs i have method OnPreviewMouseDown that is activated for each click in application.
Now i need some help with getting element name from sender (if this is even possible)
static void OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
Control control = (Control)sender; // Sender gives you which control is clicked.
string name = control.Name.ToString(); //returns main window name, not element....
string typee = sender.GetType().ToString(); //returns PPPMain.Views.MainWindow
}
}
I tried this and some other suggestions from internet but didn't find any solutions...
Thanks in advance!
Use the OriginalSource property of the MouseButtonEventArgs:
var element = e.OriginalSource as FrameworkElement;
var name = element?.Name;
You could try using this code inside your event:
VisualTreeHelper.HitTest(this, e.GetPosition(this));
you can find more in this other topic: WPF Get Element(s) under mouse

Right click selection in DataGrid

I have a DataGrid created in XAML in a C# project. I've added a context menu to the rows. Basically when the user clicks directly on the cell it should open the relevant item in the current window, which is implemented on the SelectionChanged event.
However if the user right clicks a row it should show the the context menu without selecting the row, so that the user can select an item in the context menu to open the relevant item in a new window. So they can look at both the already selected item and the new item at once, but as the right click selects the row, the user see the newly selected item in the current window and the new window.
How can I stop the right click action to show the context menu from selecting the cell?
For my solution, I have to overwrite the following two event handlers (i.e., PreviewMouseRightButtonDown and PreviewMouseRightButtonUp). Plus, not sure why data-binding for the ItemsSource does not work, so that I have to bind it manually.
private void ResultDataGrid_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (sender is DataGrid dg)
{
if (this.DataContext is PipelineStepResultViewModel dataContext
&& dataContext.DatagridMenuItems != null)
{
dg.ContextMenu.ItemsSource = dataContext.DatagridMenuItems;
}
}
e.Handled = true;
}
private void ResultDataGrid_PreviewMouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (sender is DataGrid dg && dg.ContextMenu.ItemsSource != null)
{
ResultDataGrid.ContextMenu.IsOpen = true;
}
e.Handled = true;
}

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.

Creating a context menu on drag complete in WPF

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

C#: How to detect who is the caller of a context menu's menu item when linked to two different objects?

C#: How to detect who is the caller of a context menu's menu item when linked to two different objects?
I have two labels, lblOn and lblOff. I am linking 'one' contextmenu to both labels to discard having to make two of the same.
How would I go upon finding out which label object called the contextmenu.menuitem? That way the clicked on menuitem knows if it was it it's contextmenu was called by the lblOn label or lblOffline?
Check the SourceControl property of the ContextMenuStrip.
Disregard. After googling a bit more, I found a solution + code example.
private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
{
//Make sure the sender is a ToolStripMenuItem
ToolStripMenuItem myItem = sender as ToolStripMenuItem;
if (myItem != null)
{
//Get the ContextMenuString (owner of the ToolsStripMenuItem)
ContextMenuStrip theStrip = myItem.Owner as ContextMenuStrip;
if (theStrip != null)
{
//The SourceControl is the control that opened the contextmenustrip.
//In my case it could be a linkLabel
LinkLabel linkLabel = theStrip.SourceControl as LinkLabel;
if (linkLabel == null)
MessageBox.Show("Invalid item selected.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
else
{
if (MessageBox.Show(string.Format("Are you sure you want to remove BOL {0} from this Job?", linkLabel.Text), "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
linkLabel.Text = Program.NullValue(linkLabel);
}
}
}
}
}
Source:
http://www.tek-tips.com/viewthread.cfm?qid=1441041&page=8
I know this is a question from many moons ago but I havent really been able to find
a simple answer with code...
I know SLaks kind of pointed it out, but I think others out there need a code sample...
I wanted to know who the called the context menu between either a rich text box or a label.
The reason is I wanted only one context menu and wanted the copy button within it to be
disabled if the caller was the rich text box with nothing selected.
Heres my code:
private void contextMenuStrip1_Opened(object sender, EventArgs e)
{
//get the context menu (it holds the caller)
ContextMenuStrip contextMenu = sender as ContextMenuStrip;
//get the callers name for testing
string controlName = contextMenu.SourceControl.Name;
//test if it is infact me rich text editor making the call.
if (controlName == "text_rchtxt")
{
//if I have nothing selected... I should not be able to copy
if (text_rchtxt.SelectedText == "")
copy_shrtct.Enabled = false;
}
else
{
//if I do have something selected or if its another control making the call, enable copying
copy_shrtct.Enabled = true;
}
}
Use this:
contextMenuStrip1.SourceControl;

Categories

Resources