TOC

This article is currently in the process of being translated into Vietnamese (~98% done).

Các lệnh Commands:

Sử dụng WPF commands

Trong bài viết trước, chúng ta đã thảo luận rất nhiều lý thuyết về các commands là gì và cách chúng hoạt động. Trong chương này, chúng ta sẽ xem xét cách bạn thực sự sử dụng các commands, bằng cách gán chúng cho các thành phần giao diện người dùng và tạo các ràng buộc commands liên kết tất cả lại với nhau.

Chúng ta bắt đầu với một ví dụ đơn giản:

<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");
		}
	}
}

Chúng tôi xác định một ràng buộc command trên Window, bằng cách thêm nó vào bộ sưu tập CommandBindings của nó. Chúng tôi xác định rằng Command mà chúng tôi muốn sử dụng (Command mới từ ApplicationCommands), cũng như hai trình xử lý sự kiện. Giao diện trực quan bao gồm một nút duy nhất, chúng tôi đính kèm command để sử dụng thuộc tính Command.

Trong Code-behind, chúng tôi xử lý hai sự kiện. Trình xử lý CanExecute, mà WPF sẽ gọi khi ứng dụng không hoạt động để xem command cụ thể hiện có khả dụng hay không, rất đơn giản cho ví dụ này, vì chúng tôi muốn command cụ thể này luôn có sẵn. Điều này được thực hiện bằng cách đặt thuộc tính CanExecute của các đối số sự kiện thành true.

Trình xử lý thực thi chỉ đơn giản hiển thị một hộp thông báo khi command được gọi. Nếu bạn chạy ví dụ và nhấn nút, bạn sẽ thấy thông báo này. Một điều cần chú ý là command này có một phím tắt mặc định được xác định, mà bạn nhận được như một phần thưởng bổ sung. Thay vì nhấp vào nút, bạn có thể thử nhấn Ctrl + N trên bàn phím của mình - kết quả là như nhau.

Sử dụng phương thức CanExecute

Trong ví dụ đầu tiên, chúng tôi đã triển khai một sự kiện CanExecute đơn giản là trả về đúng sự thật, để nút này luôn có sẵn. Tuy nhiên, điều này tất nhiên không đúng với tất cả các nút - trong nhiều trường hợp, bạn muốn nút này được bật hoặc tắt tùy thuộc vào một số loại trạng thái trong ứng dụng của bạn.

Một ví dụ rất phổ biến về điều này là việc bật các nút để sử dụng Windows Clipboard, nơi bạn muốn các nút Cut và Copy chỉ được bật khi văn bản được chọn và nút Paste chỉ được bật khi có văn bản trong clipboard. Đây chính xác là những gì chúng ta sẽ thực hiện trong ví dụ này:

<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();
		}
	}
}

Vì vậy, chúng tôi có giao diện rất đơn giản này với một vài nút và điều khiển TextBox. Nút đầu tiên sẽ cắt vào bảng tạm và nút thứ hai sẽ dán từ nó.

Trong Code-behind, chúng tôi có hai sự kiện cho mỗi nút: Một sự kiện thực hiện hành động thực tế, tên kết thúc bằng _Executed và sau đó là các sự kiện CanExecute. Trong mỗi function, bạn sẽ thấy rằng tôi áp dụng một số logic để quyết định liệu hành động đó có thể được thực thi hay không và sau đó gán nó cho giá trị trả về CanExecute trên EventArss.

Điều thú vị ở đây là bạn không phải gọi các phương thức này để cập nhật các nút của mình - WPF sẽ tự động thực hiện khi ứng dụng có thời điểm rảnh, đảm bảo rằng giao diện của bạn luôn được cập nhật.

Default command behavior and CommandTarget

Như chúng ta đã thấy trong ví dụ trước, việc xử lý một tập commands có thể dẫn đến khá nhiều mã, với rất nhiều khai báo phương thức và logic rất chuẩn. Đó có lẽ là lý do tại sao nhóm WPF quyết định xử lý một số thứ cho bạn. Trên thực tế, chúng ta có thể tránh được tất cả các Code-behind trong ví dụ trước, bởi vì WPF TextBox có thể tự động xử lý các commands phổ biến như Cut, Copy, Paste, Undo and Redo.

WPF thực hiện điều này bằng cách xử lý các sự kiện Executed và CanExecute cho bạn, khi một điều khiển nhập văn bản như TextBox đã tập trung. Bạn có thể tự do ghi đè các sự kiện này, về cơ bản là những gì chúng ta đã làm trong ví dụ trước, nhưng nếu bạn chỉ muốn hành vi cơ bản, bạn có thể để WPF kết nối các lệnh và điều khiển TextBox và thực hiện công việc cho bạn. Chỉ cần xem ví dụ này đơn giản hơn bao nhiêu:

<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>

Không có code Code-behind nào cần thiết cho ví dụ này - WPF xử lý tất cả, nhưng chỉ vì chúng tôi muốn sử dụng các lệnh cụ thể này cho điều khiển cụ thể này. TextBox thực hiện công việc cho chúng tôi.

Lưu ý cách tôi sử dụng các thuộc tính CommandTarget trên các nút, để liên kết các lệnh với điều khiển TextBox của chúng ta. Điều này là bắt buộc trong ví dụ cụ thể này, vì WrapPanel không xử lý tập trung theo cùng một cách, ví dụ: Thanh công cụ hoặc Menu sẽ có, nhưng nó cũng có ý nghĩa khá tốt để cung cấp cho các lệnh một mục tiêu.

Summary

Xử lý các commands khá đơn giản, nhưng liên quan đến việc đánh dấu và mã thêm một chút. Phần thưởng đặc biệt rõ ràng khi bạn cần phải thực hiện cùng một hành động từ nhiều nơi hoặc khi bạn sử dụng các commands tích hợp mà WPF có thể xử lý hoàn toàn cho bạn, như chúng ta đã thấy trong ví dụ trước.

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!