まずは、この画面に使用される、「名前」と「メッセージ」をもつクラスを作成します。
MainViewModel.cs
namespace HelloWorld
{
class MainViewModel
{
private string _Name;
private string _Message;
public MainViewModel()
{
}
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
public string Message
{
get
{
return _Message;
}
set
{
_Message = value;
}
}
}
}
ローカル変数 _Name と _Message を定義して、そのgetter, setterをpublicにしています。
これを「ViewModel」として、xamlの中に取り入れていきます。
MainWindow.xaml.cs
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Label Content="名前を入れてね" />
<TextBox Text="{Binding Name}" />
<Button Name="btnEnter" Content="Enter" Click="btnEnter_Click" />
<TextBlock Text="{Binding Message}" />
</StackPanel>
</Window>
前回から大きく変わったのが、次の2点。
・TextBox, TextBlockから、Nameプロパティが消えた。
・TextBox, TextBlockの値プロパティTextの値が「{Binding 。。。}」となった。
この「{Binding 。。。}」がMVVMのキモっぽいです。どうやら。
次に、先ほどのMainViewModelと、このxamlをどう接続させるか。
それがコードビハインドに入りました。
MainWindow.xaml.cs
using System.Windows;
namespace HelloWorld
{
public partial class MainWindow : Window
{
private MainViewModel _viewmodel;
public MainWindow()
{
InitializeComponent();
_viewmodel = new MainViewModel();
DataContext = _viewmodel;
}
private void btnEnter_Click(object sender, RoutedEventArgs e)
{
_viewmodel.Message = "こんにちは、" + _viewmodel.Name + "さん!";
}
}
}
ローカル変数としてMainViewModelを定義し、コンストラクタでnewしています。
そして、DataContextに割り当てています。
これで接続は完了なのです。ふむふむ。
また、ボタンイベントの処理は、Nameプロパティで探して.Textプロパティで値を・・・という処理から、直接stringの編集にもっていけるのがコーディングが楽になるポイントでしょうか。
さて、これを実行・・・!としても、実は動きません。
ここがMVVMのややこしいところ。
どうして動かないのかというと、xamlのほうがViewModelの変数が変わったことに気づいていないからなのです(xamlの気持ちになったことがなく、よく分からないので、たぶん、気づいていないのです)。
では気づいてもらうために・・・RaisePropertyChangedというメッセージを送ってあげます。
さて、どうするか。
面倒なので、答えのコードをここに載せます。
ViewModelBase.cs
using System.ComponentModel;
namespace HelloWorld
{
///
/// ViewModelの基底クラス
///
class ViewModelBase : INotifyPropertyChanged
{
///
/// プロパティ変更のイベント
///
public event PropertyChangedEventHandler PropertyChanged;
///
/// プロパティ変更のイベントを発行する
///
///
internal void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
}
このクラスを作成して、ViewModelのほうはこのクラスを継承させます。
もうこれは完全にテンプレート、呪文だと思って黙って入れる、でいいんですね。
MainViewModel.cs 改訂版
namespace HelloWorld
{
class MainViewModel : ViewModelBase
{
private string _Name;
private string _Message;
public MainViewModel()
{
}
public string Name
{
get
{
return _Name;
}
set
{
if (_Name != value)
{
_Name = value;
RaisePropertyChanged("Name");
}
}
}
public string Message
{
get
{
return _Message;
}
set
{
if (_Message!= value)
{
_Message = value;
RaisePropertyChanged("Message");
}
}
}
}
}
変わったのは、ViewModelBaseを継承したことと、setterでRaisePropertyChangedを書いたことです。
こう変更したことでどう動くのか?
・NameまたはMessageが変更になったとき、RaisePropertyChangedが動く。
・ViewModelBaseにより、INotifyPropertyChangedにより、プロパティの変更がxamlに通知される。
・xamlが気づいて、表示を変える。
んだと思う。。。
少しだけコードがスッキリしたような、余計にファイルが増えてややこしくなったような。
続いて、コマンドバインディングを使ってコードビハインドを完全にフリーにしてやります。
と思っていたのですが、やはりファイルが余計に増えてしまい、ViewModelも冗長なコーディングの塊になってしまうことから、MVVMって実際どうなの?っていう気持ちが強くなってきました。
ちょっと、考えてみます。

0 件のコメント:
コメントを投稿