Button inside a MenuItem won't open Sub-MenuItems - wpf

I have a Button inside a MenuItem.Header like this:
<Menu>
<MenuItem>
<MenuItem.Header>
<Button>Hello</Button>
</MenuItem.Header>
<MenuItem Header="SubItem1"/>
<MenuItem Header="SubItem2"/>
</MenuItem>
</Menu>
if I click the MenuItem outside the Button, the sub-menu opens. But if I click the Button the sub-menu will not open. I believe that's because the event of the clicked is not passed to the MenuItem. How do I fix it?
In short - I want the sub-menu to open when clicking the Button.
(The use is mainly for styling purposes, I have a button style and I want to use it as a MenuItem)

A Button doesn't know how to expand a MenuItem unless you tell it how to by writing some code:
<Menu>
<MenuItem>
<MenuItem.Header>
<Button Click="Button_Click">Hello</Button>
</MenuItem.Header>
<MenuItem Header="SubItem1"/>
<MenuItem Header="SubItem2"/>
</MenuItem>
</Menu>
private void Button_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
MenuItem mi = btn.Parent as MenuItem;
if (mi != null)
mi.IsSubmenuOpen = !mi.IsSubmenuOpen;
}

Related

How to get menu item below the icon in reactjs?

I have given Menu Items for an Icon but i couldn't able to see Icon while i click on the icon. It is getting hide due to Menu item. My Objective is to show icon even when we click on the icon(Drop down is shown) as shown in this link https://codesandbox.io/s/3rmgv. In the above link, we can we see a button, when we click on button, we could see the menu items as well as the button too. Can anyone help me in getting the in this way?
Here is the code:
<div>
<IconButton
aria-label="more"
aria-controls="simple-menu"
aria-haspopup="true"
onClick={this.handleClick}
>
<AccountBalanceIcon />
</IconButton>
<Menu
id="simple-menu"
anchorEl={this.state.anchorEl}
keepMounted
open={Boolean(this.state.anchorEl)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>My account</MenuItem>
<MenuItem onClick={this.handleClose}>Logout</MenuItem>
</Menu>
</div>
Here is the sample code

MenuItem click only works when child item is clicked

I have a larger PowerShell Script that is importing XAML code into it. Here's part of the code:
XAML
<Menu x:Name="menu" DockPanel.Dock="Top">
<MenuItem x:Name="menuFile" Header="File">
<MenuItem x:Name="menuFile_History" Header="_History"/>
<MenuItem x:Name="menuFile_Recent" Header="_Recent">
<MenuItem x:Name="menuFile_Recent1"/>
<MenuItem x:Name="menuFile_Recent2"/>
<MenuItem x:Name="menuFile_Recent3"/>
<MenuItem x:Name="menuFile_Recent4"/>
<MenuItem x:Name="menuFile_Recent5"/>
</MenuItem>
<MenuItem x:Name="menuFile_ShowMore" Header="_Show More"/>
<MenuItem x:Name="menuFile_FlushDNS" Header="_Flush DNS"/>
<MenuItem x:Name="menuFile_KillProcess" Header="Kill Process"/>
<Separator/>
<MenuItem x:Name="menuFile_Close" Header="_Close"/>
</MenuItem>
<MenuItem x:Name="menuEdit" Header="Edit">
<MenuItem x:Name="menuEdit_ConvertIP" Header="Convert IP" IsCheckable="True" IsChecked="True"/>
</MenuItem>
<MenuItem x:Name="menuHelp" Header="Help">
<MenuItem x:Name="menuHelp_About" Header="About"/>
</MenuItem>
</Menu>
PowerShell
$menuFile.Add_Click({
$txtInput.Text = "It worked!"
})
The problem is that the above PowerShell code is only ran when one of the child items is clicked, not when $menuFile is clicked. I have looked and looked and I cannot figure out why this is happening and how to fix it.
Thank you very much.
You're looking for a different event handler than Click. You want GotFocus or something like that.Try this instead
$menuFile.Add_GotFocus({$txtInput.Text = "It worked!"})
You can check out all of the events you can add event handlers to by piping to Get-Member as such:
$menuFile | Get-Member -MemberType Methods -force |?{$_.Name -like 'add*'}
Then just look for the methodsJust for kicks I tried this, and it worked as expected:
$menuFile.Add_GotFocus({$menuFile.FontSize = 16})
$menuFile.Add_LostFocus({$menuFile.FontSize = 12})
Then when I clicked on the File menu the font size for it and its children got larger, but when I moved to a different menu or clicked away the font size shrank back to font size 12.

Dynamically bound menu

i'm noobie on WPF.
i have this Admin menu include 'manage A','manage B','manage C'
in my XAML
<MenuItem Header="_Admin" Name="adminMenuItem" Visibility="{Binding Path=IsAdmin, Mode=OneWay,}" >
<MenuItem Header="manage A" Command="ShowTab" />
<MenuItem Header="manage B" Command="ShowTab" />
<MenuItem Header="manage C" Command="ShowTab" />
</MenuItem>
in my mainWindow.cs code,
private void ShowTab(MenuItem menuItem)
{
if (menuItem.Header = "manage A")
showTabA();
if (menuItem.Header = "manage B")
showTabB();
if (menuItem.Header = "manage C")
showTabC();
}
can i bind menuitem with commands like that? if not, what's the best way to get the value from different menu items.
Many thanks
Specify a CommandParameter in the MenuItems which identifies the tab, and get that value from the ExecutedRoutedEventArgs.Parameter property, it's cleaner than using the header at the very least.

WPF Popup MenuItem stays highlighted when using arrow keys

After opening a Popup menu programatically, if the user uses up and down arrow keys to move through the menu, menu items get highlighted and they never get unhighlighted. What can I do so that after the user presses the down arrow, the previously highlighted menuitem becomes unhighlighted?
This happens with a very simple Popup menu:
<Grid>
<Button x:Name="Button1" Content="Open Menu"
Click="OnPopupMenuButton_Click"
Height="23" HorizontalAlignment="Left" Margin="69,12,0,0" VerticalAlignment="Top" Width="75" />
<Popup x:Name="MyPopupMenu" StaysOpen="False" >
<StackPanel Orientation="Vertical" Background="White" Margin="0">
<MenuItem x:Name="xAimee" Header="Aimee" Margin="0,2,0,0" />
<MenuItem x:Name="xBarbara" Header="Barbara" />
<MenuItem x:Name="xCarol" Header="Carol" />
<Separator x:Name="xSeparator1" Margin="0,2,2,2"/>
<MenuItem x:Name="xDana" Header="Dana" />
<MenuItem x:Name="xElizabeth" Header="Elizabeth" />
</StackPanel>
</Popup>
</Grid>
Here is how the Popup gets opened:
private void OnPopupMenuButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
Button button = sender as Button;
MyPopupMenu.PlacementTarget = button;
MyPopupMenu.Placement = PlacementMode.Mouse;
MyPopupMenu.IsOpen = true;
MyPopupMenu.StaysOpen = false;
}
I have been following up on archer's suggestion, but I had a few issues. First, I did not want the menu to open on a right-click, partly because I just didn't want it to open on a right-click and partly because I actually need to use PlacementMode.Top, and the context menu kept opening in the standard context-menu place (to the side and down).
So in the end, I did end up using a Context Menu, but I did a couple of special things. First, in the Window constructor, I set the button's ContextMenu to null, to prevent it from opening when right-clicked. Then when the user left-clicks, I programmatically set the ContextMenu to the one that I created in the xaml file. When the menu closes, I set the button's ContextMenu back to null. I tried manipulating the ContextMenu visibility instead, but that did not seem to work as well as setting it to null and back to an object.
Here is the final xaml, not too different from the question exception that I am handling the Closed event for the ContextMenu.
<Button x:Name="xOpenContextMenuButton" Content = "Open Menu"
Click="OnContextMenuButton_Click"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Width="80" Margin="0,0,36,8" Height="23">
<Button.ContextMenu>
<ContextMenu x:Name="xContextMenu" Closed="OnContextMenu_Closed">
<MenuItem x:Name="xAimee" Header="Aimee" />
<MenuItem x:Name="xBarbara" Header="Barbara" />
<MenuItem x:Name="xCarol" Header="Carol" />
<Separator x:Name="xSeparator1" Margin="0,2,2,2" />
<MenuItem x:Name="xDana" Header="Dana" />
<MenuItem x:Name="xElizabeth" Header="Elizabeth" />
</ContextMenu>
</Button.ContextMenu>
</Button>
Here is the code-behind, which changed a lot:
public MainWindow()
{
InitializeComponent();
xOpenContextMenuButton.ContextMenu = null;
}
private void OnContextMenuButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
xOpenContextMenuButton.ContextMenu = xContextMenu;
xContextMenu.PlacementTarget = xOpenContextMenuButton;
xContextMenu.Placement = PlacementMode.Top;
xContextMenu.IsOpen = true;
xContextMenu.StaysOpen = false;
}
private void OnContextMenu_Closed(object sender, RoutedEventArgs e)
{
xOpenContextMenuButton.ContextMenu = null;
}
Once again, thanks to archer, because I didn't realize that using Popup was not the normal way to create a popup menu in WPF. I think the root cause of the problem is, a Popup can contain anything -- a label, another button, etc. Popup isn't necessarily expecting embedded MenuItems, so it isn't smart enough to understand that it should switch between my menu items when using the arrow keys. But a ContextMenu expects to have MenuItems in it so it knows how to switch between them.

How do get menu to open to the left in WPF?

I have a menu (with menuitems) in WPF. Unfortunately when I click on the menu heading it opens the menu to the right. The problem is that there is stuff on the right that I don't want it to overlap. How do I tell WPF to open the menu to the left? Do I need to do a control template? (control templates seem so heavy handed for such basic style changes).
Thanks!
KSG
While you can create a ControlTemplate to do this like they do here, I agree that it is a cumbersome method just to modify one value on a part of the MenuItems. Instead, I think that this is a great place to use an AttachedProperty. We can create something just like the ContextMenuService, but for Popups (In fact, I'm somewhat surprised that it isn't built in).
To change where the popup is opening, we're going to want to set the Popup's PlacementMode. We can use the propa shortcut to generate our AttachedProperty(or properties if you want to implement the rest). We need to add a callback to our PropertyMetadata, but if the AttachedProperty is set inline on the control in XAML then the callback will fire before the whole control is fully constructed. To ensure the MenuItem's template is applied, and the Popup exists before we try and set it's value, we can just attach to the Loaded event if it isn't already loaded.
Once it is loaded, we want to retrieve the Popup from the template, and if we look at the MenuItem class we can see that it has a TemplatePartAttribute defining the Popup's name as "PART_Popup". Once we have that, we can set the PlacementMode on the MenuItem's Popup.
public static PlacementMode GetMenuPlacement(DependencyObject obj)
{
return (PlacementMode)obj.GetValue(MenuPlacementProperty);
}
public static void SetMenuPlacement(DependencyObject obj, PlacementMode value)
{
obj.SetValue(MenuPlacementProperty, value);
}
// Using a DependencyProperty as the backing store for MenuPlacement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MenuPlacementProperty =
DependencyProperty.RegisterAttached("MenuPlacement",
typeof(PlacementMode),
typeof(Window1),
new FrameworkPropertyMetadata(PlacementMode.Bottom, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnMenuPlacementChanged)));
private static void OnMenuPlacementChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var menuItem = o as MenuItem;
if (menuItem != null)
{
if (menuItem.IsLoaded)
{
SetPopupPlacement(menuItem, (PlacementMode)e.NewValue);
}
else
{
menuItem.Loaded += new RoutedEventHandler((m, v) => SetPopupPlacement(menuItem, (PlacementMode)e.NewValue));
}
}
}
private static void SetPopupPlacement(MenuItem menuItem, PlacementMode placementMode)
{
Popup popup = menuItem.Template.FindName("PART_Popup", menuItem) as Popup;
if (popup != null)
{
popup.Placement = placementMode;
}
}
Now that we have our AttachedProperty, it's easy to change the Popup placement in the UI.
<Menu>
<MenuItem Header="Item 1"
local:Window1.MenuPlacement="Right">
<MenuItem Header="SubItem 1" />
<MenuItem Header="SubItem 2" />
<MenuItem Header="SubItem 3" />
<MenuItem Header="SubItem 4" />
</MenuItem>
<MenuItem Header="Item 2"
local:Window1.MenuPlacement="Left">
<MenuItem Header="SubItem 5" />
<MenuItem Header="SubItem 6" />
<MenuItem Header="SubItem 7" />
<MenuItem Header="SubItem 8" />
</MenuItem>
<MenuItem Header="Item 3"
local:Window1.MenuPlacement="Mouse">
<MenuItem Header="SubItem 9" />
<MenuItem Header="SubItem 10" />
<MenuItem Header="SubItem 11" />
<MenuItem Header="SubItem 12" />
</MenuItem>
</Menu>

Resources