TOC

This article has been localized into Chinese by the community.

WPF命令:

使用WPF命令

在上一篇文章中,我们讨论了很多关于命令是什么以及它们如何工作的理论。在本章中,我们将研究如何实际使用命令,将命令分配给用户界面元素并创建将它们链接在一起的命令绑定。

我们将从一个非常简单的例子开始:

<Window x:Class="WpfTutorialSamples.Commands.UsingCommandsSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="UsingCommandsSample" Height="100" Width="200">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed" CanExecute="NewCommand_CanExecute" />
    </Window.CommandBindings>

    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button Command="ApplicationCommands.New">New</Button>
    </StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace WpfTutorialSamples.Commands
{
	public partial class UsingCommandsSample : Window
	{
		public UsingCommandsSample()
		{
			InitializeComponent();
		}

		private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

		private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			MessageBox.Show("The New command was invoked");
		}
	}
}

我们在 Window.CommandBindings 集合中定义了一个窗口上的命令绑定。它包含了我们希望使用的命令(即 ApplicationCommands 中的 New 命令)以及两个事件处理程序。窗口界面由单个按钮组成,我们将命令附加到该按钮的 Command 属性上。

在Code-behind中,我们处理这两个事件。当应用程序空闲以查看特定命令当前是否可用时,WPF将调用的CanExecute处理程序对于此示例非常简单,因为我们希望此特定命令始终可用。这是通过将事件参数的CanExecute属性设置为true来完成的。

Executed处理程序在调用命令时只显示一个消息框。如果您运行示例并按下按钮,您将看到此消息。需要注意的是,此命令定义了一个默认的键盘快捷键;这是一个额外的好处。您可以尝试按键盘上的Ctrl + N而不是单击按钮 - 结果是相同的。

使用 CanExecute 方法

在第一个示例中,我们实现了一个简单返回true的CanExecute事件,以便该按钮始终可用。但是,对于所有按钮当然不是这样 - 在许多情况下,您希望根据应用程序中的某种状态启用或禁用按钮。

一个非常常见的例子是切换使用Windows剪贴板的按钮,您希望仅在选择文本时启用剪切和复制按钮,并且只有在剪贴板中存在文本时才启用粘贴按钮。这正是我们在这个例子中将要完成的事情:

<Window x:Class="WpfTutorialSamples.Commands.CommandCanExecuteSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="CommandCanExecuteSample" Height="200" Width="250">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Cut" CanExecute="CutCommand_CanExecute" Executed="CutCommand_Executed" />
        <CommandBinding Command="ApplicationCommands.Paste" CanExecute="PasteCommand_CanExecute" Executed="PasteCommand_Executed" />
    </Window.CommandBindings>
    <DockPanel>
        <WrapPanel DockPanel.Dock="Top" Margin="3">
            <Button Command="ApplicationCommands.Cut" Width="60">_Cut</Button>
            <Button Command="ApplicationCommands.Paste" Width="60" Margin="3,0">_Paste</Button>
        </WrapPanel>
        <TextBox AcceptsReturn="True" Name="txtEditor" />
    </DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace WpfTutorialSamples.Commands
{
	public partial class CommandCanExecuteSample : Window
	{
		public CommandCanExecuteSample()
		{
			InitializeComponent();
		}

		private void CutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (txtEditor != null) && (txtEditor.SelectionLength > 0);
		}

		private void CutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			txtEditor.Cut();
		}

		private void PasteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = Clipboard.ContainsText();
		}

		private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			txtEditor.Paste();
		}
	}
}

所以,我们有这个非常简单的界面,包含有几个按钮和一个TextBox控件。第一个按钮将TextBox控件中选择的内容剪切到剪贴板上,第二个按钮将剪贴板上的内容粘贴到TextBox控件的内容中。

在后端代码中,每个按钮有两个事件:一个执行实际操作,其名称以_Executed结尾,然后是CanExecute事件。在每个CanExecute事件中,您将看到我应用一些逻辑来决定操作是否可以被执行,然后将决定的结果作为返回值赋给EventArgs的CanExecute

关于这一点很酷的是,您不必调用这些方法来更新按钮 - 当应用程序有空闲时,WPF会自动执行此操作,确保您的界面始终保持更新状态。

默认命令行为和命令目标

正如我们在前面的示例中看到的那样,处理一组命令可能会导致增加相当多的代码,其中包含大量的方法声明和非常标准的逻辑。这可能就是为什么WPF团队决定为您处理一些命令的原因。事实上,在前面例子中,我们可以屏蔽所有的后端处理代码,因为WPF文本框控件可以自动处理常见的命令,如剪切、复制、粘贴、撤消和重做。

当像TextBox这样的文本输入控件具有焦点时,WPF通过为您处理Executed和CanExecute事件来完成此操作。您可以自由地覆盖这些事件,这基本上就是我们在前面的示例中所做的,但如果您只是想要基本行为,您可以让WPF连接命令和TextBox控件并为您完成工作。看看这个例子有多简单:

<Window x:Class="WpfTutorialSamples.Commands.CommandsWithCommandTargetSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="CommandsWithCommandTargetSample" Height="200" Width="250">
    <DockPanel>
        <WrapPanel DockPanel.Dock="Top" Margin="3">
            <Button Command="ApplicationCommands.Cut" CommandTarget="{Binding ElementName=txtEditor}" Width="60">_Cut</Button>
            <Button Command="ApplicationCommands.Paste" CommandTarget="{Binding ElementName=txtEditor}" Width="60" Margin="3,0">_Paste</Button>
        </WrapPanel>
        <TextBox AcceptsReturn="True" Name="txtEditor" />
    </DockPanel>
</Window>

此示例不需要Code-behind代码 - WPF为我们处理所有代码,但仅仅是因为我们希望将这些特定命令用于此特定控件。 TextBox为我们工作。

注意我是如何在按钮上使用CommandTarget属性来将命令绑定到我们的TextBox控件的。这在这个特殊的例子中是必需的,因为WrapPanel不像工具栏或菜单那样处理焦点,但是给命令一个目标也是很有意义的。

小结

处理命令非常简单,但确实涉及到一些额外的标记和代码。但是,当您需要从多个地方调用相同的操作时,或者当您使用WPF可以完全处理的内置命令时,正如我们在上一个示例中看到的那样,得到的回报是尤其明显的。


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!