Mvvm-view-viewmodel-communication
MVVM –ビュー/ViewModel通信
この章では、MVVMアプリケーションに対話性を追加する方法と、ロジックをきれいに呼び出す方法を学習します。 また、MVVMパターンの中心である疎結合と適切な構造化を維持することにより、これらすべてが行われることもわかります。 これをすべて理解するために、まずコマンドについて学習しましょう。
コマンドを介したView/ViewModel通信
コマンドパターンは十分に文書化されており、数十年にわたって頻繁にデザインパターンを使用しています。 このパターンには、呼び出し側と受信側の2つの主なアクターがあります。
View and ViewModel Communication
呼び出し側
- 呼び出し側は、いくつかの命令型ロジックを実行できるコードです。
- 通常、ユーザーがUIフレームワークのコンテキストで操作するのはUI要素です。
- アプリケーション内の別の場所にあるロジックコードの別のチャンクである可能性があります。
受信機
- レシーバーは、呼び出し側が起動したときに実行するためのロジックです。
- MVVMのコンテキストでは、受信者は通常、呼び出す必要があるViewModelのメソッドです。
これら2つの間に障害層があります。これは、呼び出し側と受信側が互いについて明示的に知る必要がないことを意味します。 これは通常、呼び出し側に公開されるインターフェース抽象化として表され、そのインターフェースの具体的な実装はレシーバーを呼び出すことができます。
コマンドと、それらを使用してViewとViewModelの間で通信する方法を学習する簡単な例を見てみましょう。 この章では、前の章と同じ例を続けます。
StudentView.xamlファイルには、ViewModelからの学生データを接続するListBoxがあります。 次に、リストボックスから生徒を削除するためのボタンを追加しましょう。
重要なことは、ICommandに接続するためのコマンドプロパティがあるため、ボタン上のコマンドの操作が非常に簡単であることです。
そのため、次のコードに示すように、ICommandを持ち、ボタンのコマンドプロパティからバインドするViewModelのプロパティを公開できます。
<Button Content = "Delete"
Command = "{Binding DeleteCommand}"
HorizontalAlignment = "Left"
VerticalAlignment = "Top"
Width = "75"/>
プロジェクトに新しいクラスを追加して、ICommandインターフェイスを実装します。 以下は、ICommandインターフェイスの実装です。
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();
}
}
}
}
ご覧のとおり、これはICommandの単純な委任実装であり、1つはexecuteMethodに、もう1つは作成時に渡すことができるcanExecuteMethodに2つのデリゲートを持っています。
上記の実装では、2つのオーバーロードされたコンストラクターがあります。1つはexecuteMethod専用で、もう1つはexecuteMethodとI canExecuteMethodの両方です。
StudentView ModelクラスにMyICommandタイプのプロパティを追加しましょう。 次に、StudentViewModelにインスタンスを構築する必要があります。 2つのパラメーターを取るMyICommandのオーバーロードされたコンストラクターを使用します。
public MyICommand DeleteCommand { get; set;}
public StudentViewModel() {
LoadStudents();
DeleteCommand = new MyICommand(OnDelete, CanDelete);
}
次に、OnDeleteメソッドとCanDeleteメソッドの実装を追加します。
private void OnDelete() {
Students.Remove(SelectedStudent);
}
private bool CanDelete() {
return SelectedStudent != null;
}
また、ユーザーがListBoxからSelected Itemを削除できるように、新しいSelectedStudentを追加する必要があります。
private Student _selectedStudent;
public Student SelectedStudent {
get {
return _selectedStudent;
}
set {
_selectedStudent = value;
DeleteCommand.RaiseCanExecuteChanged();
}
}
以下は、ViewModelクラスの完全な実装です。
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では、SelectStudentプロパティにバインドするListBoxにSelectedItemプロパティを追加する必要があります。
<ListBox ItemsSource = "{Binding Students}" SelectedItem = "{Binding SelectedStudent}"/>
完全な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: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>
上記のコードをコンパイルして実行すると、次のウィンドウが表示されます。
View and ViewModel Communication MainWindow1
削除ボタンが無効になっていることがわかります。 アイテムを選択すると有効になります。
View and ViewModel Communication MainWindow2
いずれかの項目を選択して、削除を押すと。 選択した項目リストが削除され、削除ボタンが再び無効になることがわかります。
View and ViewModel Communication MainWindow3
理解を深めるために、上記の例を段階的に実行することをお勧めします。