從基礎元件 ViewModelBase 到完成一個基本的範例
實施 MVVM(Model-View-VeiwModel) 設計模式一般第一步就在程式解決方案中新增一個類別 ViewModelBase
聽名字就知道之後的 XXXXViewModel 都會是繼承這個類別的!
ViewModelBase 的重點是實作 INotifyPropertyChanged 介面,作為響應 Property 有變化時的對應處理
基本就是通知 UI(View) 上跟這個 Property 綁定的元件跟著變化,或是通知數據處理模組(Model)跟著做對應的處理
以下是我會用的 ViewModelBase 例子,MVVM_Sample 要改成自己的命名空間啊!(要沿用這個命名空間也行啦 XD)
//using System;
//using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace MVVM_Sample.ViewModel
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void SetValue<T>(ref T property, T value, [CallerMemberName] string propertyName = null)
{
if (property != null)
{
if (property.Equals(value))
{
return;
}
}
property = value;
OnPropertyChanged(propertyName);
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region -- Debugging Aides --
//protected virtual bool ThrowOnInvalidPropertyName { get; private set; }
//[Conditional("DEBUG")]
//[DebuggerStepThrough]
//public void VerifyPropertyName(string propertyName)
//{
// // Verify that the property name matches a real, public, instance property on this object.
// if (TypeDescriptor.GetProperties(this)[propertyName] == null)
// {
// string msg = "Invalid property name: " + propertyName;
// if (this.ThrowOnInvalidPropertyName)
// throw new Exception(msg);
// else
// Debug.Fail(msg);
// }
//}
#endregion -- Debugging Aides --
}
}
哈~或許有人會問那接註記掉的部分是啥吧?那是要 Debug 時確認響應的 Property 是正確的 Property 用的
不過現在寫 ViewModelBase 會用 [CallerMemberName] 這個 Attribute 就不會錯了,為表懷念還是留著 XD (使用的話就要用到 System 跟 System.Diagnostics 這兩個命名空間)
接著上個使用這基礎類別的範例~
XXModel 部分
namespace MVVM_Sample.Model
{
class XXModel
{
public string Path { get; set; }
}
}
XXViewModel 部分 (別忘了加入 Model 的命名空間)
using MVVM_Sample.Model;
namespace MVVM_Sample.ViewModel
{
public class XXViewModel : ViewModelBase
{
private static XXModel file { get; set; }
public string FilePath
{
get
{
return file.Path;
}
set
{
if (file.Path != value)
{
file.Path = value;
OnPropertyChanged();
}
}
}
}
}
這例子多一個判斷式來決定是否要改變 file.Path 這 Property
XXView 部分 (把後面 Mode=TwoWay 刪除也行,但我習慣能確定的屬性都寫清楚的 XD)
<TextBox Name="txtPath" Text="{Binding FilePath, Mode=TwoWay}"/>
也別忘了要把 ViewModel 對應到 View 的 DataContext,方法有兩種:
(方法一)在 View 的 xaml 下設定
<Page.DataContext>
<vm:XXViewModel/>
</Page.DataContext>
P.S. 我這個 View 是 Page
別忘了要加上 ViewModel 的命名空間
<Page x:Class="MVVM.View.XXView"
......
xmlns:vm="clr-namespace:MVVM.ViewModel" <-- 加上這行才能設定 <vm:XXViewModel/>
......>
(方法二)在 View 的 xaml.cs 下設定
public XXView()
{
InitializeComponent();
this.DataContext = XXViewModel;
}
到此基本大功告成~
只要任何地方改動到 FilePath 這 Property,就可以看到 UI 上也會更著改變,或是改變 TextBox 上的字串,XXModel 的 Path 也會跟著改變~完結灑花~