C# WPF:如何为包含子项的MenuItem头部添加Click事件?
Hey there! The issue you're running into is super common with WPF's MenuItem control—when a parent menu item has sub-items, clicking its header by default only toggles the sub-menu open/closed, not firing the Click event. Let's walk through a few solid fixes for this:
Option 1: Use the PreviewMouseLeftButtonDown Event
This event fires before the default menu handling logic, so it'll catch clicks on the parent header even with sub-items present. Replace your existing Click handler with this:
item.PreviewMouseLeftButtonDown += (s, e) => { var menuItem = s as MenuItem; if (menuItem != null) { // Verify we're clicking the header text (not the sub-menu toggle arrow) if (e.OriginalSource is TextBlock headerText && headerText.Text == menuItem.Header.ToString()) { ShowMainWindow(); // Optional: Set to true if you don't want the sub-menu to toggle open/closed // e.Handled = true; } } };
This checks that you're actually clicking the header text (not the small arrow that toggles the sub-menu), so you won't accidentally trigger the action when expanding/collapsing the sub-items.
Option 2: Customize the MenuItem Template
If you want the native Click event to work as expected, you can override the default MenuItem control template. The core change is splitting the header area into two parts: one for triggering the Click event, and another for toggling the sub-menu.
Here's a simplified example of a modified template (you can adjust it to match your app's styling):
<Style TargetType="MenuItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="MenuItem"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <!-- Header text - triggers Click event --> <ContentPresenter Grid.Column="1" Content="{TemplateBinding Header}" RecognizesAccessKey="True" MouseLeftButtonDown="Header_Click"/> <!-- Sub-menu toggle arrow --> <ToggleButton Grid.Column="2" IsChecked="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource MenuItemToggleButtonStyle}"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
Then in your code-behind, add the Header_Click handler that calls ShowMainWindow().
Option 3: Use Commands (MVVM-Friendly Approach)
WPF commands are more reliable for this scenario and align with MVVM best practices. Define a simple command and bind it to your parent MenuItem:
First, create a basic command implementation:
public class ShowMainWindowCommand : ICommand { public bool CanExecute(object parameter) { // Add any logic to determine if the command can run return true; } public void Execute(object parameter) { ShowMainWindow(); } public event EventHandler CanExecuteChanged; }
Then assign it to your menu item instead of using the Click event:
item.Command = new ShowMainWindowCommand();
Commands will trigger when you click the parent header, and the sub-menu will still toggle open/closed normally.
内容的提问来源于stack exchange,提问作者Michael T

