My WPF ContextMenu is not dismissing when I click elsewhere - c#

I have a WPF ContextMenu instance declared in my XAML like this
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="Do Nothing"/>
<Separator/>
<MenuItem Header="{x:Static p:Resources.MenuExit}" Click="IconMenu_Exit"/>
</ContextMenu>
</Window.ContextMenu>
I'm using the WinForms NotifyIcon to display a tray icon like this
_notifyIcon = new System.Windows.Forms.NotifyIcon();
_notifyIcon.Icon = Properties.Resources.mainicon;
_notifyIcon.Visible = true;
_notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(OnTrayIconMouseClick);
The implementation of the mouse click handler is this
private void OnTrayIconMouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
ContextMenu.IsOpen = true;
}
}
This displays the context menu and clicking on the menu items dismisses it, but if I just click away on another window, the context menu stays visible. This seems like strange default behavior. Is there another way to display the context menu other than IsOpen or do I have to explicitly hide the context menu somehow?
Edit: I don't know if it matters but the window's DataContext is set to this in its code-behind.
Edit2: The context menu dismisses properly if it's invoked by right clicking on the actual main window but not from the tray icon.

Check that you have not defined the StaysOpen property as true.

Related

WPF C# XAML ListBox mouse events (right click vs left click)

I have a ListBox dynamically generated.
In this ListBox there are some Items that the user could select, one or more, by left click.
With the right click on an Item of the ListBox area he could show a context menu.
My problem is that if the user right-clicks in the ListBox area all goes right, but if he right-clicks on an Items he toggles the selection.
I want to avoid the Items toggling by the right click.
This is how I configured the ListBox in the MyWindow.cs:
MyBeautifulList.SelectionMode = SelectionMode.Extended;
And this is a portion of the relative XAML file:
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Send file" Click="SendFileToUser" />
<MenuItem Header="Send folder" Click="SendFolderToUser" />
<MenuItem Header="Copy user ID to the clipboard" Click="copyUserIDtoClipboard" />
</ContextMenu>
</ListBox.ContextMenu>
As well as click, wpf offers a bunch of other options.
Due to bubbling and tunnelling routed events which you might want to read up on.
You can handle the preview version of an event, mark it as handled and then it stops it firing.
void MenuItem_PreviewRightMouseButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
You will then have no context menu appear, so you will need to show the context menu using code.
Name your context menu
<ContextMenu Name="SomeMeaningfulName">
You can then set IsOpen in code in your new handler, like:
SomeMeaningfulName.IsOpen = true;

How to raise a click event when user clicks on a main menu sub item

I have a WPF app with a FILE menu bar with the following menu items:
Open
Recents
Save
Exit
The Recents menu item gets populated with the most recent open directories
Recent:
- ~\Documents
- ~\Pictures
Any pointers / suggestion, what event I should subscribe to when a user clicks on one of the sub items within the Recents menu item?
Many thanks in advance!
The MenuItem class has a Click event.
XAML:
<Menu>
<MenuItem Header="File">
<MenuItem Header="Open"/>
<MenuItem x:Name="recents" Header="Recents">
<MenuItem Header="Documents" Click="MenuItem_Click_1" />
<MenuItem Header="Pictures" />
</MenuItem>
</MenuItem>
</Menu>
Code:
public MainWindow()
{
InitializeComponent();
MenuItem mi = new MenuItem() { Header = "test" };
mi.Click += MenuItem_Click_1;
recents.Items.Add(mi);
}
private void MenuItem_Click_1(object sender, RoutedEventArgs e)
{
MessageBox.Show("clicked!");
}
The looks of it show you want to have a menu with sub menus attached to it. The best way to do this in WPF is with menus with menu items inside of them which can then have buttons or more menu items.
The menus will automatically expand and show the other items inside of it, but if you would like a button click event that all you have to do is subscribe to the event handler, or double click on the button in the designer.

Context Menu location

I have a context menu to show up manually by pressing the hotkey ctrl+menu. Therefore i use this function:
ContextMenu.IsOpen = true;
I call this in my main window. But it has some odd effects.
If I only press the menu-key, the menu alwasy appears in the middle of the screen
If I manually call the menu, it always appears in the top left corner.
my menu is this one:
<Window.ContextMenu>
<ContextMenu Placement="Center">
<MenuItem IsCheckable="False" Name="item2" Click="MenuItem_Click" Header="{DynamicResource countDownNotificationOn}"/>
</ContextMenu>
</Window.ContextMenu>
using the xaml placement above dosen't work either. Therefore I set the window to
ContextMenuService.Placement="Center"
But doesn't work.
You need to set the PlacementTarget property of the ContextMenu:
if (element.ContextMenu != null )
{
element.ContextMenu.PlacementTarget = element;
element.ContextMenu.IsOpen = true;
}
If after this, the ContextMenu is still not placed correctly, you can set the placement using the ContextMenu.HorizontalOffset and ContextMenu.VerticalOffset properties. Take a look at the ContextMenu.HorizontalOffset Property and ContextMenu.VerticalOffset Property pages at MSDN for more information.

StackOverflowException when trying to show a ContextMenu and clicking on its parent

I've encountered a weird behavior in WPF. Even though there are quite a few ways to avoid this problem, I'm trying to better understand why it's happening:
I created a new WPF application, just added a button which has a ContextMenu:
<Grid>
<Button x:Name="btnTest" Margin="10,10,10,10"
MouseEnter="BtnTest_OnMouseEnter" MouseLeave="BtnTest_OnMouseLeave">
<Button.ContextMenu>
<ContextMenu x:Name="myContext">
<TextBlock Text="Context Menu Text"></TextBlock>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
In the code behind I use MouseEnter to show the ContextMenu and MouseLeave to hide it:
private void BtnTest_OnMouseEnter(object sender, MouseEventArgs e)
{
myContext.PlacementTarget = btnTest;
myContext.Placement = PlacementMode.Bottom;
myContext.IsOpen = true;
}
private void BtnTest_OnMouseLeave(object sender, MouseEventArgs e)
{
myContext.IsOpen = false;
}
So now - I see the ContextMenu under the button when the mouse is on the button and it hides when the mouse leaves the button.
BUT when I click the button I get an exception
An unhandled exception of type 'System.StackOverflowException'
occurred in WindowsBase.dll
Question is - Why is the Mouse Click, specifically, triggering this exception? I don't have any code of mine running on the Click event, yet without clicking an exception doesn't occur...
BTW: Same will happen if I replace the Button with an Image for instance, so it doesn't seem to be caused by a specific control...
Change your XAML like this:
<Grid>
<Popup x:Name="myContext">
<TextBlock Text="Context Menu Text"></TextBlock>
</Popup>
<Button x:Name="btnTest" Margin="10,10,10,10"
MouseEnter="BtnTest_OnMouseEnter" MouseLeave="BtnTest_OnMouseLeave">
</Button>
</Grid>
I think there is a loop of this sort going on in your code:
you enter the button, the popup shows
you click, popup hides (default behavior of contextmenu)
button gets focus, popup is shown again
What happens if you set the ´StaysOpen´ property of the ContextMenu? If you then dont get this behavior anymore my suspicion is correct.

ContextMenu shows less than 1 second

I would like to control when the contextmenu of my control to show or not.
here is my code:
void MyControl_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if ( some condition .....)
{
this.Focus();
contextmeun.PlacementTarget = this;
contextmeun.IsOpen = true;
}
}
However, it just show up less than 1 second then disappear immediately. Why is that?
Thank you for all your help!
Probably because you're focussing the control that the context menu belongs to, then showing the context menu, however when the parent control gets focus, the context menu closes.
Try setting the context menu in Xaml instead to get the correct behaviour
<MyControl>
<MyControl.ContextMenu>
<ContextMenu>
<!-- Define context menu here -->
</ContextMenu>
</MyControl.ContextMenu>
</MyControl>
This can be done in pure XAML form, all you need to do is bind your visibility of context menu with a bool property containing your condition like this -
<YourControl>
<YourControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</YourControl.Resources>
<YourControl.ContextMenu>
<ContextMenu Visibility="{Binding IsEnable,
Converter={StaticResource BooleanToVisibilityConverter}}">
<MenuItem Header="MenuItem1"/>
<MenuItem Header="MenuItem2"/>
<MenuItem Header="MenuItem3"/>
</ContextMenu>
</YourControl.ContextMenu>
</YourControl>
Here IsEnable is a plain CLR property, in its getter you can have the logic for your condition depending on which you need to toggle the visibility of your context menu..

Categories