MVVM - View / ViewModel İletişim
Bu bölümde, MVVM uygulamalarına nasıl etkileşim ekleneceğini ve mantığın temiz bir şekilde nasıl çağrılacağını öğreneceğiz. Ayrıca tüm bunların, MVVM modelinin kalbi olan gevşek bağlantı ve iyi yapılanma sağlanarak yapıldığını göreceksiniz. Tüm bunları anlamak için önce komutları öğrenelim.
Komutlar aracılığıyla Model İletişimini Görüntüle / Görüntüle
Komut kalıbı iyi bir şekilde belgelenmiştir ve birkaç on yıldır tasarım modelini sıklıkla kullanır. Bu örüntüde iki ana aktör vardır, çağıran ve alan.
Invoker
Çağıran, bazı zorunlu mantığı çalıştırabilen bir kod parçasıdır.
Tipik olarak, bir UI çerçevesi bağlamında kullanıcının etkileşime girdiği bir UI öğesidir.
Bu, uygulamanın başka bir yerindeki başka bir mantık kodu parçası olabilir.
Alıcı
Alıcı, çağıran kişi ateşlediğinde yürütülmesi amaçlanan mantıktır.
MVVM bağlamında, alıcı genellikle ViewModel'inizde çağrılması gereken bir yöntemdir.
Bu ikisi arasında, çağıran ile alıcının birbirini açıkça bilmesine gerek olmadığı anlamına gelen bir engelleme katmanınız var. Bu tipik olarak, çağırıcıya maruz kalan bir arayüz soyutlaması olarak temsil edilir ve bu arayüzün somut bir uygulaması alıcıyı arayabilir.
Komutları ve bunları View ile ViewModel arasında iletişim kurmak için nasıl kullanacağınızı öğreneceğiniz basit bir örneğe bakalım. Bu bölümde, son bölümdeki aynı örnekle devam edeceğiz.
StudentView.xaml dosyasında, öğrenci verilerini ViewModel'den bağlayan bir ListBox var. Şimdi bir öğrenciyi ListBox'tan silmek için bir düğme ekleyelim.
Önemli olan, düğme üzerindeki komutlarla çalışmanın çok kolay olmasıdır çünkü bir ICommand'e bağlanmak için bir komut özelliğine sahiptirler.
Böylece, ViewModel'imizde bir ICommand'e sahip olan ve aşağıdaki kodda gösterildiği gibi butonun command özelliğinden ona bağlanan bir özelliği açığa çıkarabiliriz.
<Button Content = "Delete"
Command = "{Binding DeleteCommand}"
HorizontalAlignment = "Left"
VerticalAlignment = "Top"
Width = "75" />
Projenize ICommand arayüzünü uygulayacak yeni bir sınıf ekleyelim. Aşağıda, ICommand arayüzünün uygulanması yer almaktadır.
using System;
using System.Windows.Input;
namespace MVVMDemo {
public class MyICommand : ICommand {
Action _TargetExecuteMethod;
Func<bool> _TargetCanExecuteMethod;
public MyICommand(Action executeMethod) {
_TargetExecuteMethod = executeMethod;
}
public MyICommand(Action executeMethod, Func<bool> canExecuteMethod){
_TargetExecuteMethod = executeMethod;
_TargetCanExecuteMethod = canExecuteMethod;
}
public void RaiseCanExecuteChanged() {
CanExecuteChanged(this, EventArgs.Empty);
}
bool ICommand.CanExecute(object parameter) {
if (_TargetCanExecuteMethod != null) {
return _TargetCanExecuteMethod();
}
if (_TargetExecuteMethod != null) {
return true;
}
return false;
}
// Beware - should use weak references if command instance lifetime
is longer than lifetime of UI objects that get hooked up to command
// Prism commands solve this in their implementation
public event EventHandler CanExecuteChanged = delegate { };
void ICommand.Execute(object parameter) {
if (_TargetExecuteMethod != null) {
_TargetExecuteMethod();
}
}
}
}
Gördüğünüz gibi, bu ICommand'in basit bir delege uygulamasıdır; burada biri executeMethod ve diğeri de canExecuteMethod için inşa sırasında aktarılabilen iki delegemiz var.
Yukarıdaki uygulamada, biri yalnızca executeMethod ve diğeri hem executeMethod hem de I canExecuteMethod için olmak üzere iki aşırı yüklenmiş kurucu vardır.
StudentView Model sınıfına MyICommand türünün bir özelliğini ekleyelim. Şimdi StudentViewModel'de bir örnek oluşturmamız gerekiyor. İki parametre alan MyICommand'ın aşırı yüklenmiş yapıcısını kullanacağız.
public MyICommand DeleteCommand { get; set;}
public StudentViewModel() {
LoadStudents();
DeleteCommand = new MyICommand(OnDelete, CanDelete);
}
Şimdi OnDelete ve CanDelete yöntemlerinin uygulamasını ekleyin.
private void OnDelete() {
Students.Remove(SelectedStudent);
}
private bool CanDelete() {
return SelectedStudent != null;
}
Ayrıca, kullanıcının Seçilen Öğeyi ListBox'tan silebilmesi için yeni bir SelectedStudent eklememiz gerekir.
private Student _selectedStudent;
public Student SelectedStudent {
get {
return _selectedStudent;
}
set {
_selectedStudent = value;
DeleteCommand.RaiseCanExecuteChanged();
}
}
Aşağıda ViewModel sınıfının tam uygulaması verilmiştir.
using MVVMDemo.Model;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System;
namespace MVVMDemo.ViewModel {
public class StudentViewModel {
public MyICommand DeleteCommand { get; set;}
public StudentViewModel() {
LoadStudents();
DeleteCommand = new MyICommand(OnDelete, CanDelete);
}
public ObservableCollection<Student> Students {
get;
set;
}
public void LoadStudents() {
ObservableCollection<Student> students = new ObservableCollection<Student>();
students.Add(new Student { FirstName = "Mark", LastName = "Allain" });
students.Add(new Student { FirstName = "Allen", LastName = "Brown" });
students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" });
Students = students;
}
private Student _selectedStudent;
public Student SelectedStudent {
get {
return _selectedStudent;
}
set {
_selectedStudent = value;
DeleteCommand.RaiseCanExecuteChanged();
}
}
private void OnDelete() {
Students.Remove(SelectedStudent);
}
private bool CanDelete() {
return SelectedStudent != null;
}
}
}
StudentView.xaml'de, SelectStudent özelliğine bağlanacak bir ListBox'a SelectedItem özelliğini eklememiz gerekir.
<ListBox ItemsSource = "{Binding Students}" SelectedItem = "{Binding SelectedStudent}"/>
Tam xaml dosyası aşağıdadır.
<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:data = "clr-namespace:MVVMDemo.Model"
xmlns:vml = "clr-namespace:MVVMDemo.VML"
vml:ViewModelLocator.AutoHookedUpViewModel = "True"
mc:Ignorable = "d"
d:DesignHeight = "300" d:DesignWidth = "300">
<UserControl.Resources>
<DataTemplate DataType = "{x:Type data:Student}">
<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>
</UserControl.Resources>
<Grid>
<StackPanel Orientation = "Horizontal">
<ListBox ItemsSource = "{Binding Students}"
SelectedItem = "{Binding SelectedStudent}"/>
<Button Content = "Delete"
Command = "{Binding DeleteCommand}"
HorizontalAlignment = "Left"
VerticalAlignment = "Top"
Width = "75" />
</StackPanel>
</Grid>
</UserControl>
Yukarıdaki kod derlendiğinde ve çalıştırıldığında, aşağıdaki pencereyi göreceksiniz.
Silme düğmesinin devre dışı olduğunu görebilirsiniz. Herhangi bir öğeyi seçtiğinizde etkinleştirilecektir.
Herhangi bir öğeyi seçip sil tuşuna bastığınızda. Seçilen öğe listesinin silindiğini ve sil düğmesinin tekrar devre dışı bırakıldığını göreceksiniz.
Daha iyi anlamak için yukarıdaki örneği adım adım uygulamanızı öneririz.