MVVM 不僅是 MVC 的變體,更是 WPF 獨特技術特性(Binding、Command、Attached Property)與團隊協作模式(設計師/開發者分離)共同催生的產物。本文從問題根源切入,闡述 ViewModel 如何充當「抽象視圖」、為何單元測試是驗證 ViewModel 的最佳消費者,並介紹 Attached Behavior 解決事件綁定盲區。
Binding 實現資料雙向同步,Command 封裝操作邏輯,皆可直接寫在 XAML,Code-behind 可幾乎為空。DataContext、Converter、Command 定義;"View and Unit Test are just two different types of ViewModel consumers." — Josh Smith
並非所有控制項事件都有對應 Command(如 Loaded、MouseEnter)。Attached Behavior 以附加屬性封裝事件訂閱,於屬性變更時掛載/解除事件處理器,並在處理器中呼叫 ViewModel 的 Command 或方法。
// 範例:Loaded 事件綁定 Command
public static class LoadedBehavior
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(LoadedBehavior),
new PropertyMetadata(null, OnCommandChanged));
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var fe = d as FrameworkElement;
if (fe == null) return;
fe.Loaded -= OnLoaded;
if (e.NewValue != null) fe.Loaded += OnLoaded;
}
private static void OnLoaded(object sender, RoutedEventArgs e)
{
var fe = sender as FrameworkElement;
var cmd = fe.GetValue(CommandProperty) as ICommand;
cmd?.Execute(null);
}
}
XAML 使用:
<Button local:LoadedBehavior.Command="{Binding InitCommand}" />
MVVM 核心在於:以 Binding 替代 Code-behind 的資料同步,以 Command 替代事件處理器,以 Attached Behavior 補足事件綁定缺口。ViewModel 成為純邏輯單元,設計師專注 XAML,開發者專注 ViewModel,雙方以契約(屬性/命令名稱)協作,單元測試守護品質。這正是 WPF 團隊開發模式轉型的關鍵推手。