MVVM - Menghubungkan ViewModel
Dalam bab ini, kita akan membahas cara menghubungkan ViewModel. Ini adalah kelanjutan dari bab terakhir di mana kita membahas konstruksi View pertama. Nah, bentuk konstruksi pertama selanjutnya adalah ameta-pattern yang dikenal sebagai ViewModelLocator. Ini adalah pola semu dan dilapisi di atas pola MVVM.
Dalam MVVM, setiap Tampilan harus dihubungkan ke ViewModel-nya.
ViewModelLocator adalah pendekatan sederhana untuk memusatkan kode dan lebih banyak memisahkan tampilan.
Artinya, ia tidak harus mengetahui secara eksplisit tentang tipe ViewModel dan cara membangunnya.
Ada sejumlah pendekatan berbeda untuk menggunakan ViewModelLocator, tetapi di sini kami menggunakan yang paling mirip dengan yang merupakan bagian dari kerangka PRISM.
ViewModelLocator menyediakan cara standar, konsisten, deklaratif, dan digabungkan secara longgar untuk melakukan konstruksi tampilan pertama yang mengotomatiskan proses menghubungkan ViewModel ke Tampilan. Gambar berikut mewakili proses tingkat tinggi ViewModelLocator.
Step 1 - Cari tahu tipe View mana yang sedang dibangun.
Step 2 - Identifikasi ViewModel untuk jenis Tampilan tertentu tersebut.
Step 3 - Bangun ViewModel itu.
Step 4 - Setel Views DataContext ke ViewModel.
Untuk memahami konsep dasarnya, mari kita lihat contoh sederhana ViewModelLocator dengan melanjutkan contoh yang sama dari bab sebelumnya. Jika Anda melihat file StudentView.xaml, Anda akan melihat bahwa kami telah menghubungkan ViewModel secara statis.
Sekarang seperti yang ditunjukkan pada program berikut, komen kode XAML ini juga hapus kode dari Code-behind.
<UserControl x:Class = "MVVMDemo.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:MVVMDemo.Views"
xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModel"
mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300">
<!--<UserControl.DataContext>
<viewModel:StudentViewModel/>
</UserControl.DataContext>-->
<Grid>
<StackPanel HorizontalAlignment = "Left">
<ItemsControl ItemsSource = "{Binding Path = Students}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>
<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</UserControl>
Sekarang mari kita buat folder baru VML dan tambahkan ViewModelLocator kelas publik baru yang akan berisi satu properti terlampir (properti ketergantungan) AutoHookedUpViewModel seperti yang ditunjukkan pada kode berikut.
public static bool GetAutoHookedUpViewModel(DependencyObject obj) {
return (bool)obj.GetValue(AutoHookedUpViewModelProperty);
}
public static void SetAutoHookedUpViewModel(DependencyObject obj, bool value) {
obj.SetValue(AutoHookedUpViewModelProperty, value);
}
// Using a DependencyProperty as the backing store for AutoHookedUpViewModel.
//This enables animation, styling, binding, etc...
public static readonly DependencyProperty AutoHookedUpViewModelProperty =
DependencyProperty.RegisterAttached("AutoHookedUpViewModel",
typeof(bool), typeof(ViewModelLocator), new PropertyMetadata(false,
AutoHookedUpViewModelChanged));
Dan sekarang Anda dapat melihat definisi properti lampirkan dasar. Untuk menambahkan perilaku ke properti, kita perlu menambahkan pengendali kejadian yang diubah untuk properti ini yang berisi proses otomatis menghubungkan ViewModel untuk Tampilan. Kode untuk melakukan ini adalah sebagai berikut -
private static void AutoHookedUpViewModelChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
if (DesignerProperties.GetIsInDesignMode(d)) return;
var viewType = d.GetType();
string str = viewType.FullName;
str = str.Replace(".Views.", ".ViewModel.");
var viewTypeName = str;
var viewModelTypeName = viewTypeName + "Model";
var viewModelType = Type.GetType(viewModelTypeName);
var viewModel = Activator.CreateInstance(viewModelType);
((FrameworkElement)d).DataContext = viewModel;
}
Berikut adalah implementasi lengkap kelas ViewModelLocator.
using System;
using System.ComponentModel;
using System.Windows;
namespace MVVMDemo.VML {
public static class ViewModelLocator {
public static bool GetAutoHookedUpViewModel(DependencyObject obj) {
return (bool)obj.GetValue(AutoHookedUpViewModelProperty);
}
public static void SetAutoHookedUpViewModel(DependencyObject obj, bool value) {
obj.SetValue(AutoHookedUpViewModelProperty, value);
}
// Using a DependencyProperty as the backing store for AutoHookedUpViewModel.
//This enables animation, styling, binding, etc...
public static readonly DependencyProperty AutoHookedUpViewModelProperty =
DependencyProperty.RegisterAttached("AutoHookedUpViewModel",
typeof(bool), typeof(ViewModelLocator), new
PropertyMetadata(false, AutoHookedUpViewModelChanged));
private static void AutoHookedUpViewModelChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
if (DesignerProperties.GetIsInDesignMode(d)) return;
var viewType = d.GetType();
string str = viewType.FullName;
str = str.Replace(".Views.", ".ViewModel.");
var viewTypeName = str;
var viewModelTypeName = viewTypeName + "Model";
var viewModelType = Type.GetType(viewModelTypeName);
var viewModel = Activator.CreateInstance(viewModelType);
((FrameworkElement)d).DataContext = viewModel;
}
}
}
Hal pertama yang harus dilakukan adalah menambahkan namespace sehingga kita bisa mendapatkan tipe ViewModelLocator di root proyek kita. Kemudian pada elemen rute yang merupakan tipe tampilan, tambahkan properti AutoHookedUpViewModel dan setel ke true.
xmlns:vml = "clr-namespace:MVVMDemo.VML"
vml:ViewModelLocator.AutoHookedUpViewModel = "True"
Berikut adalah implementasi lengkap file StudentView.xaml.
<UserControl x:Class = "MVVMDemo.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:MVVMDemo.Views"
xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModel"
xmlns:vml = "clr-namespace:MVVMDemo.VML"
vml:ViewModelLocator.AutoHookedUpViewModel = "True"
mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300">
<!--<UserControl.DataContext>
<viewModel:StudentViewModel/>
</UserControl.DataContext>-->
<Grid>
<StackPanel HorizontalAlignment = "Left">
<ItemsControl ItemsSource = "{Binding Path = Students}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>
<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</UserControl>
Ketika kode di atas dikompilasi dan dijalankan, Anda akan melihat bahwa ViewModelLocator menghubungkan ViewModel untuk View tersebut.
Hal utama yang perlu diperhatikan tentang ini adalah tampilan tidak lagi digabungkan dengan jenis ViewModel-nya atau bagaimana cara membuatnya. Itu semua telah dipindahkan ke lokasi pusat di dalam ViewModelLocator.