WPF MVVM從入門到精通3:數據綁定express
WPF MVVM從入門到精通5:PasswordBox的綁定ide
WPF MVVM從入門到精通6:RadioButton等一對多控件的綁定this
這一部分咱們要作的事情,是把點擊登陸按鈕的事件也在ViewModel裏實現。若不是用MVVM模式,可能XAML文件裏是這樣的:xml
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登陸" Width="200" Height="30" Click="Button_Click"/>
而跟XAML文件相關的CS文件裏則是這樣的:
private void Button_Click(object sender, RoutedEventArgs e) { //業務處理邏輯代碼 }
如此一來,前端和後端的代碼又耦合在一塊兒了。其實,命令和事件都是能夠綁定的,就像數據同樣。
咱們先來了解一下命令。ICommand是全部命令的接口,它主要完成兩件事情,這個命令可否被執行,以及執行命令。
event EventHandler CanExecuteChanged; public bool CanExecute(object parameter); public void Execute(object parameter);
例如當用戶名爲空時,咱們可能會禁用按鈕。當登陸按鈕跟一個命令綁定在一塊兒時,CanExecute會不斷被執行,若是返回false,按鈕的IsEnabled屬性也會被置爲false。
通常狀況下,咱們須要繼承ICommand接口來進行開發。
using System; using System.Windows.Input; namespace LoginDemo.ViewModel.Common { /// <summary> /// 命令基類 /// </summary> public class BaseCommand : ICommand { public event EventHandler CanExecuteChanged { add { if (_canExecute != null) { CommandManager.RequerySuggested += value; } } remove { if (_canExecute != null) { CommandManager.RequerySuggested -= value; } } } public bool CanExecute(object parameter) { if (_canExecute == null) { return true; } return _canExecute(parameter); } public void Execute(object parameter) { if (_execute != null && CanExecute(parameter)) { _execute(parameter); } } private Func<object, bool> _canExecute; private Action<object> _execute; public BaseCommand(Action<object> execute, Func<object, bool> canExecute) { _execute = execute; _canExecute = canExecute; } public BaseCommand(Action<object> execute) : this(execute, null) { } } }
BaseCommand的功能很簡單,就是執行命令前先判斷一下命令能不能執行。
而後咱們就能夠綁定命令了,在後端這樣寫:
private BaseCommand clickLoginCommand; public BaseCommand ClickLoginCommand { get { if(clickLoginCommand==null) { clickLoginCommand = new BaseCommand(new Action<object>(o => { //執行登陸邏輯 })); } return clickLoginCommand; } }
前端這樣寫:
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登陸" Width="200" Height="30" Command="{Binding ClickLoginCommand}"/>
點擊按鈕執行登陸邏輯的代碼就這樣完成了。但不要急着複製代碼,由於咱們不打算使用命令。
咱們知道,對於按鈕的操做,不必定是點擊,多是鼠標劃過,多是鼠標右擊。那Command觸發的是什麼呢?就是點擊,沒有其餘了。對於其餘控件,例如是輸入框,Command又表明什麼呢?文本改變事件能用Command嗎?這些問題讓咱們感到困惑,因此通常在項目中,我都只會使用事件,而不會使用命令(即便是單擊事件)。
BaseCommand這個類還能夠留着,咱們後面還須要使用的。在引入事件以前,咱們須要先引用一個dll:System.Windows.Interactivity.dll。這個dll並非.NET Framework的標配,它是Blend的一個類庫。能夠在擴展的程序集裏找到:
若是沒有找到(我安裝VS2017後就沒有找到),須要安裝如下庫纔有:
好了,引用了System.Windows.Interactivity.dll後,咱們就能夠開始講事件了。
有些事件是有參數的,例如鼠標移動這個事件,會帶上鼠標的位置。但咱們以前使用的命令,默認傳入的參數是null。爲了可以傳遞參數,咱們須要先定義一個事件基類:
using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; namespace LoginDemo.ViewModel.Common { /// <summary> /// 事件命令 /// </summary> public class EventCommand : TriggerAction<DependencyObject> { protected override void Invoke(object parameter) { if (CommandParameter != null) { parameter = CommandParameter; } if (Command != null) { Command.Execute(parameter); } } /// <summary> /// 事件 /// </summary> public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommand), new PropertyMetadata(null)); /// <summary> /// 事件參數,若是爲空,將自動傳入事件的真實參數 /// </summary> public object CommandParameter { get { return (object)GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(EventCommand), new PropertyMetadata(null)); } }
如今,咱們能夠在ViewModel裏增長以下代碼:
private BaseCommand loginClick; /// <summary> /// 登陸事件 /// </summary> public BaseCommand LoginClick { get { if(loginClick==null) { loginClick = new BaseCommand(new Action<object>(o => { //執行登陸邏輯 })); } return loginClick; } }
而後在XAML文件裏,先加入i這個命名空間:xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity",而後修改按鈕的代碼:
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登陸" Width="200" Height="30"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <c:EventCommand Command="{Binding LoginClick}"/> </i:EventTrigger> </i:Interaction.Triggers> </Button>
上面的代碼指出,Click這個事件,綁定到了LoginClick這個屬性。當咱們點擊按鈕的時候,LoginClick裏面的Action就會被執行。