命令綁定(Command)
[7.1updated]這一節除了基礎app部分,並沒有什么變化
什么是Command?
先看下微軟官方的說明:
Commanding is an input mechanism in Windows Presentation Foundation (WPF) which provides input handling at a more semantic level than device input. Examples of commands are the Copy, Cut, and Paste operations found on many applications.
雖然英語捉雞,但是不妨礙我們閱讀一手資料,燃鵝(●'◡'●),我們看下Google的翻譯:
指令是Windows Presentation Foundation(WPF)中的一種輸入機制,它提供比設備輸入更多語義級別的輸入處理。命令的例子是在許多應用程序中找到的復制,剪切和粘貼操作。
好像也沒什么用!還是直接拿例子來看:
MainWindow.xaml
<Window x:Class="UsingDelegateCommands.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="Using DelegateCommand" Width="350" Height="275">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<CheckBox IsChecked="{Binding IsEnabled}" Content="Can Execute Command" Margin="10"/>
<Button Command="{Binding ExecuteDelegateCommand}" Content="DelegateCommand" Margin="10"/>
<Button Command="{Binding DelegateCommandObservesProperty}" Content="DelegateCommand ObservesProperty" Margin="10"/>
<Button Command="{Binding DelegateCommandObservesCanExecute}" Content="DelegateCommand ObservesCanExecute" Margin="10"/>
<Button Command="{Binding ExecuteGenericDelegateCommand}" CommandParameter="Passed Parameter" Content="DelegateCommand Generic" Margin="10"/>
<TextBlock Text="{Binding UpdateText}" Margin="10" FontSize="22"/>
</StackPanel>
</Window>
MainWindowViewModel.cs
using System;
using Prism.Commands;
using Prism.Mvvm;
namespace UsingDelegateCommands.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
SetProperty(ref _isEnabled, value);
ExecuteDelegateCommand.RaiseCanExecuteChanged();
}
}
private string _updateText;
public string UpdateText
{
get { return _updateText; }
set { SetProperty(ref _updateText, value); }
}
public DelegateCommand ExecuteDelegateCommand { get; private set; }
public DelegateCommand<string> ExecuteGenericDelegateCommand { get; private set; }
public DelegateCommand DelegateCommandObservesProperty { get; private set; }
public DelegateCommand DelegateCommandObservesCanExecute { get; private set; }
public MainWindowViewModel()
{
ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);
DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute)
.ObservesProperty(() => IsEnabled);
DelegateCommandObservesCanExecute = new DelegateCommand(Execute)
.ObservesCanExecute(() => IsEnabled);
ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric)
.ObservesCanExecute(() => IsEnabled);
}
private void Execute()
{
UpdateText = $"Updated: {DateTime.Now}";
}
private void ExecuteGeneric(string parameter)
{
UpdateText = parameter;
}
private bool CanExecute()
{
return IsEnabled;
}
}
}
View部分:
頭部引入命名空間,指定ViewModeLocator模式:
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
接着是一個:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
</StackPanel>
接着內部是一組控件,一個CheckBox四個Button一個 TextBlock。
- CheckBox IsChecked="{Binding IsEnabled}"
復選框的勾選狀態綁定到一個布爾型屬性上。
- Button Command="{Binding ExecuteDelegateCommand}"
普通命令綁定
- Button Command="{Binding ExecuteGenericDelegateCommand}" CommandParameter="Passed Parameter"
帶參數的 命令綁定
- TextBlock Text="{Binding UpdateText}"
為TextBlock的Text屬性綁定數據源
Tips:
Binding語法 Property="{Binding PropertyPath}",PropertyPath就是VM
當為Command進行Binding的時候,還可以帶參數,使用CommandParameter屬性,上面的CommandParameter指定了一個字符串“Passed Parameter”,當然還可以為其Binding一個對象。
ViewModel部分:
set方法中的:
SetProperty(ref _isEnabled, value);
屬性變更的通知,當視圖狀態更新后,會通知VM更改_isEnabled。
ExecuteDelegateCommand.RaiseCanExecuteChanged();
這段代碼,則會通知ExecuteDelegateCommand的可執行狀態更改了,讓他重新獲取下可執行狀態,那他是怎么獲取可執行狀態的呢?我們看下這個Command:
ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);
new 的時候,有兩個參數,第一個是Action(無返回類型的方法)Execute(需要執行的方法),第二個是一個Func
private bool CanExecute()
{
return IsEnabled;
}
很簡單,直接返回了IsEnabled,而他是跟視圖的CheckBox的IsChecked綁定的,當然也可以返回_isEnabled,而我更傾向后面這個,Public那個是給外人用的,蛤蛤。
當然可執行狀態,還有其他的更優雅的寫法,也就不用寫ExecuteDelegateCommand.RaiseCanExecuteChanged();了,具體代碼如下:
DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute)
.ObservesProperty(() => IsEnabled);
DelegateCommandObservesCanExecute = new DelegateCommand(Execute)
.ObservesCanExecute(() => IsEnabled);
下面這個是帶參數的命令(command),他的回調函數需要一個string類型的參數,在new的時候要指定入參類型:
ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric)
.ObservesCanExecute(() => IsEnabled);
回調函數ExecuteGeneric:
private void ExecuteGeneric(string parameter)
{
UpdateText = parameter;
}
總結:
ViewModel(簡稱VM,下文也偶爾會出現VM,也指ViewModel)的類需要繼承BindableBase,BindableBase實現了INotifyPropertyChanged接口。
命令類型是DelegateCommand,這繼承自DelegateCommandBase,而DelegateCommandBase實現了ICommand接口。
這倆接口是MVVM的底層接口。有興趣的可以看一下 MVVMFoundation,他封裝沒有那么多次,只有四個cs文件,可以直接看到,他是如何運用ICommand和INotifyPropertyChanged接口的。
有興趣的可以看一下淺談WPF中的MVVM框架--MVVMFoundation
但是,作為高級的我們,就用高級的封裝,有了火柴誰還燧木取火,233333
復合型命令綁定
通常情況下,我們的命令調用者直接調用我們的命令,但是有些時候,我們需要從外部(比如其他的視圖或父視圖)的控件調用該命令,那么就需要一個CompositeCommand。
CompositeCommand是一個由多個子命令組成的命令。它提供了執行子命令的所有關聯方法(Execute和CanExecute)的功能,當所有子命令的可執行狀態為True的時候CompositeCommand才可以被執行。
