SlideShare a Scribd company logo
わんくま同盟 東京勉強会 #90
きっと怖くないMVVM&MVPVM
暁 紫電
@akatukisiden
わんくま同盟 東京勉強会 #90
自己紹介
• HN:暁 紫電
• Twitter: @akatukisiden
• 本名:伊藤 伸男
• フリーランス プログラマー
• 使用言語
–C++
–C#
–C++/CLI
わんくま同盟 東京勉強会 #90
アジェンダ
• 目的
• MVVMとは
• ViewとViewModelの分離
• 細かいことは程々にして
実装してみた
• MVVMでの画面遷移
• MVVMまとめ
• MVPVMとは
• とりあえず実装してみた
• MVPVMでの画面遷移
• MVPVMまとめ
• まとめ
わんくま同盟 東京勉強会 #90
このセッションの目的
• 細かいことは置いておいて、
とりあえずMVVM,MVPVMっぽい形で
プログラムを書けるようにする。
• MVVMでのナビゲーション手法について理解する
• MVPVMでのナビゲーションについて理解する
• 疎結合、密結合、コードビハインドなどの用語を
できる限り使わずに説明する
わんくま同盟 東京勉強会 #90
MVVM(Model-View-ViewModel)とは
• 最近流行りのUIアーキテクチャパターン
• いくつかの理由によりXAML系フレームワーク
(WPF,Silverlight,WinRT)では必須と言われている
• UI(View)とビジネスロジック(Model)のあいだにViewModelを
置くことで二つを分離する。
• View・ViewModel間のやり取りはデータバインドを用いる
わんくま同盟 東京勉強会 #90
View
• ユーザーインターフェース
• UIへの出力とUIからの入力を担当する。
• FrameworkElementの派生クラス
• XAMLの記述+対応する(partial )class
• Viewの必要な情報を保持公開
• Viewからの入力やコマンドを処理し
Modelを呼び出す
ViewModel Model
• ビジネスロジック
• プログラムの中核となる処理
• ViewとViewModel以外の部分
わんくま同盟 東京勉強会 #90
ViewとViewModelの分離(疎結合と密結合)
• MVVMの説明などでよく使われる用語、
疎結合と密結合
• ViewとViewModelを密結合にならないようにし、
疎結合に保つと良いらしい
• 「疎結合に保つ」「密結合になってしまっている」という記述
はよく見るが具体的にどのような状況を疎結合・密結合と
言うのか書かれていることはあまりない
• もしかしたら一般的な用語で説明する必要もないのかもし
れないが、
少なくとも自分にとってMVVM/MVPVMの文脈でしか聞か
ない言葉
わんくま同盟 東京勉強会 #90
さまざまな資料の記述を総合すると
• View/ViewModelで互いのインスタンスや
型名を直接扱うと密結合
• データバインドを使えば疎結合
わんくま同盟 東京勉強会 #90
具体的に何が許されて何が許されないのか
• 直接触れると密結合
– ViewはViewModelが特定の型であることに依存してはいけない
– ViewでViewModelのインスタンスを扱ってはいけない
– ViewModelはViewが特定の型であることに依存してはいけない
– ViewModelでViewのインスタンスを扱ってはいけない
• データバインドは疎結合
– ViewはViewModelがINotifyPropertyChangedを
実装していることに依存してよい。
– ViewはViewModelが特定の名前のプロパティを
持つことに依存してよい
わんくま同盟 東京勉強会 #90
厳密にいうとこれもだめかもしれない
<Window x:Class="MVVM1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300"
>
<Window.DataContext >
<MainViewModel />
</Window.DataContext>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
View内でViewModelの型を
扱っている
わんくま同盟 東京勉強会 #90
細かいことは置いておいて
• MainWindowのイベントハンドラに全部の処理を書いた状態
から
少しずつ修正してMVVMの形にしてみようと思います。
• テキストボックス、ラベル、ボタンを配置し、ボタンを押すとテ
キストボックスに入力した文字列を加工してラベルに出力する
アプリを作る
※小さすぎてMVVMにする意味がないとか言わないでください
意味がなくてもとりあえず始めることが大事です。
わんくま同盟 東京勉強会 #90
STEP1:全部イベントハンドラ等に記述
わんくま同盟 東京勉強会 #90
MainWindow.xaml
<Window x:Class=“Step1.MainWindow”
// 略
Title="MainWindow" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition />
</Grid.RowDefinitions>
<Button Content="Button" Grid.Row="0“ HorizontalAlignment="Center"
VerticalAlignment="Center" Width="120" Click="Button_Click"/>
<TextBox Name="textBox1" Grid.Row="1“ HorizontalAlignment="Center"
VerticalAlignment="Center“ Height="23" Width="120" />
<Border Grid.Row="2" BorderThickness="1" BorderBrush="Black"
HorizontalAlignment="Center" VerticalAlignment="Center" >
<Label Name="label1" HorizontalAlignment="Center" VerticalAlignment="Center"
Width="120"/>
</Border>
</Grid>
</Window>
わんくま同盟 東京勉強会 #90
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object
sender,RoutedEventArgs e)
{
// なんか複数の関数が絡んだ複雑な処理
string f1 = Func1(textBox1.Text);
string f2 = Func2(f1);
string f3 = Func3(f2);
label1.Content = f3;
}
//頭にBをつける
private string Func1(string input)
{ return “B” + input; }
//末尾にEをつける
private string Func2(string input)
{ return input+"E"; }
//順番をひっくり返す。
private string Func3(string input)
{
var rev = input.Reverse().ToArray();
string ret = new string(rev);
return ret;
}
}
わんくま同盟 東京勉強会 #90
STEP2:
MainWindow.xaml.csは
イベントハンドラだけにしたいので
処理内容を別クラスに移す
C++で云うところの
pImpl
わんくま同盟 東京勉強会 #90
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private MainWindowImpl impl = new MainWindowImpl();
private void Button_Click(object sender, RoutedEventArgs e)
{
label1.Content = impl.Logic(textBox1.Text);
}
}
処理を移すための別クラス
別クラスに移した処理の
呼び出し
わんくま同盟 東京勉強会 #90
MainWindowImpl.cs
public class MainWindowImpl
{
public string Logic(string input)
{
string f1 = Func1(input);
string f2 = Func2(f1);
string f3 = Func3(f2);
return f3;
}
private string Func1(string input)
{ return "B" + input;}
private string Func2(string input)
{ return input + "E";}
private string Func3(string input)
{
var rev = input.Reverse().ToArray();
string ret = new string(rev);
return ret;
}
}
わんくま同盟 東京勉強会 #90
STEP3:
入出力(引数/戻り値)が多く必要になると
記述が大変なので
データバインディングを使ってみる
わんくま同盟 東京勉強会 #90
MainWindow.xaml
<Window x:Class=“Step3.MainWindow"
//略
Title="MainWindow" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition
/></Grid.RowDefinitions>
<Button Content="Button" Grid.Row="0" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="120" Click="Button_Click"/>
<TextBox Name="textBox1" Grid.Row="1" HorizontalAlignment="Center"
VerticalAlignment="Center" Height="23" Width="120" Text="{Binding Input}“
<Border Grid.Row="2" BorderThickness="1" BorderBrush="Black"
HorizontalAlignment="Center" VerticalAlignment="Center" >
<Label Name=“label1” HorizontalAlignment=“Center”
VerticalAlignment=“Center” Width=“120“ Content="{Binding Output}" />
</Border>
</Grid>
</Window>
わんくま同盟 東京勉強会 #90
MainWindow.xaml.cs
public partial class MainWindow : Window
{
// コントロールからの入力、出力をデータバインドに変換
private MainWindowImpl impl = new MainWindowImpl();
public MainWindow()
{
InitializeComponent();
this.DataContext = impl;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
impl.Logic();
}
}
バインド対象の設定
入出力はバインドしたので
引数・戻り値なしになっている
わんくま同盟 東京勉強会 #90
MainWindowImpl.cs
public class MainWindowImpl:
BindingSourceBase
{
public string input_;
public string Input
{
get { return input_; }
set
{
if (input_ != value)
{
input_ = value;
OnPropertyChanged("Input");
}
}
}
public void Logic()
{
string f1 = Func1(Input);
string f2 = Func2(f1);
string f3 = Func3(f2);
Output = f3;
}
private string Func1(string input){略}
private string Func2(string input){略}
private string Func3(string input){略}
}
public string output_;
public string Output
{
get { return output_; }
set
{
if (output_ != value)
{
output_ = value;
OnPropertyChanged("Output");
}
}
}
わんくま同盟 東京勉強会 #90
BindingSourceBase
public class
BindingSourceBase:System.ComponentModel.INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyname)
{
if(PropertyChanged != null)
{
PropertyChanged(this,new
PropertyChangedEventArgs(propertyname));
}
}
}
わんくま同盟 東京勉強会 #90
STEP4:
引数・戻り値なしなら直接呼出したいので、
イベントハンドラをImplに移動する。
わんくま同盟 東京勉強会 #90
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private MainWindowImpl impl = new MainWindowImpl();
public MainWindow()
{
InitializeComponent();
// バインド対象の設定
this.DataContext = impl;
Button1.Click += impl.Button_Click;
}
}
Clickイベントにimplクラスの
関数を登録
わんくま同盟 東京勉強会 #90
MainWindow.xaml
<Window x:Class=“Step3.MainWindow"
//略
Title="MainWindow" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition
/></Grid.RowDefinitions>
<Button Content=“Button” Grid.Row=“0” HorizontalAlignment=“Center”
VerticalAlignment=“Center” Width=“120” />
<TextBox Name="textBox1" Grid.Row="1" HorizontalAlignment="Center"
VerticalAlignment="Center" Height="23" Width="120" Text="{Binding Input}" />
<Border Grid.Row="2" BorderThickness="1" BorderBrush="Black"
HorizontalAlignment="Center" VerticalAlignment="Center" >
<Label Name="label1" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="120“
Content="{Binding Output}" />
</Border>
</Grid>
</Window>
イベントの登録部分を削除
わんくま同盟 東京勉強会 #90
MainWindowImpl.cs
public class MainWindowImpl:BindingSourceBase
{
public void Button_Click(object sender,RoutedEventArgs e)
{
this.Logic();
}
public string input_;
public string Input
{ get { return input_; } set { 略 } }
public string output_;
public string Output
{ get { return output_; } set { 略 } }
public void Logic()
{
string f1 = Func1(Input);
string f2 = Func2(f1);
string f3 = Func3(f2);
Output = f3;
}
private string Func1(string input){略}
private string Func2(string input){略}
private string Func3(string input){略}
}
Button.Clickイベントから呼
び出される
ビジネスロジック
わんくま同盟 東京勉強会 #90
STEP5:
Implクラスにデータバインドと
ビジネスロジック両方があるとじゃまなので
ビジネスロジックをさらに別クラスへ移動する。
わんくま同盟 東京勉強会 #90
MainWindowImpl.cs
public class MainWindowImpl:BindingSourceBase
{
private BusinessLogic BL = new BusinessLogic();
public void Button_Click(object sender, RoutedEventArgs e)
{
Output = BL.Logic(Input);
}
public string input_;
public string Input { get { return input_; } set {略} }
public string output_;
public string Output { get { return output_; } set {略}}
}
わんくま同盟 東京勉強会 #90
BusinessLogic.cs
public class BusinessLogic
{
public string Logic(string Input)
{
string f1 = Func1(Input);
string f2 = Func2(f1);
string f3 = Func3(f2);
return f3;
}
private string Func1(string input){略}
private string Func2(string input){略}
private string Func3(string input){略}
}
関数が増えてクラスが肥大化するので
あれば
外部とのインターフェースになる関数
だけ残して内部実装はさらに別のクラ
スに移した方がいいかも
わんくま同盟 東京勉強会 #90
STEP6:XAML環境ではロジックも
コマンドとしてバインドできるので
イベントハンドラからコマンドバインディングに変更する
※WinFormsでもFormクラス等にActionプロパティを作り
On○○メソッド等でアクションを発火するようにすれば可能
わんくま同盟 東京勉強会 #90
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private MainWindowImpl impl = new MainWindowImpl();
public MainWindow()
{
InitializeComponent();
// バインド対象の設定
this.DataContext = impl;
// Button1.Click += impl.Button_Click;
}
}
削除
わんくま同盟 東京勉強会 #90
MainWindow.xaml
<Window x:Class=“Step6.MainWindow"
//略
Title="MainWindow" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition
/></Grid.RowDefinitions>
<Button Content="Button" Grid.Row="0" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="120" Command="{Binding MainCommand}“ />
<TextBox Name="textBox1" Grid.Row="1" HorizontalAlignment="Center"
VerticalAlignment="Center" Height="23" Width="120" Text="{Binding Input}" />
<Border Grid.Row="2" BorderThickness="1" BorderBrush="Black"
HorizontalAlignment="Center" VerticalAlignment="Center" >
<Label Name="label1" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="120" Content="{Binding Output}" />
</Border>
</Grid>
</Window>
わんくま同盟 東京勉強会 #90
MainWindowImpl.cs
public class MainWindowImpl:BindingSourceBase
{
private BusinessLogic BL = new BusinessLogic();
public ICommand MainCommand{get;set;}
public MainWindowImpl()
{
MainCommand = new Microsoft.TeamFoundation.
MVVM.RelayCommand(() => { Output = BL.Logic(Input); });
}
public string input_;
public string Input { get { return input_; } set { 略} }
public string output_;
public string Output { get { return output_; } set{ 略 } }
ロジックのバインド用のコマン
ド
コマンドの中身を作成。
わんくま同盟 東京勉強会 #90
(LastSTEP:)クラス名の変更
• MainWindowImpl → MainViewModel
• BindingSourceBase → ViewModelBase
• BussinesLogic → MainModel
わんくま同盟 東京勉強会 #90
とりあえずMVVM完成
※但し画面遷移無し
わんくま同盟 東京勉強会 #90
画面遷移とは
• 表示されているデータでは無く、
コントロール自体を変更する
• 主にユーザーコントロールやパネルの切り替え
わんくま同盟 東京勉強会 #90
MVVMでの画面遷移手法
• ViewModelの型に応じてコントロールを切り替える方法。
– データテンプレート
• 表示するデータの型に応じて表示方法を変える機能
• 指定した型のデータの表示方法を定義する。
• コントロールの切り替えロジックを呼び出し、
新しいコントロールに新しいViewModelを関連付ける手法。
– ViewModelからViewを呼び出す。
• 逆方向バインディングコマンド
• Behavior
• TriggerAndAction
わんくま同盟 東京勉強会 #90
とりあえずサンプル作る
• ボタンを押すことで背景色の異なる(赤・青)二つのユーザーコ
ントロールを切り替える。
• Modelは省略
• 切り替えロジック呼び出しのサンプルは
逆方向バインディングコマンドで実装
わんくま同盟 東京勉強会 #90
共通部分 (赤)
<UserControl x:Class="NavigationCommon.UCRed“
(略)
d:DesignHeight="150" d:DesignWidth="150"
Background="Red">
<Grid>
<TextBlock HorizontalAlignment="Center“
VerticalAlignment="Center" Text="{Binding Text}" />
</Grid>
</UserControl>
public partial class UCRed : UserControl
{
public UCRed()
{ InitializeComponent(); }
}
public class
RedViewModel:ViewModelBase
{
private string text = "赤";
public string Text
{
set{
if (text != value)
{
text = value;
OnPropertyChanged("Text");
}
}
get{ return text; }
}
}
View ViewModel
わんくま同盟 東京勉強会 #90
共通部分 (青)
<UserControl x:Class="NavigationCommon.UCBlue“
(略)
d:DesignHeight="150" d:DesignWidth="150"
Background=“Blue">
<Grid>
<TextBlock HorizontalAlignment="Center“
VerticalAlignment="Center" Text="{Binding Text}" />
</Grid>
</UserControl>
public partial class UCBlue : UserControl
{
public UCBlue()
{ InitializeComponent(); }
}
public class
BlueViewModel:ViewModelBase
{
private string text = “青";
public string Text
{
set{
if (text != value)
{
text = value;
OnPropertyChanged("Text");
}
}
get{ return text; }
}
}
View ViewModel
わんくま同盟 東京勉強会 #90
データテンプレート
わんくま同盟 東京勉強会 #90
View
<Window x:Class="MainWindow"
(略)
Title="MainWindow" >
<Window.Resources>
<DataTemplate DataType="{x:Type
navi:RedViewModel}">
<navi:UCRed x:Name="RedUC" />
</DataTemplate>
<DataTemplate DataType=“{x:Type
navi:BlueViewModel}”>
<navi:UCBlue x:Name="BlueUC" />
</DataTemplate>
</Window.Resources>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Name="ParentGrid">
<ContentControl Name="ContentControl“
Content="{Binding ChildViewModel}" />
</Grid>
<Grid Grid.Column="1" >
<Button Content="Button“ Command="{Binding
NavigationCommand}" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="75" Height="25"
/>
</Grid>
</Grid>
</Window>
ViewModelの型を直接扱ってい
る。
public partial class MainWindow : Window
{ public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
} }
ViewModelを表示しようとしている
わんくま同盟 東京勉強会 #90
ViewModel
public class MainViewModel:ViewModelBase
{
ViewModelBase childVM;
public ViewModelBase ChildViewModel
{ get { return childVM; } set {略} }
ICommand nCommand;
public ICommand NavigationCommand
{ get { return nCommand; } set { 略 } }
public MainViewModel(){ NavigateRed(); }
private void NavigateRed()
{
ChildViewModel = new RedViewModel();
NavigationCommand = new
Microsoft.TeamFoundation.
MVVM.RelayCommand( (p) =>{NavigateBlue();});
}
private void NavigateBlue()
{
ChildViewModel = new BlueViewModel();
NavigationCommand = new
Microsoft.TeamFoundation.
MVVM.RelayCommand( (p) =>{ NavigateRed();} );
}
}
もう一度ボタンを押したら
元の色に戻るように
コマンドをリセット
データテンプレートで表示する子ViewModel
表示するViewModelを変更
わんくま同盟 東京勉強会 #90
逆方向バインディングコマンド
わんくま同盟 東京勉強会 #90
Command UserControl
public class DependencyCommandControl :
Control
{
public DependencyCommandControl():base(){ }
static DependencyCommandControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(DependencyCommandControl),
new FrameworkPropertyMetadata(
typeof(DependencyCommandControl))
);
}
public static readonly
DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command“,
typeof(ICommand),
typeof(DependencyCommandControl)
);
public ICommand Command
{
set { SetValue(CommandProperty, value); }
get { return
(ICommand)GetValue(CommandProperty); }
}
}
XAML上で扱うには依存関係プロパティである必要があるので
依存関係プロパティ化したICommandを持つ
カスタムコントロールを作る
わんくま同盟 東京勉強会 #90
View
<Window x:Class="MainWindow"
(略)
Title="MainWindow">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/><ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Name="ParentGrid“ >
</Grid>
<Grid Grid.Column="1" >
<Button Content="Button" Command="{Binding NavigationCommand}"
HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="25"/>
<DependencyCommandControl x:Name="CommandHolder“
Command="{Binding
Mode=OneWayToSource,Path='SouceToTargetCommand' }" />
</Grid>
</Grid>
</Window>
ボタンクリック時に呼ばれる順方向コマンド
ViewModelから呼ばれる逆方向コマンド逆方向バインディング
カスタムコントロール
わんくま同盟 東京勉強会 #90
ViewModel
public class MainViewModel:ViewModelBase
{
ViewModelBase childVM;
public ViewModelBase ChildViewModel{get;set}
ICommand navigationcommand;
public ICommand NavigationCommand
{ get { return navigationcommand; }set {略} }
ICommand sttCommand;
public ICommand SouceToTargetCommand
{ get { return sttCommand; } set{ 略 } }
public MainViewModel() { NavigateToRed(); }
ボタンクリックから呼び出される
(順方向)コマンド
ViewModelからViewを呼び出すための
逆方向バインディングをするコマンド
わんくま同盟 東京勉強会 #90
ViewModel
private void NavigateToRed()
{
ChildViewModel = new RedViewModel();
if (SouceToTargetCommand != null)
SouceToTargetCommand.
Execute(ChildViewModel);
NavigationCommand = new
Microsoft.TeamFoundation.
MVVM.RelayCommand(
(p) => { NavigateToBlue(); });
}
private void NavigateToBlue()
{
ChildViewModel = new BlueViewModel();
if (SouceToTargetCommand != null)
SouceToTargetCommand.
Execute(ChildViewModel);
NavigationCommand = new
Microsoft.TeamFoundation.
MVVM.RelayCommand(
(p) => { NavigateToRed(); } );
}
}
子コントロール用の新しいViewModelを作成、
コマンドでViewに送る
もう一度ボタンを押したら元に戻すために順方向コマンドをリセット
わんくま同盟 東京勉強会 #90
View
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var mainVM = new MainViewModel();
ChangeToRed(mainVM.ChildViewModel);
this.DataContext = mainVM;
}
private void ChangeToBlue(object vm)
{
ParentGrid.Children.Clear();
var newPanel = new UCBlue();
newPanel.DataContext = vm;
ParentGrid.Children.Add(newPanel);
CommandHolder.Command = new
Microsoft.TeamFoundation.
MVVM.RelayCommand(ChangeToRed);
}
private void ChangeToRed(object vm)
{
ParentGrid.Children.Clear();
var newPanel = new UCRed();
newPanel.DataContext = vm;
ParentGrid.Children.Add(newPanel);
CommandHolder.Command = new
Microsoft.TeamFoundation.
MVVM.RelayCommand(ChangeToBlue);
}
}
ViewModelから受け取った新ViewModelを
Viewで直接扱っている
新しいViewを作成
新しいViewModelを受け取る
わんくま同盟 東京勉強会 #90
MVVMまとめ
• View と ViewModel が互いを扱わなくていいはずのMVVMで
画面遷移を行おうとするとViewでViewModelを扱ってまう。
→ そもそもMVVMにはXAML環境に適応するための
最低限必要な機能しかなく、
画面遷移の存在を前提にしていないのでは?
• MVVMの利点(≒XAML環境への適応≒データバインディング)
を
生かしつつ画面遷移の存在を前提とするパターンが必要
→ MVPVM
わんくま同盟 東京勉強会 #90
MVPVM(Model-View-Presenter-ViewModel)とは
• MVPとMVVMを合体させたもの
• View,ViewModelの上にPresenterを置き、そこで、画面遷
移、
ナビゲーションを管理する。
• ViewModelに書かれていたロジックをPresenterに移動する
ことでViewModelにはバインド対象となるプロパティのみが
含まれるようにする。
• ViewModelにロジックが含まれなくなるので使いまわしが容
易になる。
わんくま同盟 東京勉強会 #90
View
• ユーザーインターフェース
• UIへの出力とUIからの入力を担当する。
• FrameworkElementの派生クラス
• XAMLの記述+対応する partial class
Model
• ビジネスロジック/プログラムの中核となる処理
• ViewとViewModel(とPresenter)以外の部分
わんくま同盟 東京勉強会 #90
• Viewの必要な情報を保持公開
• Viewから受け取った入力やコマンドををPresenterに渡す
(MVPVM)
• Viewからの入力やコマンドを処理しModelを呼び出す
(MVVM)
ViewModel
わんくま同盟 東京勉強会 #90
• View,ViewModelを保持、その接続を管理する
• ViewModelから受け取った入力やコマンドを処理しModel
を呼び出す。
• ViewModelのプロパティを通してViewを変更する。
• ナビゲーション・画面遷移の管理
(子View,子ViewModelの作成、接続)
Presenter
わんくま同盟 東京勉強会 #90
とりあえず組んでみた
• MVVMの時と同じようにテキストボックスから入力、加工して
ラベルに出力するアプリ
※画面遷移がないのに
MVPVMで組む必要性がないとか言わないように
わんくま同盟 東京勉強会 #90
View
<Window x:Class="MVPVM1.MainWindow"
(略)
Title="MainWindow" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition />
</Grid.RowDefinitions>
<Button Content="Button" Grid.Row="0" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="120" Command="{Binding MainCommand}"/>
<TextBox Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"
Height="23" Width="120" Text="{Binding Input}" />
<Border Grid.Row="2" BorderThickness="1" BorderBrush="Black"
HorizontalAlignment="Center" VerticalAlignment="Center" >
<Label HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding
Output}" Width="120" />
</Border>
</Grid>
</Window>
public partial class MainWindow :
Window
{
public MainWindow()
{ InitializeComponent(); }
}
わんくま同盟 東京勉強会 #90
ViewModel
class MainViewModel:ViewModelBase
{
public MainViewModel()
{ }
public override void Cleanup()
{
MainCommand = null;
base.Cleanup();
}
private ICommand _mainCommand;
public ICommand MainCommand { set{略} get{ return _mainCommand;} }
private string _input;
public string Input { set{略} get{ return _input;} }
private string _output;
public string Output { set{略} get{ return _output;} }
}
Commandの中身の定義
Modelの関数の呼び出しコードがなくなっている
わんくま同盟 東京勉強会 #90
PresenterBase
class PresenterBase<TView,TViewModel>
where TView:System.Windows.FrameworkElement
where TViewModel:ViewModelBase
{
public PresenterBase(TView view, TViewModel viewmodel)
{
View = view;
ViewModel = viewmodel;
}
public TView View { set; get; }
public TViewModel ViewModel { set; get; }
public virtual void Initialize()
{ View.DataContext = ViewModel; }
DataContextの設定
View-ViewModelの接続
public virtual void CleanUp()
{
if (ViewModel != null)
{
ViewModel.Cleanup();
ViewModel = null;
}
if (View != null)
{
View.DataContext = null;
View = null;
}
}
}
View-ViewModel間の接続解除
View,ViewModelの参照解除
引数の
View,ViewModel
メンバに代入
わんくま同盟 東京勉強会 #90
Presenter
class MainPresenter:PresenterBase<MainWindow,MainViewModel>
{
MainModel model = new MainModel();
public MainPresenter(MainWindow view,MainViewModel viewmodel)
:base(view,viewmodel){ }
public override void Initialize()
{
ViewModel.MainCommand =
new Microsoft.TeamFoundation.MVVM.RelayCommand(
()=>{ViewModel.Output = model.Logic(ViewModel.Input); });
base.Initialize();
}
public override void CleanUp() { base.CleanUp(); }
}
ViewModelのコマンドの中身を作成
コンストラクタがViewとViewModelの
インスタンスを受け取る
Modelの関数の呼び出し。
Viewの操作はデータバインドした
ViewModelのプロパティを通して行う。
わんくま同盟 東京勉強会 #90
App.xaml
<Application x:Class="MVPVM1.App"
(略)
Startup="Application_Startup“
Exit="Application_Exit“
>
<Application.Resources>
</Application.Resources>
</Application>
public partial class App : Application
{
MainPresenter presenter ;
private void Application_Startup(object sender,
StartupEventArgs e)
{
var view =new MainWindow();
var viewmodel = new MainViewModel();
presenter = new MainPresenter(view, viewmodel);
presenter.Initialize();
view.Show();
}
private void Application_Exit(object sender, ExitEventArgs e)
{ presenter.CleanUp(); }
}
App.xaml.cs
StartupUri=“MainWindow.xaml” を削除
Startup,Exitを追加
アプリ起動時に、V,VM,Pを作成、
ウィンドウを表示
アプリ終了時にPresenterから全体をクリア
わんくま同盟 東京勉強会 #90
MVPVMでの画面遷移
• View,ViewModel両方を扱うことが出来る
Presenterに記述する
• MVVMではView,ViewModelの二か所に分割されていた
画面遷移ロジックをPresenter一つにまとめられるため
自然な形で実装することができる。
わんくま同盟 東京勉強会 #90
View
<Window x:Class="MVPVMNavigation.MainWindow"
(略)
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Name="ParentGrid" >
</Grid>
<Grid Grid.Column="1" >
<Button Content=“Button”
HorizontalAlignment=“Center” VerticalAlignment=“Center”
Command="{Binding NavigationCommand}" Width="75"
/>
</Grid>
</Grid>
</Window>
public partial class MainWindow
: Window
{
public MainWindow()
{ InitializeComponent(); }
}
Viewに画面遷移用のロ
ジックが存在しない
ボタンがクリックされた時に呼び出さ
れるコマンドのバインド
わんくま同盟 東京勉強会 #90
ViewModel
public class MainViewModel:ViewModelBase
{
ViewModelBase childVM;
public ViewModelBase ChildViewModel
{
get { return childVM; }
set {略}
}
ICommand navigationCommand;
public ICommand NavigationCommand
{
get { return navigationCommand; }
set {略}
}
public MainViewModel(){}
public override void Cleanup()
{
if (ChildViewModel != null)
{
NavigationCommand = null;
ChildViewModel.Cleanup();
ChildViewModel = null;
}
base.Cleanup();
}
}
子ViewModel
子Presenterからアクセスできるので
もしかしたら要らないかも
ボタンクリックで呼び出される
画面遷移用コマンド
各プロパティのクリア
わんくま同盟 東京勉強会 #90
子Presenter(赤,青)
public class RedPresenter
: PresenterBase<UCRed, RedViewModel>
{
public
RedPresenter(UCRed view, RedViewModel
viewmodel)
: base(view, viewmodel)
{ }
public override void Initialize()
{
base.Initialize();
}
public override void CleanUp()
{
base.CleanUp();
}
}
public class BluePresenter
:PresenterBase<UCBlue,BlueViewModel>
{
public
BluePresenter(UCBlue view, BlueViewModel
viewmodel)
: base(view, viewmodel)
{ }
public override void Initialize()
{
base.Initialize();
}
public override void CleanUp()
{
base.CleanUp();
}
}
わんくま同盟 東京勉強会 #90
MainPresenter(1)
public class MainPresenter: PresenterBase<MainWindow,MainViewModel>
{
public MainPresenter(MainWindow view,MainViewModel viewmodel)
:base(view,viewmodel){ }
public IPresenter ChildPresenter { get; set; }
public override void Initialize()
{
base.Initialize();
NavigateToRed();
}
public override void CleanUp()
{
ChildPresenter.CleanUp();
base.CleanUp();
}
子コントロール(赤・青)用の
Presenter
子Presenterの解放
わんくま同盟 東京勉強会 #90
MainPresenter(2)
private void NavigateToRed()
{
if (ChildPresenter != null)
{ ChildPresenter.CleanUp(); }
var v = new UCRed();
var vm = new RedViewModel();
var presenter = new RedPresenter(v, vm);
View.ParentGrid.Children.Clear();
View.ParentGrid.Children.Add(v);
ViewModel.ChildViewModel = vm;
ViewModel.NavigationCommand = new
Microsoft.TeamFoundation.MVVM.RelayCommand( (p) => {NavigateToBlue();} );
ChildPresenter = presenter;
ChildPresenter.Initialize();
);
新しいView,ViewModel,Presenter
の作成
次回ボタンクリック時に元の色に戻すた
めにコマンドをリセット
新しいViewをGridに追加
旧Presenterのクリア
わんくま同盟 東京勉強会 #90
MainPresenter(3)
private void NavigateToBlue()
{
if (ChildPresenter != null)
{ ChildPresenter.CleanUp(); }
var v = new UCBlue();
var vm = new BlueViewModel();
var presenter = new RedPresenter(v, vm);
View.ParentGrid.Children.Clear();
View.ParentGrid.Children.Add(v);
ViewModel.ChildViewModel = vm;
ViewModel.NavigationCommand = new
Microsoft.TeamFoundation.MVVM.RelayCommand( (p) => {NavigateToRed();} );
ChildPresenter = presenter;
ChildPresenter.Initialize();
);
新しいView,ViewModelPresenterの作
成
次回ボタンクリック時に元の色に戻すた
めにコマンドをリセット
新しいViewをGridに追加
旧Presenterのクリ
ア
わんくま同盟 東京勉強会 #90
MVPVMまとめ
• ViewModelはBinding対象になるプロパティのみを記述し
コマンドの中身はPresenterに記述する
• PresenterはView,ViewModelどちらも扱えるので
その二つに分けて記述していた画面遷移ロジックを
Presenter 1ヵ所に記述することができる。
→MVVMでは三ケ所すべてにロジックが含まれる可能性があったのが
MVPVMでは基本的にP,M の二か所に減る
• 何らかの事情(ActiveX,低スキル,etc…)によりViewがビジネスロジッ
クを持っている場合でもPresenterから直接呼べる
わんくま同盟 東京勉強会 #90
まとめ
• Viewとの入出力はバインディングで行い、
インターフェースになる関数だけ残して
実装は別クラスに移動することを繰り返せば
とりあえずMVVMの形にはなる
• PresenterでView,ViewModelを管理しViewModelのコマ
ンドの中身を
Presenterで作ればMVPVMになる。
• 一画面で完結するアプリならMVVMでもいいが、
ナビゲーション(画面遷移)を含む場合はMVPVMの方がオ
ススメ
わんくま同盟 東京勉強会 #90
今回扱わなかったこと
• XAML環境でデータバインディングが必須な理由
• コレクションコントロール
• エラー処理
• CommandのCanExecute()
• 非同期処理(Model)
• Viewに合わせた、ViewModel,Presenterそれぞれツリーの構
造

More Related Content

What's hot

オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門
増田 亨
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
Yoshitaka Kawashima
 
認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio
認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio
認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio
都元ダイスケ Miyamoto
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単に
Yoshifumi Kawai
 
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。 【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
日本マイクロソフト株式会社
 
データベース設計徹底指南
データベース設計徹底指南データベース設計徹底指南
データベース設計徹底指南
Mikiya Okuno
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコード
Shigenori Sagawa
 
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
NTT DATA Technology & Innovation
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
増田 亨
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
 
ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』
Yoshitaka Kawashima
 
Clojureの世界と実際のWeb開発
Clojureの世界と実際のWeb開発Clojureの世界と実際のWeb開発
Clojureの世界と実際のWeb開発
Tsutomu Yano
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っている
Koichi Tanaka
 
C#でもメタプログラミングがしたい!!
C#でもメタプログラミングがしたい!!C#でもメタプログラミングがしたい!!
C#でもメタプログラミングがしたい!!
TATSUYA HAYAMIZU
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
Takuto Wada
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについてkumake
 
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
Mikiya Okuno
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
土岐 孝平
 

What's hot (20)

オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 
認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio
認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio
認証の標準的な方法は分かった。では認可はどう管理するんだい? #cmdevio
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単に
 
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。 【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
 
データベース設計徹底指南
データベース設計徹底指南データベース設計徹底指南
データベース設計徹底指南
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコード
 
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』
 
Clojureの世界と実際のWeb開発
Clojureの世界と実際のWeb開発Clojureの世界と実際のWeb開発
Clojureの世界と実際のWeb開発
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っている
 
C#でもメタプログラミングがしたい!!
C#でもメタプログラミングがしたい!!C#でもメタプログラミングがしたい!!
C#でもメタプログラミングがしたい!!
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについて
 
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 

Viewers also liked

塹壕よりLivetとMVVM
塹壕よりLivetとMVVM塹壕よりLivetとMVVM
塹壕よりLivetとMVVM
Hiroshi Maekawa
 
WPF MVVM Review
WPF MVVM ReviewWPF MVVM Review
WPF MVVM Review
Takayuki Kondou
 
KnockoutJS勉強会 プロジェクトにmvvmを適用する狙い
KnockoutJS勉強会 プロジェクトにmvvmを適用する狙いKnockoutJS勉強会 プロジェクトにmvvmを適用する狙い
KnockoutJS勉強会 プロジェクトにmvvmを適用する狙い
Toshihiro Kawachi
 
今風なデスクトップアプリのモダンインストーラー開発
今風なデスクトップアプリのモダンインストーラー開発今風なデスクトップアプリのモダンインストーラー開発
今風なデスクトップアプリのモダンインストーラー開発
Kaoru Nakajima
 
ModelとViewに分ける設計 - #JSオジサン
ModelとViewに分ける設計 - #JSオジサンModelとViewに分ける設計 - #JSオジサン
ModelとViewに分ける設計 - #JSオジサン
Ginpei Takanashi
 
Windows アプリケーション開発 はじめに ~ Windows アプリケーション開発初学者の方向け Visual Studio を使ったアプリケーショ...
Windows アプリケーション開発はじめに ~ Windows アプリケーション開発初学者の方向けVisual Studio を使ったアプリケーショ...Windows アプリケーション開発はじめに ~ Windows アプリケーション開発初学者の方向けVisual Studio を使ったアプリケーショ...
Windows アプリケーション開発 はじめに ~ Windows アプリケーション開発初学者の方向け Visual Studio を使ったアプリケーショ...
Fujio Kojima
 
Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...
Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...
Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...
友太 渡辺
 
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみたADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
Narami Kiyokura
 
「Entity Framework Coreを使ってみる」 公開用
「Entity Framework Coreを使ってみる」 公開用「Entity Framework Coreを使ってみる」 公開用
「Entity Framework Coreを使ってみる」 公開用
ESM SEC
 
知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編Shota Baba
 
20分でできる!Xamarin.Forms入門
20分でできる!Xamarin.Forms入門20分でできる!Xamarin.Forms入門
20分でできる!Xamarin.Forms入門
Shinichi Hirauchi
 
IOS/Androidアプリの3つの大事な設計方針
IOS/Androidアプリの3つの大事な設計方針IOS/Androidアプリの3つの大事な設計方針
IOS/Androidアプリの3つの大事な設計方針Ken Morishita
 
リアクティブプログラミングとMVVMパターンについて
リアクティブプログラミングとMVVMパターンについてリアクティブプログラミングとMVVMパターンについて
リアクティブプログラミングとMVVMパターンについて
Hidenori Takeshita
 
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
慎一 古賀
 
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞いiOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
Ken Morishita
 
Xamarin.forms入門
Xamarin.forms入門Xamarin.forms入門
Xamarin.forms入門
一希 大田
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
増田 亨
 

Viewers also liked (18)

塹壕よりLivetとMVVM
塹壕よりLivetとMVVM塹壕よりLivetとMVVM
塹壕よりLivetとMVVM
 
WPF MVVM Review
WPF MVVM ReviewWPF MVVM Review
WPF MVVM Review
 
KnockoutJS勉強会 プロジェクトにmvvmを適用する狙い
KnockoutJS勉強会 プロジェクトにmvvmを適用する狙いKnockoutJS勉強会 プロジェクトにmvvmを適用する狙い
KnockoutJS勉強会 プロジェクトにmvvmを適用する狙い
 
MVVM入門
MVVM入門MVVM入門
MVVM入門
 
今風なデスクトップアプリのモダンインストーラー開発
今風なデスクトップアプリのモダンインストーラー開発今風なデスクトップアプリのモダンインストーラー開発
今風なデスクトップアプリのモダンインストーラー開発
 
ModelとViewに分ける設計 - #JSオジサン
ModelとViewに分ける設計 - #JSオジサンModelとViewに分ける設計 - #JSオジサン
ModelとViewに分ける設計 - #JSオジサン
 
Windows アプリケーション開発 はじめに ~ Windows アプリケーション開発初学者の方向け Visual Studio を使ったアプリケーショ...
Windows アプリケーション開発はじめに ~ Windows アプリケーション開発初学者の方向けVisual Studio を使ったアプリケーショ...Windows アプリケーション開発はじめに ~ Windows アプリケーション開発初学者の方向けVisual Studio を使ったアプリケーショ...
Windows アプリケーション開発 はじめに ~ Windows アプリケーション開発初学者の方向け Visual Studio を使ったアプリケーショ...
 
Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...
Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...
Xamarin と Visual Studio でまとめて作る iOS / Android / Windows アプリ ( Developers Summ...
 
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみたADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
 
「Entity Framework Coreを使ってみる」 公開用
「Entity Framework Coreを使ってみる」 公開用「Entity Framework Coreを使ってみる」 公開用
「Entity Framework Coreを使ってみる」 公開用
 
知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編
 
20分でできる!Xamarin.Forms入門
20分でできる!Xamarin.Forms入門20分でできる!Xamarin.Forms入門
20分でできる!Xamarin.Forms入門
 
IOS/Androidアプリの3つの大事な設計方針
IOS/Androidアプリの3つの大事な設計方針IOS/Androidアプリの3つの大事な設計方針
IOS/Androidアプリの3つの大事な設計方針
 
リアクティブプログラミングとMVVMパターンについて
リアクティブプログラミングとMVVMパターンについてリアクティブプログラミングとMVVMパターンについて
リアクティブプログラミングとMVVMパターンについて
 
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
 
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞いiOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
 
Xamarin.forms入門
Xamarin.forms入門Xamarin.forms入門
Xamarin.forms入門
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
 

Similar to T90 きっと怖くないmvvm & mvpvm

VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
Mr. Vengineer
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会Jumpei Ogawa
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
Akira Inoue
 
ATLに見る魔術
ATLに見る魔術ATLに見る魔術
ATLに見る魔術egtra
 
わんくまT78 mfcを始めようとしてみた
わんくまT78 mfcを始めようとしてみたわんくまT78 mfcを始めようとしてみた
わんくまT78 mfcを始めようとしてみた伸男 伊藤
 
Live Coding で学ぶ C# 7
Live Coding で学ぶ C# 7Live Coding で学ぶ C# 7
Live Coding で学ぶ C# 7
Takaaki Suzuki
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Akira Inoue
 
GoF デザインパターン 2009
GoF デザインパターン 2009GoF デザインパターン 2009
GoF デザインパターン 2009
miwarin
 
Pronama 0707 wf4
Pronama 0707 wf4Pronama 0707 wf4
Pronama 0707 wf4
Tomoyuki Obi
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11えぴ 福田
 
Jenkins x Kubernetesが簡単だと思ったら大変だった話
Jenkins x Kubernetesが簡単だと思ったら大変だった話Jenkins x Kubernetesが簡単だと思ったら大変だった話
Jenkins x Kubernetesが簡単だと思ったら大変だった話
Masaki Yamamoto
 
ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)
ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)
ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)
Takashi Yoshinaga
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~Akira Inoue
 
111008 silverlight square_datavalidation
111008 silverlight square_datavalidation111008 silverlight square_datavalidation
111008 silverlight square_datavalidationTakayoshi Tanaka
 
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0
Yuta Matsumura
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
Tatsuki SHIMIZU
 
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
Tomoharu ASAMI
 

Similar to T90 きっと怖くないmvvm & mvpvm (20)

VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
 
ATLに見る魔術
ATLに見る魔術ATLに見る魔術
ATLに見る魔術
 
わんくまT78 mfcを始めようとしてみた
わんくまT78 mfcを始めようとしてみたわんくまT78 mfcを始めようとしてみた
わんくまT78 mfcを始めようとしてみた
 
Live Coding で学ぶ C# 7
Live Coding で学ぶ C# 7Live Coding で学ぶ C# 7
Live Coding で学ぶ C# 7
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
 
GoF デザインパターン 2009
GoF デザインパターン 2009GoF デザインパターン 2009
GoF デザインパターン 2009
 
Pronama 0707 wf4
Pronama 0707 wf4Pronama 0707 wf4
Pronama 0707 wf4
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
Jenkins x Kubernetesが簡単だと思ったら大変だった話
Jenkins x Kubernetesが簡単だと思ったら大変だった話Jenkins x Kubernetesが簡単だと思ったら大変だった話
Jenkins x Kubernetesが簡単だと思ったら大変だった話
 
ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)
ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)
ARコンテンツ作成勉強会:C#ではじめようOpenCV(カラートラッキング編)
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
 
111008 silverlight square_datavalidation
111008 silverlight square_datavalidation111008 silverlight square_datavalidation
111008 silverlight square_datavalidation
 
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
 
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
 

Recently uploaded

CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料
Yuuitirou528 default
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
Matsushita Laboratory
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
CRI Japan, Inc.
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
Toru Tamaki
 
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
t m
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
Matsushita Laboratory
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
chiefujita1
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
0207sukipio
 

Recently uploaded (8)

CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
 
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
 

T90 きっと怖くないmvvm & mvpvm

  • 2. わんくま同盟 東京勉強会 #90 自己紹介 • HN:暁 紫電 • Twitter: @akatukisiden • 本名:伊藤 伸男 • フリーランス プログラマー • 使用言語 –C++ –C# –C++/CLI
  • 3. わんくま同盟 東京勉強会 #90 アジェンダ • 目的 • MVVMとは • ViewとViewModelの分離 • 細かいことは程々にして 実装してみた • MVVMでの画面遷移 • MVVMまとめ • MVPVMとは • とりあえず実装してみた • MVPVMでの画面遷移 • MVPVMまとめ • まとめ
  • 4. わんくま同盟 東京勉強会 #90 このセッションの目的 • 細かいことは置いておいて、 とりあえずMVVM,MVPVMっぽい形で プログラムを書けるようにする。 • MVVMでのナビゲーション手法について理解する • MVPVMでのナビゲーションについて理解する • 疎結合、密結合、コードビハインドなどの用語を できる限り使わずに説明する
  • 5. わんくま同盟 東京勉強会 #90 MVVM(Model-View-ViewModel)とは • 最近流行りのUIアーキテクチャパターン • いくつかの理由によりXAML系フレームワーク (WPF,Silverlight,WinRT)では必須と言われている • UI(View)とビジネスロジック(Model)のあいだにViewModelを 置くことで二つを分離する。 • View・ViewModel間のやり取りはデータバインドを用いる
  • 6. わんくま同盟 東京勉強会 #90 View • ユーザーインターフェース • UIへの出力とUIからの入力を担当する。 • FrameworkElementの派生クラス • XAMLの記述+対応する(partial )class • Viewの必要な情報を保持公開 • Viewからの入力やコマンドを処理し Modelを呼び出す ViewModel Model • ビジネスロジック • プログラムの中核となる処理 • ViewとViewModel以外の部分
  • 7. わんくま同盟 東京勉強会 #90 ViewとViewModelの分離(疎結合と密結合) • MVVMの説明などでよく使われる用語、 疎結合と密結合 • ViewとViewModelを密結合にならないようにし、 疎結合に保つと良いらしい • 「疎結合に保つ」「密結合になってしまっている」という記述 はよく見るが具体的にどのような状況を疎結合・密結合と 言うのか書かれていることはあまりない • もしかしたら一般的な用語で説明する必要もないのかもし れないが、 少なくとも自分にとってMVVM/MVPVMの文脈でしか聞か ない言葉
  • 8. わんくま同盟 東京勉強会 #90 さまざまな資料の記述を総合すると • View/ViewModelで互いのインスタンスや 型名を直接扱うと密結合 • データバインドを使えば疎結合
  • 9. わんくま同盟 東京勉強会 #90 具体的に何が許されて何が許されないのか • 直接触れると密結合 – ViewはViewModelが特定の型であることに依存してはいけない – ViewでViewModelのインスタンスを扱ってはいけない – ViewModelはViewが特定の型であることに依存してはいけない – ViewModelでViewのインスタンスを扱ってはいけない • データバインドは疎結合 – ViewはViewModelがINotifyPropertyChangedを 実装していることに依存してよい。 – ViewはViewModelが特定の名前のプロパティを 持つことに依存してよい
  • 10. わんくま同盟 東京勉強会 #90 厳密にいうとこれもだめかもしれない <Window x:Class="MVVM1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="300" Width="300" > <Window.DataContext > <MainViewModel /> </Window.DataContext> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new MainViewModel(); } View内でViewModelの型を 扱っている
  • 11. わんくま同盟 東京勉強会 #90 細かいことは置いておいて • MainWindowのイベントハンドラに全部の処理を書いた状態 から 少しずつ修正してMVVMの形にしてみようと思います。 • テキストボックス、ラベル、ボタンを配置し、ボタンを押すとテ キストボックスに入力した文字列を加工してラベルに出力する アプリを作る ※小さすぎてMVVMにする意味がないとか言わないでください 意味がなくてもとりあえず始めることが大事です。
  • 13. わんくま同盟 東京勉強会 #90 MainWindow.xaml <Window x:Class=“Step1.MainWindow” // 略 Title="MainWindow" Height="300" Width="300"> <Grid> <Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /> </Grid.RowDefinitions> <Button Content="Button" Grid.Row="0“ HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Click="Button_Click"/> <TextBox Name="textBox1" Grid.Row="1“ HorizontalAlignment="Center" VerticalAlignment="Center“ Height="23" Width="120" /> <Border Grid.Row="2" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Center" VerticalAlignment="Center" > <Label Name="label1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120"/> </Border> </Grid> </Window>
  • 14. わんくま同盟 東京勉強会 #90 MainWindow.xaml.cs public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender,RoutedEventArgs e) { // なんか複数の関数が絡んだ複雑な処理 string f1 = Func1(textBox1.Text); string f2 = Func2(f1); string f3 = Func3(f2); label1.Content = f3; } //頭にBをつける private string Func1(string input) { return “B” + input; } //末尾にEをつける private string Func2(string input) { return input+"E"; } //順番をひっくり返す。 private string Func3(string input) { var rev = input.Reverse().ToArray(); string ret = new string(rev); return ret; } }
  • 16. わんくま同盟 東京勉強会 #90 MainWindow.xaml.cs public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private MainWindowImpl impl = new MainWindowImpl(); private void Button_Click(object sender, RoutedEventArgs e) { label1.Content = impl.Logic(textBox1.Text); } } 処理を移すための別クラス 別クラスに移した処理の 呼び出し
  • 17. わんくま同盟 東京勉強会 #90 MainWindowImpl.cs public class MainWindowImpl { public string Logic(string input) { string f1 = Func1(input); string f2 = Func2(f1); string f3 = Func3(f2); return f3; } private string Func1(string input) { return "B" + input;} private string Func2(string input) { return input + "E";} private string Func3(string input) { var rev = input.Reverse().ToArray(); string ret = new string(rev); return ret; } }
  • 19. わんくま同盟 東京勉強会 #90 MainWindow.xaml <Window x:Class=“Step3.MainWindow" //略 Title="MainWindow" Height="300" Width="300"> <Grid> <Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /></Grid.RowDefinitions> <Button Content="Button" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Click="Button_Click"/> <TextBox Name="textBox1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Height="23" Width="120" Text="{Binding Input}“ <Border Grid.Row="2" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Center" VerticalAlignment="Center" > <Label Name=“label1” HorizontalAlignment=“Center” VerticalAlignment=“Center” Width=“120“ Content="{Binding Output}" /> </Border> </Grid> </Window>
  • 20. わんくま同盟 東京勉強会 #90 MainWindow.xaml.cs public partial class MainWindow : Window { // コントロールからの入力、出力をデータバインドに変換 private MainWindowImpl impl = new MainWindowImpl(); public MainWindow() { InitializeComponent(); this.DataContext = impl; } private void Button_Click(object sender, RoutedEventArgs e) { impl.Logic(); } } バインド対象の設定 入出力はバインドしたので 引数・戻り値なしになっている
  • 21. わんくま同盟 東京勉強会 #90 MainWindowImpl.cs public class MainWindowImpl: BindingSourceBase { public string input_; public string Input { get { return input_; } set { if (input_ != value) { input_ = value; OnPropertyChanged("Input"); } } } public void Logic() { string f1 = Func1(Input); string f2 = Func2(f1); string f3 = Func3(f2); Output = f3; } private string Func1(string input){略} private string Func2(string input){略} private string Func3(string input){略} } public string output_; public string Output { get { return output_; } set { if (output_ != value) { output_ = value; OnPropertyChanged("Output"); } } }
  • 22. わんくま同盟 東京勉強会 #90 BindingSourceBase public class BindingSourceBase:System.ComponentModel.INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyname) { if(PropertyChanged != null) { PropertyChanged(this,new PropertyChangedEventArgs(propertyname)); } } }
  • 24. わんくま同盟 東京勉強会 #90 MainWindow.xaml.cs public partial class MainWindow : Window { private MainWindowImpl impl = new MainWindowImpl(); public MainWindow() { InitializeComponent(); // バインド対象の設定 this.DataContext = impl; Button1.Click += impl.Button_Click; } } Clickイベントにimplクラスの 関数を登録
  • 25. わんくま同盟 東京勉強会 #90 MainWindow.xaml <Window x:Class=“Step3.MainWindow" //略 Title="MainWindow" Height="300" Width="300"> <Grid> <Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /></Grid.RowDefinitions> <Button Content=“Button” Grid.Row=“0” HorizontalAlignment=“Center” VerticalAlignment=“Center” Width=“120” /> <TextBox Name="textBox1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Height="23" Width="120" Text="{Binding Input}" /> <Border Grid.Row="2" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Center" VerticalAlignment="Center" > <Label Name="label1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120“ Content="{Binding Output}" /> </Border> </Grid> </Window> イベントの登録部分を削除
  • 26. わんくま同盟 東京勉強会 #90 MainWindowImpl.cs public class MainWindowImpl:BindingSourceBase { public void Button_Click(object sender,RoutedEventArgs e) { this.Logic(); } public string input_; public string Input { get { return input_; } set { 略 } } public string output_; public string Output { get { return output_; } set { 略 } } public void Logic() { string f1 = Func1(Input); string f2 = Func2(f1); string f3 = Func3(f2); Output = f3; } private string Func1(string input){略} private string Func2(string input){略} private string Func3(string input){略} } Button.Clickイベントから呼 び出される ビジネスロジック
  • 28. わんくま同盟 東京勉強会 #90 MainWindowImpl.cs public class MainWindowImpl:BindingSourceBase { private BusinessLogic BL = new BusinessLogic(); public void Button_Click(object sender, RoutedEventArgs e) { Output = BL.Logic(Input); } public string input_; public string Input { get { return input_; } set {略} } public string output_; public string Output { get { return output_; } set {略}} }
  • 29. わんくま同盟 東京勉強会 #90 BusinessLogic.cs public class BusinessLogic { public string Logic(string Input) { string f1 = Func1(Input); string f2 = Func2(f1); string f3 = Func3(f2); return f3; } private string Func1(string input){略} private string Func2(string input){略} private string Func3(string input){略} } 関数が増えてクラスが肥大化するので あれば 外部とのインターフェースになる関数 だけ残して内部実装はさらに別のクラ スに移した方がいいかも
  • 31. わんくま同盟 東京勉強会 #90 MainWindow.xaml.cs public partial class MainWindow : Window { private MainWindowImpl impl = new MainWindowImpl(); public MainWindow() { InitializeComponent(); // バインド対象の設定 this.DataContext = impl; // Button1.Click += impl.Button_Click; } } 削除
  • 32. わんくま同盟 東京勉強会 #90 MainWindow.xaml <Window x:Class=“Step6.MainWindow" //略 Title="MainWindow" Height="300" Width="300"> <Grid> <Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /></Grid.RowDefinitions> <Button Content="Button" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Command="{Binding MainCommand}“ /> <TextBox Name="textBox1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Height="23" Width="120" Text="{Binding Input}" /> <Border Grid.Row="2" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Center" VerticalAlignment="Center" > <Label Name="label1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Content="{Binding Output}" /> </Border> </Grid> </Window>
  • 33. わんくま同盟 東京勉強会 #90 MainWindowImpl.cs public class MainWindowImpl:BindingSourceBase { private BusinessLogic BL = new BusinessLogic(); public ICommand MainCommand{get;set;} public MainWindowImpl() { MainCommand = new Microsoft.TeamFoundation. MVVM.RelayCommand(() => { Output = BL.Logic(Input); }); } public string input_; public string Input { get { return input_; } set { 略} } public string output_; public string Output { get { return output_; } set{ 略 } } ロジックのバインド用のコマン ド コマンドの中身を作成。
  • 34. わんくま同盟 東京勉強会 #90 (LastSTEP:)クラス名の変更 • MainWindowImpl → MainViewModel • BindingSourceBase → ViewModelBase • BussinesLogic → MainModel
  • 36. わんくま同盟 東京勉強会 #90 画面遷移とは • 表示されているデータでは無く、 コントロール自体を変更する • 主にユーザーコントロールやパネルの切り替え
  • 37. わんくま同盟 東京勉強会 #90 MVVMでの画面遷移手法 • ViewModelの型に応じてコントロールを切り替える方法。 – データテンプレート • 表示するデータの型に応じて表示方法を変える機能 • 指定した型のデータの表示方法を定義する。 • コントロールの切り替えロジックを呼び出し、 新しいコントロールに新しいViewModelを関連付ける手法。 – ViewModelからViewを呼び出す。 • 逆方向バインディングコマンド • Behavior • TriggerAndAction
  • 38. わんくま同盟 東京勉強会 #90 とりあえずサンプル作る • ボタンを押すことで背景色の異なる(赤・青)二つのユーザーコ ントロールを切り替える。 • Modelは省略 • 切り替えロジック呼び出しのサンプルは 逆方向バインディングコマンドで実装
  • 39. わんくま同盟 東京勉強会 #90 共通部分 (赤) <UserControl x:Class="NavigationCommon.UCRed“ (略) d:DesignHeight="150" d:DesignWidth="150" Background="Red"> <Grid> <TextBlock HorizontalAlignment="Center“ VerticalAlignment="Center" Text="{Binding Text}" /> </Grid> </UserControl> public partial class UCRed : UserControl { public UCRed() { InitializeComponent(); } } public class RedViewModel:ViewModelBase { private string text = "赤"; public string Text { set{ if (text != value) { text = value; OnPropertyChanged("Text"); } } get{ return text; } } } View ViewModel
  • 40. わんくま同盟 東京勉強会 #90 共通部分 (青) <UserControl x:Class="NavigationCommon.UCBlue“ (略) d:DesignHeight="150" d:DesignWidth="150" Background=“Blue"> <Grid> <TextBlock HorizontalAlignment="Center“ VerticalAlignment="Center" Text="{Binding Text}" /> </Grid> </UserControl> public partial class UCBlue : UserControl { public UCBlue() { InitializeComponent(); } } public class BlueViewModel:ViewModelBase { private string text = “青"; public string Text { set{ if (text != value) { text = value; OnPropertyChanged("Text"); } } get{ return text; } } } View ViewModel
  • 42. わんくま同盟 東京勉強会 #90 View <Window x:Class="MainWindow" (略) Title="MainWindow" > <Window.Resources> <DataTemplate DataType="{x:Type navi:RedViewModel}"> <navi:UCRed x:Name="RedUC" /> </DataTemplate> <DataTemplate DataType=“{x:Type navi:BlueViewModel}”> <navi:UCBlue x:Name="BlueUC" /> </DataTemplate> </Window.Resources> <Grid > <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid Grid.Column="0" Name="ParentGrid"> <ContentControl Name="ContentControl“ Content="{Binding ChildViewModel}" /> </Grid> <Grid Grid.Column="1" > <Button Content="Button“ Command="{Binding NavigationCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="25" /> </Grid> </Grid> </Window> ViewModelの型を直接扱ってい る。 public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new MainViewModel(); } } ViewModelを表示しようとしている
  • 43. わんくま同盟 東京勉強会 #90 ViewModel public class MainViewModel:ViewModelBase { ViewModelBase childVM; public ViewModelBase ChildViewModel { get { return childVM; } set {略} } ICommand nCommand; public ICommand NavigationCommand { get { return nCommand; } set { 略 } } public MainViewModel(){ NavigateRed(); } private void NavigateRed() { ChildViewModel = new RedViewModel(); NavigationCommand = new Microsoft.TeamFoundation. MVVM.RelayCommand( (p) =>{NavigateBlue();}); } private void NavigateBlue() { ChildViewModel = new BlueViewModel(); NavigationCommand = new Microsoft.TeamFoundation. MVVM.RelayCommand( (p) =>{ NavigateRed();} ); } } もう一度ボタンを押したら 元の色に戻るように コマンドをリセット データテンプレートで表示する子ViewModel 表示するViewModelを変更
  • 45. わんくま同盟 東京勉強会 #90 Command UserControl public class DependencyCommandControl : Control { public DependencyCommandControl():base(){ } static DependencyCommandControl() { DefaultStyleKeyProperty.OverrideMetadata( typeof(DependencyCommandControl), new FrameworkPropertyMetadata( typeof(DependencyCommandControl)) ); } public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command“, typeof(ICommand), typeof(DependencyCommandControl) ); public ICommand Command { set { SetValue(CommandProperty, value); } get { return (ICommand)GetValue(CommandProperty); } } } XAML上で扱うには依存関係プロパティである必要があるので 依存関係プロパティ化したICommandを持つ カスタムコントロールを作る
  • 46. わんくま同盟 東京勉強会 #90 View <Window x:Class="MainWindow" (略) Title="MainWindow"> <Grid > <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/><ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid Grid.Column="0" Name="ParentGrid“ > </Grid> <Grid Grid.Column="1" > <Button Content="Button" Command="{Binding NavigationCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="25"/> <DependencyCommandControl x:Name="CommandHolder“ Command="{Binding Mode=OneWayToSource,Path='SouceToTargetCommand' }" /> </Grid> </Grid> </Window> ボタンクリック時に呼ばれる順方向コマンド ViewModelから呼ばれる逆方向コマンド逆方向バインディング カスタムコントロール
  • 47. わんくま同盟 東京勉強会 #90 ViewModel public class MainViewModel:ViewModelBase { ViewModelBase childVM; public ViewModelBase ChildViewModel{get;set} ICommand navigationcommand; public ICommand NavigationCommand { get { return navigationcommand; }set {略} } ICommand sttCommand; public ICommand SouceToTargetCommand { get { return sttCommand; } set{ 略 } } public MainViewModel() { NavigateToRed(); } ボタンクリックから呼び出される (順方向)コマンド ViewModelからViewを呼び出すための 逆方向バインディングをするコマンド
  • 48. わんくま同盟 東京勉強会 #90 ViewModel private void NavigateToRed() { ChildViewModel = new RedViewModel(); if (SouceToTargetCommand != null) SouceToTargetCommand. Execute(ChildViewModel); NavigationCommand = new Microsoft.TeamFoundation. MVVM.RelayCommand( (p) => { NavigateToBlue(); }); } private void NavigateToBlue() { ChildViewModel = new BlueViewModel(); if (SouceToTargetCommand != null) SouceToTargetCommand. Execute(ChildViewModel); NavigationCommand = new Microsoft.TeamFoundation. MVVM.RelayCommand( (p) => { NavigateToRed(); } ); } } 子コントロール用の新しいViewModelを作成、 コマンドでViewに送る もう一度ボタンを押したら元に戻すために順方向コマンドをリセット
  • 49. わんくま同盟 東京勉強会 #90 View public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var mainVM = new MainViewModel(); ChangeToRed(mainVM.ChildViewModel); this.DataContext = mainVM; } private void ChangeToBlue(object vm) { ParentGrid.Children.Clear(); var newPanel = new UCBlue(); newPanel.DataContext = vm; ParentGrid.Children.Add(newPanel); CommandHolder.Command = new Microsoft.TeamFoundation. MVVM.RelayCommand(ChangeToRed); } private void ChangeToRed(object vm) { ParentGrid.Children.Clear(); var newPanel = new UCRed(); newPanel.DataContext = vm; ParentGrid.Children.Add(newPanel); CommandHolder.Command = new Microsoft.TeamFoundation. MVVM.RelayCommand(ChangeToBlue); } } ViewModelから受け取った新ViewModelを Viewで直接扱っている 新しいViewを作成 新しいViewModelを受け取る
  • 50. わんくま同盟 東京勉強会 #90 MVVMまとめ • View と ViewModel が互いを扱わなくていいはずのMVVMで 画面遷移を行おうとするとViewでViewModelを扱ってまう。 → そもそもMVVMにはXAML環境に適応するための 最低限必要な機能しかなく、 画面遷移の存在を前提にしていないのでは? • MVVMの利点(≒XAML環境への適応≒データバインディング) を 生かしつつ画面遷移の存在を前提とするパターンが必要 → MVPVM
  • 51. わんくま同盟 東京勉強会 #90 MVPVM(Model-View-Presenter-ViewModel)とは • MVPとMVVMを合体させたもの • View,ViewModelの上にPresenterを置き、そこで、画面遷 移、 ナビゲーションを管理する。 • ViewModelに書かれていたロジックをPresenterに移動する ことでViewModelにはバインド対象となるプロパティのみが 含まれるようにする。 • ViewModelにロジックが含まれなくなるので使いまわしが容 易になる。
  • 52. わんくま同盟 東京勉強会 #90 View • ユーザーインターフェース • UIへの出力とUIからの入力を担当する。 • FrameworkElementの派生クラス • XAMLの記述+対応する partial class Model • ビジネスロジック/プログラムの中核となる処理 • ViewとViewModel(とPresenter)以外の部分
  • 53. わんくま同盟 東京勉強会 #90 • Viewの必要な情報を保持公開 • Viewから受け取った入力やコマンドををPresenterに渡す (MVPVM) • Viewからの入力やコマンドを処理しModelを呼び出す (MVVM) ViewModel
  • 54. わんくま同盟 東京勉強会 #90 • View,ViewModelを保持、その接続を管理する • ViewModelから受け取った入力やコマンドを処理しModel を呼び出す。 • ViewModelのプロパティを通してViewを変更する。 • ナビゲーション・画面遷移の管理 (子View,子ViewModelの作成、接続) Presenter
  • 55. わんくま同盟 東京勉強会 #90 とりあえず組んでみた • MVVMの時と同じようにテキストボックスから入力、加工して ラベルに出力するアプリ ※画面遷移がないのに MVPVMで組む必要性がないとか言わないように
  • 56. わんくま同盟 東京勉強会 #90 View <Window x:Class="MVPVM1.MainWindow" (略) Title="MainWindow" Height="300" Width="300"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Button Content="Button" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Command="{Binding MainCommand}"/> <TextBox Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Height="23" Width="120" Text="{Binding Input}" /> <Border Grid.Row="2" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Center" VerticalAlignment="Center" > <Label HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding Output}" Width="120" /> </Border> </Grid> </Window> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } }
  • 57. わんくま同盟 東京勉強会 #90 ViewModel class MainViewModel:ViewModelBase { public MainViewModel() { } public override void Cleanup() { MainCommand = null; base.Cleanup(); } private ICommand _mainCommand; public ICommand MainCommand { set{略} get{ return _mainCommand;} } private string _input; public string Input { set{略} get{ return _input;} } private string _output; public string Output { set{略} get{ return _output;} } } Commandの中身の定義 Modelの関数の呼び出しコードがなくなっている
  • 58. わんくま同盟 東京勉強会 #90 PresenterBase class PresenterBase<TView,TViewModel> where TView:System.Windows.FrameworkElement where TViewModel:ViewModelBase { public PresenterBase(TView view, TViewModel viewmodel) { View = view; ViewModel = viewmodel; } public TView View { set; get; } public TViewModel ViewModel { set; get; } public virtual void Initialize() { View.DataContext = ViewModel; } DataContextの設定 View-ViewModelの接続 public virtual void CleanUp() { if (ViewModel != null) { ViewModel.Cleanup(); ViewModel = null; } if (View != null) { View.DataContext = null; View = null; } } } View-ViewModel間の接続解除 View,ViewModelの参照解除 引数の View,ViewModel メンバに代入
  • 59. わんくま同盟 東京勉強会 #90 Presenter class MainPresenter:PresenterBase<MainWindow,MainViewModel> { MainModel model = new MainModel(); public MainPresenter(MainWindow view,MainViewModel viewmodel) :base(view,viewmodel){ } public override void Initialize() { ViewModel.MainCommand = new Microsoft.TeamFoundation.MVVM.RelayCommand( ()=>{ViewModel.Output = model.Logic(ViewModel.Input); }); base.Initialize(); } public override void CleanUp() { base.CleanUp(); } } ViewModelのコマンドの中身を作成 コンストラクタがViewとViewModelの インスタンスを受け取る Modelの関数の呼び出し。 Viewの操作はデータバインドした ViewModelのプロパティを通して行う。
  • 60. わんくま同盟 東京勉強会 #90 App.xaml <Application x:Class="MVPVM1.App" (略) Startup="Application_Startup“ Exit="Application_Exit“ > <Application.Resources> </Application.Resources> </Application> public partial class App : Application { MainPresenter presenter ; private void Application_Startup(object sender, StartupEventArgs e) { var view =new MainWindow(); var viewmodel = new MainViewModel(); presenter = new MainPresenter(view, viewmodel); presenter.Initialize(); view.Show(); } private void Application_Exit(object sender, ExitEventArgs e) { presenter.CleanUp(); } } App.xaml.cs StartupUri=“MainWindow.xaml” を削除 Startup,Exitを追加 アプリ起動時に、V,VM,Pを作成、 ウィンドウを表示 アプリ終了時にPresenterから全体をクリア
  • 61. わんくま同盟 東京勉強会 #90 MVPVMでの画面遷移 • View,ViewModel両方を扱うことが出来る Presenterに記述する • MVVMではView,ViewModelの二か所に分割されていた 画面遷移ロジックをPresenter一つにまとめられるため 自然な形で実装することができる。
  • 62. わんくま同盟 東京勉強会 #90 View <Window x:Class="MVPVMNavigation.MainWindow" (略) Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid Grid.Column="0" Name="ParentGrid" > </Grid> <Grid Grid.Column="1" > <Button Content=“Button” HorizontalAlignment=“Center” VerticalAlignment=“Center” Command="{Binding NavigationCommand}" Width="75" /> </Grid> </Grid> </Window> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } Viewに画面遷移用のロ ジックが存在しない ボタンがクリックされた時に呼び出さ れるコマンドのバインド
  • 63. わんくま同盟 東京勉強会 #90 ViewModel public class MainViewModel:ViewModelBase { ViewModelBase childVM; public ViewModelBase ChildViewModel { get { return childVM; } set {略} } ICommand navigationCommand; public ICommand NavigationCommand { get { return navigationCommand; } set {略} } public MainViewModel(){} public override void Cleanup() { if (ChildViewModel != null) { NavigationCommand = null; ChildViewModel.Cleanup(); ChildViewModel = null; } base.Cleanup(); } } 子ViewModel 子Presenterからアクセスできるので もしかしたら要らないかも ボタンクリックで呼び出される 画面遷移用コマンド 各プロパティのクリア
  • 64. わんくま同盟 東京勉強会 #90 子Presenter(赤,青) public class RedPresenter : PresenterBase<UCRed, RedViewModel> { public RedPresenter(UCRed view, RedViewModel viewmodel) : base(view, viewmodel) { } public override void Initialize() { base.Initialize(); } public override void CleanUp() { base.CleanUp(); } } public class BluePresenter :PresenterBase<UCBlue,BlueViewModel> { public BluePresenter(UCBlue view, BlueViewModel viewmodel) : base(view, viewmodel) { } public override void Initialize() { base.Initialize(); } public override void CleanUp() { base.CleanUp(); } }
  • 65. わんくま同盟 東京勉強会 #90 MainPresenter(1) public class MainPresenter: PresenterBase<MainWindow,MainViewModel> { public MainPresenter(MainWindow view,MainViewModel viewmodel) :base(view,viewmodel){ } public IPresenter ChildPresenter { get; set; } public override void Initialize() { base.Initialize(); NavigateToRed(); } public override void CleanUp() { ChildPresenter.CleanUp(); base.CleanUp(); } 子コントロール(赤・青)用の Presenter 子Presenterの解放
  • 66. わんくま同盟 東京勉強会 #90 MainPresenter(2) private void NavigateToRed() { if (ChildPresenter != null) { ChildPresenter.CleanUp(); } var v = new UCRed(); var vm = new RedViewModel(); var presenter = new RedPresenter(v, vm); View.ParentGrid.Children.Clear(); View.ParentGrid.Children.Add(v); ViewModel.ChildViewModel = vm; ViewModel.NavigationCommand = new Microsoft.TeamFoundation.MVVM.RelayCommand( (p) => {NavigateToBlue();} ); ChildPresenter = presenter; ChildPresenter.Initialize(); ); 新しいView,ViewModel,Presenter の作成 次回ボタンクリック時に元の色に戻すた めにコマンドをリセット 新しいViewをGridに追加 旧Presenterのクリア
  • 67. わんくま同盟 東京勉強会 #90 MainPresenter(3) private void NavigateToBlue() { if (ChildPresenter != null) { ChildPresenter.CleanUp(); } var v = new UCBlue(); var vm = new BlueViewModel(); var presenter = new RedPresenter(v, vm); View.ParentGrid.Children.Clear(); View.ParentGrid.Children.Add(v); ViewModel.ChildViewModel = vm; ViewModel.NavigationCommand = new Microsoft.TeamFoundation.MVVM.RelayCommand( (p) => {NavigateToRed();} ); ChildPresenter = presenter; ChildPresenter.Initialize(); ); 新しいView,ViewModelPresenterの作 成 次回ボタンクリック時に元の色に戻すた めにコマンドをリセット 新しいViewをGridに追加 旧Presenterのクリ ア
  • 68. わんくま同盟 東京勉強会 #90 MVPVMまとめ • ViewModelはBinding対象になるプロパティのみを記述し コマンドの中身はPresenterに記述する • PresenterはView,ViewModelどちらも扱えるので その二つに分けて記述していた画面遷移ロジックを Presenter 1ヵ所に記述することができる。 →MVVMでは三ケ所すべてにロジックが含まれる可能性があったのが MVPVMでは基本的にP,M の二か所に減る • 何らかの事情(ActiveX,低スキル,etc…)によりViewがビジネスロジッ クを持っている場合でもPresenterから直接呼べる
  • 69. わんくま同盟 東京勉強会 #90 まとめ • Viewとの入出力はバインディングで行い、 インターフェースになる関数だけ残して 実装は別クラスに移動することを繰り返せば とりあえずMVVMの形にはなる • PresenterでView,ViewModelを管理しViewModelのコマ ンドの中身を Presenterで作ればMVPVMになる。 • 一画面で完結するアプリならMVVMでもいいが、 ナビゲーション(画面遷移)を含む場合はMVPVMの方がオ ススメ
  • 70. わんくま同盟 東京勉強会 #90 今回扱わなかったこと • XAML環境でデータバインディングが必須な理由 • コレクションコントロール • エラー処理 • CommandのCanExecute() • 非同期処理(Model) • Viewに合わせた、ViewModel,Presenterそれぞれツリーの構 造