最近在研究學習Swift,蘋果希望它迅速取代復雜的Objective-C開發,引發了一大堆熱潮去學它,放眼望去各個培訓機構都已打着Swift開發0基礎快速上手的招牌了。不過我覺得,等同於無C++基礎上手學習C#一樣,即使將來OC被淘汰,那也是N年之后的事情,如果真的要做IOS開發,趁現在Swift才剛開始,花那么幾個月去了解一下OC絕對是一件有幫助的事情。
扯遠了,我前幾天剛接觸到一個叫做mvvm的框架,發現很有意思,帶着學習的態度來寫點東西,不足之處一起研究。還有一個很重要的原因,我發現不少同學學習WPF的時候的思維和Windows Form是完全一樣的,也就是說為什么用WPF而不用WinForm對於他們來說僅僅是:WPF的UI好看!
下面是WPF的一個簡介:
Windows Presentation Foundation(WPF)是美國微軟公司推出.NET Framework 3.0及以后版本的組成部分之一,它是一套基於XML、.NET Framework、矢量繪圖技術的展示層開發框架,微軟視其為下一代用戶界面技術。
WPF使用一種新的XAML(eXtensible Application Markup Language)語言來開發界面,這將把界面開發以及后台邏輯很好的分開,降低了耦合度,使用戶界面設計師與程序開發者能更好的合作,降低維護和更新的成本。
注意上面的說明,XAML的使用就是為了降低耦合度。那么我們不得不說說WinForm和WPF的區別了。
1.WinForm更新UI的操作是通過后台操作UI名,即ID來完成的。WPF是通過數據Binding來實現UI更新的。
2.WinForm響應用戶操作的方式是事件Event。WPF是通過命令(Command)Binding的方式。
所以說,從你寫的第一個WPF的Hello World開始,你就要轉變思路了!而不是很多人做的那種給按鈕添加事件,點擊觸發然后抱怨和過去的Winform沒啥區別一點都不好用。。。
上面又扯遠了。
好了,開始寫第一個MVVM框架。
定義一個NotificationBase類,這個類的作用是實現了INotifyPropertyChanged接口,目的是綁定數據屬性。實現了它這個接口,數據屬性發生變化后才會去通知UI。如果想在數據屬性發生變化前知道,需要實現INotifyPropertyChanging接口。
1 using System.ComponentModel; 2 3 namespace mvvw框架示例 4 { 5 class NotificationBase : INotifyPropertyChanged 6 { 7 public event PropertyChangedEventHandler PropertyChanged; 8 9 public void RaisePropertyChanged(string propertyName) 10 { 11 if (this.PropertyChanged != null) 12 { 13 this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 14 } 15 } 16 } 17 }
OK,下一步。
同樣實現了數據屬性的可Binding,用來響應用戶UI操作的命令也該有了。定義DelegateCommand類。目的是綁定命令屬性。這個類的作用是實現了ICommand接口,WPF中實現了ICommand接口的類,才能作為命令綁定到UI。
using System.Windows.Input; namespace mvvw框架示例 { class DelegateCommand : ICommand { //A method prototype without return value. public Action<object> ExecuteCommand = null; //A method prototype return a bool type. public Func<object, bool> CanExecuteCommand = null; public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { if (CanExecuteCommand != null) { return this.CanExecuteCommand(parameter); } else { return true; } } public void Execute(object parameter) { if (this.ExecuteCommand != null) this.ExecuteCommand(parameter); } public void RaiseCanExecuteChanged() { if (CanExecuteChanged != null) { CanExecuteChanged(this, EventArgs.Empty); } } } }
開始定義Model類。一個屬性成員"Now Time",它就是數據屬性,繼承自NotificationBase類,所以數據屬性具有通知功能,它改變后,會知道通知UI更新。一個方法“PrintNowTime”,用來改變屬性“Now Time”的值,它通過命令的方式相應UI事件。
namespace mvvw框架示例 { class Model : NotificationBase { private string _NowTime = "Now Time"; public string NowTime { get { return _NowTime; } set { _NowTime = value; this.RaisePropertyChanged("Now Time"); } } public void PrintNowTime(object obj) { this.NowTime += "Now Time :" + System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + System.Environment.NewLine; } } }
定義ViewModel類。定義了一個命令屬性"PrintCmd",聚合了一個Model對象"model"。這里的關鍵是,給PrintCmd命令指定響應命令的方法是model對象的“PrintNowTime”方法。
using System; namespace mvvw框架示例 { class ViewModel { public DelegateCommand PrintCmd { get; set; } public Model model { get; set; } public ViewModel() { this.model = new Model(); this.PrintCmd = new DelegateCommand(); this.PrintCmd.ExecuteCommand = new Action<object>(this.model.PrintNowTime); } } }
定義View。Binding一個model中的NowTime屬性到TextBlock的Text和PrintCmd命令到按鈕的Command。
<Window x:Class="mvvw框架示例.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <StackPanel VerticalAlignment="Center" > <TextBlock Text="{Binding model.NowTime}" Height="208" TextWrapping="WrapWithOverflow"></TextBlock> <Button Command="{Binding PrintCmd}" Height="60" Width="100">Print Time</Button> </StackPanel> </Grid> </Window>
上面的{Binding Model.NowTime}也可以寫成{Binding Path = NowTime},是一個意思,前者更直觀。
最后需要在MainWindowx.xaml.cs中加上this.DataContext = new ViewModel();表明MainWindowx.xaml這個UI層的數據和命令指定為從ViewModel獲得。
運行結果: