MVVMモデルでカウンタを作るには
えー、これまで見てきた、オブジェクト指向を説明するために書かれたソースコードの中で、もっともシンプルなものはカウンターだと思ってます。
どういったプログラムかと言いますと、
「ボタンを押せば数字が上がっていく」
たったこれだけです。たったこれだけと侮るなかれ。
今までの、OOP以前のプログラミングで同じことを実現することを考えてみましょう。
たとえばC言語なら
int UpCount(int num){
return ++num;
}
と書けば、済む話かも知れません。
でも、カウンターを複数持ちたい場合は?
このカウンターが鳥を数えるためのバードカウンターだったとします。
カラスを数えるのに1つほしい
スズメを数えるのに1つほしい
ついでに野鳥研究会人数分欲しい
そう、1つだけでは足りないわけです。
そこでOOPの出番ですよ奥さん。
たとえばこんなコードになります。
class Counter{
int num
public UpCount(){
num++;
}
}int main()
{
Counter KarasuCounter = new Counter();
Counter SuzumeCounter = new Counter();
//UpCountを呼ぶたびに数値が上がっていきます。
KarasuCounter.UpCount();
KarasuCounter.UpCount();
KarasuCounter.UpCount();
//スズメを数えたい時はそれようのインスタンスを呼びます。
SuzumeCounter.UpCount();
SuzumeCounter.UpCount();
SuzumeCounter.UpCount();
}
だいたい雰囲気は伝わったのではないでしょうか。
これをMVVMModelでやりたいというのが今回の試みです。
ViewModelはこんな感じ
class CounterViewModel:INotifyPropertyChanged
{
private int num = 0;
public int Num
{
get
{
return num;
}
private set
{
num = value;
NotifyPropertyChanged("Num");
}
}
DelegateCommand upCommand = new DelegateCommand();
public DelegateCommand UpCommand
{
get
{
return upCommand;
}
set
{
upCommand = value;
}
}
public CounterViewModel()
{
UpCommand.ExecuteHandler = upCount;
}
private void upCount()
{
Num++;
}
// 概要:
// プロパティ値が変更されたときに発生します。
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
コマンドクラス
public delegate void myDelegate();
public class DelegateCommand : ICommand
{
public myDelegate ExecuteHandler;
#region ICommand メンバー
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var d = ExecuteHandler;
if (d != null)
d();
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
var d = CanExecuteChanged;
if (d != null)
d(this, null);
}
#endregion
}
XAMLの方はこんな感じ
<UserControl x:Class="othello.Counter"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:othello"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<local:CounterViewModel/>
</UserControl.DataContext>
<StackPanel>
<TextBlock Text="{Binding Num,UpdateSourceTrigger=PropertyChanged}"/>
<Button Command="{Binding UpCommand}" Content="upcount"/>
</StackPanel>
</UserControl>
ついでだからWindowも作っちゃいましょう。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:othello" x:Class="othello.CounterWindow"
Title="CounterWindow" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Horizontal">
<StackPanel Margin="10">
<TextBlock>カラスカウンター</TextBlock>
<local:Counter HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" Width="70"/>
</StackPanel>
<StackPanel Margin="10">
<TextBlock>スズメカウンター</TextBlock>
<local:Counter HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" Width="70"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
完成図はこんな感じ
ポイントはCommandクラスにDelegeteを使って関数を渡しているところ
あとはCommandのBindingSourceをプロパティにすることを忘れないようにしよう!(これ、よく忘れてしまうんですよね)
こんな風に、MVVMでオブジェクト指向ができるとめっさ便利ですよね...