WPF MVVM架構
談到WPF ,最多人提到就是用MVVM這種架構去寫軟體。
雖然也可以用傳統WindowForm的那種事件方式去做控制項的相關操作
但是MVVM模式更貼近WPF的設計
MVVM是由Model ViewModel View三個部分組成
Model 通常是放不加處理的類別,像是poco類別。
public class 產品Model
{
public string 品號{get;set;}
public string 單位{get;set;}
}
ViewModel則是用來做顯示介面View的Binding
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
}
public class 產品ViewModel : ViewModelBase
{
private 產品Model;
public 產品ViewModel()
{
產品Model= new 產品Model();
}
public string 品號
{
get { return 產品Model.品號;}
set { 產品Model.品號=value; OnPropertyChanged(); }
}
public string 單位
{
get { return 產品Model.單位;}
set { 產品Model.單位=value; OnPropertyChanged(); }
}
}
我在寫的時候會用一個母類別ViewModelBase讓所有ViewModel繼承,這樣可以省略上方OnPropertyChanged的程式碼
OnPropertyChanged的功能是,在程式中,可以完全不用使用到前方的控件,只需要專注的將商業邏輯寫在ViewModel中
透過改變ViewModel中的屬性,會呼叫到OnPropertyChanged,讓前方的View知道,後方的ViewModel的值已經改變了
需要更新顯示的資料。
而不僅僅是這樣,像是之後的Command的Binding,若是有更改都需要透過OnPropertyChanged去做通知的動作。
也就是說,當你採用MVVM模式時,若是更改了ViewModel中的值
而View沒有變化,那就是沒有去呼叫OnPropertyChanged
或是Binding失敗。
程式碼中的[CallerMemberName] 忘記是多少以後版本才有
這個特性的用法是,會自動以呼叫這個方法的屬性當參數傳入方法中
WPF中的特色,透過Binding跟Command可以有效的將前端的View跟ViewModel做有效的連接,乾淨的切割。
這樣設計界面的可以透過VisualStudio中的資料來源,用ViewModel 快速產生出前端的View
只要不去調整到Binding的連結,就可以隨意地變更前端控件的樣式。
前方的產品View ,XAML大概會長這樣,最重要的是要在程式碼中設定DataContext或是在Xaml中設定
<Page x:Name="產品View">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="品號" Grid.Row="0" Grid.Column="0"></TextBlock>
<TextBox Text="{Binding 品號}" Grid.Row="0" Grid.Column="1"></TextBox>
<TextBlock Text="單位" Grid.Row="1" Grid.Column="0"></TextBlock>
<TextBox Text="{Binding 單位}" Grid.Row="1" Grid.Column="1"></TextBox>
</Grid>
</Page>
public partial class 產品表 : Page
{
產品ViewModel viewModel;
public 產品表()
{
InitializeComponent();
viewModel = new 產品ViewModel;
this.DataContext = viewModel;
}
}
整個架構就是這樣,在XAML中使用Binding跟ViewModel中的屬性名稱做連結,在程式碼中設定DataContext,就可以達到後方跟前方的分離。
若是要顯示預設值,可以在ViewModel中的建構式直接設定屬性,程式運行時,一開始顯示的就是建構式中設定的值。
以上的介紹是用單一產品。
若是要用DataGrid 或List,做一個主從式的顯示。
可以新增一個View,ViewModel跟View的關係是很緊密的,View要怎麼顯示,那對應的ViewModel就要有對應的屬性。
public class 產品表主從式ViewModel : ViewModelBase
{
public 產品表主從式ViewModel()
{
//設定屬性預設值,或從其他資料來源取的資料
}
public 產品主檔ViewModel 產品主檔
{
get
{
return _產品主檔;
}
set
{
_產品主檔 = value;
OnPropertyChanged();
}
}
private 產品主檔ViewModel _產品主檔;
public ObservableCollection<產品表ViewModel> 明細
{
get
{
return _明細;
}
set
{
_明細 = value;
OnPropertyChanged();
}
}
private ObservableCollection<產品表ViewModel> 明細
}
上方的程式碼,是做一個簡單的主從式ViewModel,包含兩個原先的ViewModel。
這邊要注意的是 ObservableCollection 泛型的類別裡的屬性一定要有呼叫OnPropertyChanged,不然改變值的時候,不會顯示在View上。
有任何改進的意見及問題歡迎傳送到電子郵件
電子郵件:momo16542@gmail.com