相关文章推荐
有爱心的卡布奇诺  ·  android ...·  1 年前    · 
温暖的枕头  ·  .NET MAUI ...·  1 年前    · 
留胡子的番茄  ·  一篇关于Tortoisegit ...·  1 年前    · 

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

https://www.zhihu.com/video/1504813865359949824

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;