從PRISM開始學WPF(六)MVVM(二)Command?
從PRISM開始學WPF(一)WPF?
從PRISM開始學WPF(二)Prism?
從PRISM開始學WPF(三)Prism-Region?
從PRISM開始學WPF(四)Prism-Module?
從PRISM開始學WPF(五)MVVM(一)ViewModel?
從PRISM開始學WPF(六)MVVM(二)Command?
從PRISM開始學WPF(七)MVVM(三)事件聚合器EventAggregator?
命令綁定(Command)
什麽是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那個是給外人用的,蛤蛤。
當然可執行狀態,還有其他的更優雅的寫法:
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接口的。
但是,作為高級的我們,就用高級的封裝,有了火柴誰還燧木取火,233333
復合型命令綁定
通常情況下,我們的命令調用者直接調用我們的命令,但是有些時候,我們需要從外部(比如其他的視圖或父視圖)的控件調用該命令,那麽就需要一個CompositeCommand。
CompositeCommand是一個由多個子命令組成的命令。它提供了執行子命令的所有關聯方法(Execute和CanExecute)的功能,當所有子命令的可執行狀態為True的時候CompositeCommand才可以被執行。
看下具體應用的代碼:
聲明:
public CompositeCommand SaveCommand { get; } = new CompositeCommand();
註冊子命令:
SaveCommand.RegisterCommand(UpdateCommand);
取消註冊:
SaveCommand.UnregisterCommand(UpdateCommand);
從PRISM開始學WPF(六)MVVM(二)Command?