当前位置:首页 > 技术 > 正文内容

WPF入门教程(4):Command与功能区控件

访客 技术 2026年8月2日 1

许多数据驱动的应用程序都包含菜单和工具栏或功能区控件,允许用户控制操作。在WPF中,也可以使用功能区控件,因此本文将介绍菜单和功能区控件。

一.菜单控件

在WPF中,菜单可以通过`Menu`和`MenuItem`元素轻松创建。以下是一个示例代码,展示了如何创建一个包含主菜单、次菜单和子菜单项的菜单。

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="文件">
                <MenuItem Header="首页"/>
                <MenuItem Header="信息">
                    <MenuItem Header="首页"/>
                </MenuItem>
                <Separator/>
                <MenuItem Header="退出"/>
            </MenuItem>
        </Menu>
    </DockPanel>
</Window>

运行应用程序后,可以看到如下的菜单:

菜单示例

二.功能区控件

菜单控件的替代品是功能区控件。自Microsoft Office 07起,微软引入了新开发的功能区控件。这个新功能的引入使得Office以前版本的许多用户在新的UI中难以找到操作按钮。

WPF功能区控件位于`System.Windows.Controls.Ribbon`命名空间中,需要引用该命名空间。以下是一个示例代码,展示了如何使用功能区控件。

<RibbonWindow x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <Ribbon DockPanel.Dock="Top">
            <Ribbon.QuickAccessToolBar>
                <RibbonQuickAccessToolBar>
                    <RibbonButton SmallImageSource="one.png"/>
                    <RibbonButton SmallImageSource="one.png"/>
                </RibbonQuickAccessToolBar>
            </Ribbon.QuickAccessToolBar>
            <Ribbon.ApplicationMenu>
                <RibbonApplicationMenu SmallImageSource="one.png">
                    <RibbonApplicationMenuItem Header="Hello"/>
                    <RibbonSeparator/>
                    <RibbonApplicationMenuItem Header="Exit" Command="Close"/>
                </RibbonApplicationMenu>
            </Ribbon.ApplicationMenu>
        </Ribbon>
    </DockPanel>
</RibbonWindow>

在应用程序菜单中,使用`RibbonTab`元素定义功能区控件的内容。每个`RibbonTab`中包含多个`RibbonGroup`,每个`RibbonGroup`中包含多个`RibbonButton`。

<RibbonTab Header="Home">
    <RibbonGroup Header="Clipboard">
        <RibbonButton Command="Paste" Label="yi" LargeImageSource="one.png"/>
        <RibbonButton Command="Cut" Label="er" LargeImageSource="one.png"/>
        <RibbonButton Command="Undo" Label="san" LargeImageSource="one.png"/>
    </RibbonGroup>
    <RibbonGroup Header="Show">
        <RibbonButton Label="yi" LargeImageSource="one.png"/>
        <RibbonButton Command="Cut" Label="er" LargeImageSource="one.png"/>
        <RibbonButton Command="Undo" Label="san" LargeImageSource="one.png"/>
    </RibbonGroup>
</RibbonTab>

第二个`RibbonTab`仅用于演示如何在功能区使用不同类型的控件。

<RibbonTab Header="Ribben Controla">
    <RibbonGroup Header="Smaples">
        <RibbonButton Label="Button"/>
        <RibbonCheckBox Label="Checkbox"/>
        <RibbonComboBox>
            <Label>one</Label>
            <Label>two</Label>
        </RibbonComboBox>
        <RibbonTextBox>Text Box</RibbonTextBox>
        <RibbonSplitButton Label="Split Button">
            <RibbonMenuItem Header="One"/>
            <RibbonMenuItem Header="Two"/>
        </RibbonSplitButton>
        <RibbonComboBox Label="Combox2" IsEditable="False">
            <RibbonGallery SelectedValuePath="Content" MaxColumnCount="1" SelectedValue="Green">
                <RibbonGalleryCategory>
                    <RibbonGalleryItem Content="red" Foreground="Red"/>
                    <RibbonGalleryItem Content="Green" Foreground="Green"/>
                </RibbonGalleryCategory>
            </RibbonGallery>
        </RibbonComboBox>
    </RibbonGroup>
    <RibbonGroup Header="Smaples">
        <RibbonButton Label="Button"/>
        <RibbonCheckBox Label="Checkbox"/>
        <RibbonComboBox>
            <Label>one</Label>
            <Label>two</Label>
        </RibbonComboBox>
        <RibbonTextBox>Text Box</RibbonTextBox>
    </RibbonGroup>
</RibbonTab>

效果图如下:

功能区控件示例

三.Commanding

Commanding是WPF中的一个概念,它在动作源和执行动作的目标之间创建松散耦合。这个概念基于Gang Of Four中的命令模式。在WPF中,事件通常是紧密耦合的,而命令则是松散耦合的。

命令模式是一种行为设计模式,它分离了客户和命令的接收者,更加适合进行单元测试。

要执行的动作用于命令对象创建。命令实现`ICommand`接口。WPF使用的命令类是`RoutedCommand`及其派生类`RoutedUiCommand`。`RoutedUiCommand`类定义了一个`ICommand`接口未定义的附加`Text`属性,这个属性可以在用户界面中用作文件信息。`ICommand`定义了`Execute()`和`CanExecute()`方法,它们都在对象上执行。

命令源是调用命令的对象。命令源实现`ICommandSource`接口。这种命令源的例子有派生自`ButtonBase`的按钮类,`HyperLink`、`KeyBinding`、`InputBinding`和`MouseBinging`是派生自`InputBinding`的类。命令源有一个`Command`属性,其中就可以指定实现这个`ICommand`接口的命令对象。

下面举一个例子来说明如何实现命令对象。我们需要先讲解如何定义命令。

四.定义命令

.NET提供了返回预定义命令的类,如`ApplicationCommands`类定义了静态属性`New`、`Open`、`Close`、`Print`、`Cut`、`Copy`、`Paste`等这些属性返回可用于特殊目的的`RoutedUiCommand`对象。还提供了其他类如`NavigationCommands`和`MediaCommands`,它们分别提供了导航和媒体相关的命令。

定义执行应用程序域并不难,为此创建了一个`BooksCommands`类,它通过`ShowBook`与`ShowBookList`属性返回了一个`RoutedUiCommand`。也可以给命令指定一个手势,如`KeyGesture`或`MouseGesture`,这里指定一个`KeyGesture`。用`Alt`修饰`B`键,所以按`Alt+B`组合键可以调用这个命令。我们看以下这个方法的具体实现:

using System.Windows.Input;

namespace WpfApp1
{
    public class BooksCommands
    {
        private static RoutedUICommand s_showbook;
        public static ICommand ShowBook =>
            s_showbook ?? (s_showbook = new RoutedUICommand("Show Book", nameof(ShowBook), typeof(BooksCommands)));
        private static RoutedUICommand s_showBooksList;
        public static ICommand ShowBooksList
        {
            get
            {
                if (s_showBooksList == null)
                {
                    s_showBooksList = new RoutedUICommand("Show Book", nameof(ShowBook), typeof(BooksCommands));
                    s_showBooksList.InputGestures.Add(new KeyGesture(Key.B, ModifierKeys.Alt));
                }
                return s_showBooksList;
            }
        }
    }
}

五.定义命令源

每个实现`ICommandSource`接口的类都可以是命令源,如`Button`和`MenuItem`。在前面创建的功能区控件中,把`Command`属性赋予几个`RibbonButton`元素中,如下列代码所示:

<Ribbon DockPanel.Dock="Top">
    <Ribbon.QuickAccessToolBar>
        <RibbonQuickAccessToolBar>
            <RibbonButton SmallImageSource="one.png" Command="local:BooksCommands.ShowBook"/>
            <RibbonButton SmallImageSource="one.png" Command="local:BooksCommands.ShowBooksList"/>
        </RibbonQuickAccessToolBar>
    </Ribbon.QuickAccessToolBar>
</Ribbon>

一些常见的预命令,例如`ApplicationCommands.Cut`、`Copy`、`Paste`等也赋予`RibbonButton`元素的`Command`属性。对于域命令的命令可以直接在`Command`上写上这些命令。

六.命令绑定

必须添加命令绑定才能把它们连接到处理程序方法上。这里在`Window`元素中定义命令绑定,这样这些就可以操作所有的窗口元素。执行`ApplicationCommands.Close`命令时,会调用`OnClose`;执行`BooksCommands.ShowBook`命令时,会调用`OnShowBooks()`。

<Window.CommandBindings>
    <CommandBinding Command="Close" Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
private void CommandBinding_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
    Application.Current.Shutdown();
}

...未完待续,我们明天继续讨论数据绑定。敬请期待!

标签: WPF

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。