WPF 入门教程Menu和ContextMenu
Windows 应用程序最常见的部分之一是菜单,有时也称为主菜单,因为应用程序中通常只有一个。菜单很实用,因为它提供了很多选项,只占用很少的空间,即使微软正在推动 Ribbon 作为优秀的、旧的菜单和工具栏的替代品,它们仍然在每个优秀开发人员的工具箱中占有一席之地。
WPF 带有用于创建名为...菜单的菜单的精细控件。向其中添加项目非常简单 - 您只需向其中添加 MenuItem 元素,并且每个 MenuItem 可以具有一系列子项目,从而允许您创建分层菜单,正如您在许多 Windows 应用程序中所知道的那样。让我们直接跳到使用菜单的示例:
<Window x:Class="WpfTutorialSamples.Common_interface_controls.MenuSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuSample" Height="200" Width="200">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_New" />
<MenuItem Header="_Open" />
<MenuItem Header="_Save" />
<Separator />
<MenuItem Header="_Exit" />
</MenuItem>
</Menu>
<TextBox AcceptsReturn="True" />
</DockPanel>
</Window>
与大多数 Windows 应用程序一样,我的菜单放置在窗口的顶部,但为了与 WPF 的巨大灵活性保持一致,您实际上可以将 Menu 控件放置在您喜欢的任何位置,以及您可能需要的任何宽度或高度。
我定义了一个顶级项目,有 4 个子项目和一个分隔符。我使用 Header 属性来定义项目的标签,您应该注意到每个标签的第一个字符之前的下划线。它告诉 WPF 使用该字符作为加速键,这意味着用户可以按 Alt 键后跟给定的字符,以激活菜单项。这从顶级项目一直到层次结构都有效,这意味着在这个例子中,我可以按 Alt ,然后 F 然后 N ,以激活 新 项目。
图标和复选框
菜单项的两个常见功能是图标,用于更轻松地识别菜单项及其功能,以及具有可检查菜单项的能力,可以打开和关闭特定功能。WPF MenuItem 两者都支持,并且非常易于使用:
<Window x:Class="WpfTutorialSamples.Common_interface_controls.MenuIconCheckableSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuIconCheckableSample" Height="150" Width="300">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Exit" />
</MenuItem>
<MenuItem Header="_Tools">
<MenuItem Header="_Manage users">
<MenuItem.Icon>
<Image Source="/WpfTutorialSamples;component/Images/user.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Show groups" IsCheckable="True" IsChecked="True" />
</MenuItem>
</Menu>
<TextBox AcceptsReturn="True" />
</DockPanel>
</Window>
在这个例子中,我创建了一个二级顶级项目,我在其中添加了两个项目:一个定义了一个图标,使用 Icon 属性,里面有一个标准的 Image 控件,另一个我们使用 IsCheckable 属性来允许用户选中和取消选中该项目。我什至使用 IsChecked 属性来默认检查它。从代码隐藏中,您可以阅读该属性以了解是否选中了给定的菜单项。
处理点击
当用户单击菜单项时,您通常希望发生某些事情。最简单的方法是简单地向 MenuItem 添加一个单击事件处理程序,如下所示:
<MenuItem Header="_New" Click="mnuNew_Click" />
在代码隐藏中,您将需要实现 mnuNew_Click 方法,如下所示:
private void mnuNew_Click(object sender, RoutedEventArgs e)
MessageBox.Show("New");
这对于更简单的应用程序或原型设计就足够了,但 WPF 方法是为此使用命令。
推荐一款WPF MVVM框架开源项目:Newbeecoder.UI

Demo下载:
键盘快捷键和命令
您可以像我们上面所做的那样轻松处理菜单项的 Click 事件,但更常见的方法是使用 WPF 命令。有很多关于使用和创建命令的理论,所以他们在网站上有自己的文章类别,但现在,我可以告诉你,在 WPF 中使用它们时,它们有几个优点,尤其是与菜单结合使用时或工具栏。
首先,它们确保您可以在工具栏、菜单甚至上下文菜单上执行相同的操作,而无需在多个位置实现相同的代码。它们还使键盘快捷键的处理变得更加容易,因为与 WinForms 不同,如果您将键盘快捷键分配给例如菜单项,WPF 不会自动侦听键盘快捷键 - 您必须手动执行此操作。
但是,在使用命令时,WPF 会全神贯注,并且会自动响应键盘快捷键。菜单项的文本 (Header) 也是自动设置的(尽管您可以根据需要覆盖它),InputGestureText 也是如此,它向用户显示可使用哪个键盘快捷键来调用特定菜单项。让我们直接跳到将 Menu 与 WPF 命令相结合的示例:
<Window x:Class="WpfTutorialSamples.Common_interface_controls.MenuWithCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuWithCommandsSample" Height="200" Width="300">
<Window.CommandBindings>
<CommandBinding Command="New" CanExecute="NewCommand_CanExecute" Executed="NewCommand_Executed" />
</Window.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Command="New" />
<Separator />
<MenuItem Header="_Exit" />
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Command="Cut" />
<MenuItem Command="Copy" />
<MenuItem Command="Paste" />
</MenuItem>
</Menu>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Input;
namespace WpfTutorialSamples.Common_interface_controls
public partial class MenuWithCommandsSample : Window
public MenuWithCommandsSample()
InitializeComponent();
private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
e.CanExecute = true;
private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
txtEditor.Text = "";
这可能不是很明显,但是通过使用命令,我们可以免费获得一大堆东西:项目上的键盘快捷键、文本和 InputGestureText ,WPF 根据活动控件及其状态自动启用/禁用项目。在这种情况下,剪切和复制被禁用,因为没有选择文本,但粘贴被启用,因为我的剪贴板不是空的!
并且因为 WPF 知道如何结合某些控件来处理某些命令,在这种情况下,剪切/复制/粘贴命令结合文本输入控件,我们甚至不必处理它们的 Execute 事件 - 它们可以直接工作盒子!不过,我们必须为 New 命令处理它,因为 WPF 无法猜测当用户激活它时我们想要它做什么。这是通过窗口的 CommandBindings 完成的 ,所有这些都在有关命令的章节中进行了详细说明。
ContextMenu,通常称为弹出菜单或弹出菜单,是在特定用户操作时显示的菜单,通常是在特定控件或窗口上用鼠标右键单击。上下文菜单通常用于提供与单个控件相关的功能。
WPF 带有 ContextMenu 控件,因为它几乎总是与特定控件相关联,所以通常也是将其添加到界面的方式。这是通过所有控件公开的 ContextProperty 完成的(它来自大多数 WPF 控件继承自的 FrameworkElement)。考虑下一个示例,看看它是如何完成的:
<Window x:Class="WpfTutorialSamples.Common_interface_controls.ContextMenuSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ContextMenuSample" Height="250" Width="250">
<Button Content="Right-click me!" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu item 1" />
<MenuItem Header="Menu item 2" />
<Separator />
<MenuItem Header="Menu item 3" />
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
</Window>
如果您已经阅读了有关常规菜单的章节,您很快就会意识到 ContextMenu 的工作方式完全相同,这也不足为奇,因为它们都继承了 MenuBase 类。就像我们在使用常规菜单的示例中看到的那样,您当然可以向这些项目添加 Click 事件以在用户单击它们时进行处理,但更适合 WPF 的方法是使用命令。
带有命令和图标的 ContextMenu
在下一个示例中,我将向您展示使用 ContextMenu 时的两个关键概念: WPF 命令的使用,它将为我们提供许多功能,包括 Click 事件处理程序、文本和快捷文本,只需通过分配命令属性的东西。我还将向您展示如何在 ContextMenu 项目上使用图标。看一看:
<Window x:Class="WpfTutorialSamples.Common_interface_controls.ContextMenuWithCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ContextMenuWithCommandsSample" Height="200" Width="250">
<StackPanel Margin="10">
<TextBox Text="Right-click here for context menu!">
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Command="Cut">
<MenuItem.Icon>
<Image Source="/WpfTutorialSamples;component/Images/cut.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Command="Copy">
<MenuItem.Icon>
<Image Source="/WpfTutorialSamples;component/Images/copy.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Command="Paste">
<MenuItem.Icon>
<Image Source="/WpfTutorialSamples;component/Images/paste.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</StackPanel>
</Window>
尝试运行该示例,通过为项目分配命令,亲眼看看我们免费获得了多少功能。还要注意在 ContextMenu 的菜单项上使用图标是多么简单。
从代码隐藏调用 ContextMenu
到目前为止,ContextMenu 已经在右键单击它所属的控件时被调用。当我们将其分配给 ContextMenu 属性时,WPF 会自动为我们执行此操作。但是,在某些情况下,您可能很想从代码中手动调用它。这也很简单,所以让我们重新使用第一个示例来演示它:
<Window x:Class="WpfTutorialSamples.Common_interface_controls.ContextMenuManuallyInvokedSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ContextMenuManuallyInvokedSample" Height="250" Width="250">
<Window.Resources>
<ContextMenu x:Key="cmButton">
<MenuItem Header="Menu item 1" />
<MenuItem Header="Menu item 2" />
<Separator />
<MenuItem Header="Menu item 3" />
</ContextMenu>
</Window.Resources>
<Button Content="Click me!" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click" />
</Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Controls;
namespace WpfTutorialSamples.Common_interface_controls
public partial class ContextMenuManuallyInvokedSample : Window
public ContextMenuManuallyInvokedSample()
InitializeComponent();
private void Button_Click(object sender, RoutedEventArgs e)
ContextMenu cm = this.FindResource("cmButton") as ContextMenu;