まずは、この画面に使用される、「名前」と「メッセージ」をもつクラスを作成します。
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のほうはこのクラスを継承させます。/// ViewModelの基底クラス /// class ViewModelBase : INotifyPropertyChanged { ////// プロパティ変更のイベント /// public event PropertyChangedEventHandler PropertyChanged; ////// プロパティ変更のイベントを発行する /// /// internal void RaisePropertyChanged(string prop) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } } }
もうこれは完全にテンプレート、呪文だと思って黙って入れる、でいいんですね。
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 件のコメント:
コメントを投稿