SlideShare une entreprise Scribd logo
1  sur  70
わんくま同盟 東京勉強会 #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それぞれツリーの構
造

Contenu connexe

Tendances

WinFormsからWPFへ
WinFormsからWPFへWinFormsからWPFへ
WinFormsからWPFへYamamoto Reki
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかShohei Okada
 
UniRxことはじめ
UniRxことはじめUniRxことはじめ
UniRxことはじめShoichi Yasui
 
入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き土岐 孝平
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意Yoshitaka Kawashima
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)Yoshitaka Kawashima
 
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞いiOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞いKen Morishita
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム信之 岩永
 
フィーチャモデルの描き方
フィーチャモデルの描き方フィーチャモデルの描き方
フィーチャモデルの描き方H Iseri
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
Flutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成する
Flutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成するFlutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成する
Flutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成するIgaHironobu
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)NTT DATA Technology & Innovation
 
ソフトウェアテスト入門
ソフトウェアテスト入門ソフトウェアテスト入門
ソフトウェアテスト入門Preferred Networks
 
XunitとMoq 公開用
XunitとMoq 公開用XunitとMoq 公開用
XunitとMoq 公開用ESM SEC
 
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しようUnityTechnologiesJapan002
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 

Tendances (20)

WinFormsからWPFへ
WinFormsからWPFへWinFormsからWPFへ
WinFormsからWPFへ
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのか
 
UniRxことはじめ
UniRxことはじめUniRxことはじめ
UniRxことはじめ
 
入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞いiOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム
 
フィーチャモデルの描き方
フィーチャモデルの描き方フィーチャモデルの描き方
フィーチャモデルの描き方
 
Kotlinアンチパターン
KotlinアンチパターンKotlinアンチパターン
Kotlinアンチパターン
 
bicep 紹介
bicep 紹介bicep 紹介
bicep 紹介
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
Flutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成する
Flutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成するFlutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成する
Flutterでscroll viewとexpandedを併用してsign in sign up画面 などの レイアウトを作成する
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
 
ソフトウェアテスト入門
ソフトウェアテスト入門ソフトウェアテスト入門
ソフトウェアテスト入門
 
XunitとMoq 公開用
XunitとMoq 公開用XunitとMoq 公開用
XunitとMoq 公開用
 
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
 
C++の黒魔術
C++の黒魔術C++の黒魔術
C++の黒魔術
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 

En vedette

塹壕よりLivetとMVVM
塹壕よりLivetとMVVM塹壕よりLivetとMVVM
塹壕よりLivetとMVVMHiroshi Maekawa
 
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 を使った 高品質・低コスト・保守性の高い開発慎一 古賀
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門増田 亨
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する増田 亨
 

En vedette (19)

塹壕より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 を使った 高品質・低コスト・保守性の高い開発
 
Mvpvm pattern
Mvpvm patternMvpvm pattern
Mvpvm pattern
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
 
Xamarin.forms入門
Xamarin.forms入門Xamarin.forms入門
Xamarin.forms入門
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
 

Similaire à T90 きっと怖くないmvvm & mvpvm

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# 7Takaaki 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 デザインパターン 2009miwarin
 
ぱっと見でわかる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.0Yuta Matsumura
 
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】
実装(3) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第32回】Tomoharu ASAMI
 

Similaire à 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回】
 

Dernier

自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineerYuki Kikuchi
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfFumieNakayama
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfFumieNakayama
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案sugiuralab
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)Hiroshi Tomioka
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...博三 太田
 
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?akihisamiyanaga1
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)UEHARA, Tetsutaro
 

Dernier (8)

自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
 
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
 

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それぞれツリーの構 造