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)