WPF – MVVM (三)
做到這邊,我們已經做了很大部分的分離了,但是實際上,我們還有一個地方還沒處理,那就是放在View那邊的邏輯,也就是按下Button時的事件,所以我們這邊再進一步的去處理。
移除View裡面的邏輯
首先我們先把View裡面的邏輯移除,並把它放到ViewModel裡面去,所以我們先將View裡面的東西移除掉,現在裡面真的是空空沒有東西了。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WPFMVVM3 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } }
接下來我們來看看移到ViewModel產生了甚麼變化。
邏輯移到ViewModel
到這邊,我相信大家就會產生一個疑問,那View裡面的按鈕按下後,要怎樣去呼叫ViewModel裡面的東西呢??其實我們還是會使用一個Binding的方式,只是這次Binding的是一個ICommand的型別;接下來我們繼續處理ViewModel,這次在ViewModel加了一個ICommand型別的參數UpdateTitleNmae,他會回傳一個實作ICommand的RelayCommand實體,並且傳入兩個方法UpdateTitleExecute,CanUpdateTitleExecute ( 沒錯,不要懷疑,傳入進去的是方法)。等下我們會建立RelayCommand類別,到時候就會看到,另外UpdateTitleExecute這個方法裡面定義著要處理的邏輯,也就是從View搬過來的邏輯;而CanUpdateTitleExecute代表著是否可以執行此方法,因為我們這邊一定都會讓此方法( UpdateTitleExecute )可以動作,所以CanUpdateTitleExecute就直接回傳True。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.Windows.Input; namespace WPFMVVM3 { //實作InotifyPropertyChanged public class PostsViewModel : INotifyPropertyChanged { public Posts posts{ get; set;} public event PropertyChangedEventHandler PropertyChanged; //定義一個ICommand型別的參數,他會回傳實作ICommand介面的RelayCommand類別。 public ICommand UpdateTitleName { get { return new RelayCommand(UpdateTitleExecute, CanUpdateTitleExecute); } } public PostsViewModel() { posts = new Posts { postsText = "", postsTitle = "Unknown" }; } public string PostsTitle { get { return posts.postsTitle; } set { if (posts.postsTitle != value) { posts.postsTitle = value; RaisePropertyChanged("postsTitle"); } } } //產生事件的方法 private void RaisePropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } //更新Title,原本放在View那邊的邏輯,藉由繫結的方式來處理按下Button的事件。 void UpdateTitleExecute() { PostsTitle = "SkyMVVM"; } //定義是否可以更新Title bool CanUpdateTitleExecute() { return true; } } }
這樣,ViewModel就完成了,接下來是處理RelayCommand。
撰寫RelayCommand
RelayCommand是實作ICommand的類別,一開始我們就可以看到定義了Func和Action,這兩個就是用來參考到剛剛傳入進來的兩個方法,並進行了一些的處理。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Input; using System.Diagnostics; namespace WPFMVVM3 { public class RelayCommand :ICommand { readonly Func_canExecute; readonly Action _execute; public RelayCommand(Action execute) : this(execute, null) { } public RelayCommand(Action execute, Func canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } public event EventHandler CanExecuteChanged { add { if (_canExecute != null) CommandManager.RequerySuggested += value; } remove { if (_canExecute != null) CommandManager.RequerySuggested -= value; } } [DebuggerStepThrough] public Boolean CanExecute(Object parameter) { return _canExecute == null ? true : _canExecute(); } public void Execute(Object parameter) { _execute(); } } }
最後,我們必須重新調整XMAL。
調整XMAL
最後的一個動作,我們將Button的Click屬性拿掉了,改成Command屬性,並將之Binding到ViewModel的UpdateTitleName屬性,就完成了。
<Window x:Class="WPFMVVM3.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WPFMVVM3" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <!-- 實例化PostViewModel --> <local:PostsViewModel /> </Window.DataContext> <Grid> <Label Content="{Binding PostsTitle}" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" /> <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="145,13,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding UpdateTitleName}" /> </Grid> </Window>
以上就完成了!
結尾
到這邊就算是手工打造MVVM的一個段落了,其實現在有許多的Framework可以幫我們處理一些繁雜的事物,但如果能了解原理,我相信會更有幫助,所以這次用了循序漸進的方式,來記錄這些內容,也希望能給大家一點幫助!
參考資料
- [http://www.codeproject.com/KB/WPF/MVVMMadeSimple.aspx](http://www.codeproject.com/KB/WPF/MVVMMadeSimple.aspx)
- [http://www.codeproject.com/KB/WPF/MVVMQuickTutorial.aspx](http://www.codeproject.com/KB/WPF/MVVMQuickTutorial.aspx)
- [http://csharperimage.jeremylikness.com/2010/04/model-view-viewmodel-mvvm-explained.html](http://csharperimage.jeremylikness.com/2010/04/model-view-viewmodel-mvvm-explained.html)