レビューやらせていただきましたよ。
んで、せっかくだから「周回遅れにもほどがあんぞヲイ」なWPFに手を付けます。
いやね、Visual Studio 11でよぅやっとC++/CLIのインテリセンスが復活してくれたんで、
マンドクセーことやる気になったっちゅーのが本音。
てかさ、WPFアプリケーションてばC++の出番ナシなのが癪に障るんで、
ひな形生成だけをC#にやらせ、残りはぜーんぶC++/CLIで書いてみるココロミ。
おためしにこしらえたのは毎度毎度のカウンター。
「3.2.3 視覚的デザインツールの利用」にあったMVVMをほとんどそのままパクらせてもらいました。
<Window x:Class="DataBindingSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="データ バインディング サンプル" Width="193" SizeToContent="Height" Height="157">
<StackPanel>
<TextBox Text="{Binding Count}" FontSize="36" FontWeight="Bold" TextAlignment="Center" />
<Button Content="+" Command="{Binding IncCommand}" />
<Button Content="-" Command="{Binding DecCommand}" />
</StackPanel>
</Window>
XAMLはこんな↑カンジね、表示とボタンをそれぞれ CountとIncCommand/DecCommandにバインドしてます。
以降C#からはしばらくオサラバ、C++/CLIでCLRクラスライブラリを用意して参照させます。
ViewModel がコレ↓
#ifndef MAINWINDOWVIEWMODEL_H__
#define MAINWINDOWVIEWMODEL_H__
namespace DataBindingSample {
public ref class MainWindowViewModel : public System::ComponentModel::INotifyPropertyChanged {
public:
property int Count {
int get();
void set(int value);
}
virtual event System::ComponentModel::PropertyChangedEventHandler^ PropertyChanged;
void attachCommand(System::Action<Object^>^ inc, System::Action<Object^>^ dec);
void Update(int count);
property System::Windows::Input::ICommand^ IncCommand
{ System::Windows::Input::ICommand^ get(); }
property System::Windows::Input::ICommand^ DecCommand
{ System::Windows::Input::ICommand^ get(); }
private:
int _Count;
System::Windows::Input::ICommand^ incCommand;
System::Windows::Input::ICommand^ decCommand;
};
}
#endif
attachCommandでView(のIncCommand/DecCommand)からModelに、
UpdateでModel(のカウント値変更)をViewに飛ばします。
カウンタ本体:Counter と ViewModelに接続するための CounterModel はそれぞれ:
#ifndef COUNTER_H__
#define COUNTER_H__
namespace DataBindingSample {
public ref class Counter {
public:
void inc();
void dec();
int count();
private:
int count_;
};
public ref class CounterModel : Counter {
public:
// Model→ViewModel
event System::Action<int>^ CountUpdatedHandler;
// ViewModel→Model
property System::Action<Object^>^ Increment { System::Action<Object^>^ get(); }
property System::Action<Object^>^ Decrement { System::Action<Object^>^ get(); }
private:
void Notify();
void inc(Object^ dummy);
void dec(Object^ dummy);
};
}
#endif
CountUpdateHandlerとIncrement/Decrement がViewModelとの接続ポートになってます。
んでもって MainWindow, MainWindowViewModel, CounterModel をがしゃがしゃ繋ぐトコ
をC#側にねじ込みます。 MainWindowViewModel と CounterModel は App のstaticメンバ
にしちゃいました。
/*
* App.xaml.cs
*/
using System.Windows;
namespace DataBindingSample {
public partial class App : Application {
public static MainWindowViewModel ViewModel {
get {
if ( viewmodel_ == null )
viewmodel_ = new MainWindowViewModel();
return viewmodel_;
}
}
public static CounterModel Model {
get {
if ( model_ == null )
model_ = new CounterModel();
return model_;
}
}
public static MainWindowViewModel viewmodel_;
public static CounterModel model_;
}
}
/*
* MainWindow.xaml.cs
*/
using System.Windows;
namespace DataBindingSample {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
this.DataContext = App.ViewModel;
App.ViewModel.attachCommand(App.Model.Increment, App.Model.Decrement);
App.Model.CountUpdatedHandler += App.ViewModel.Update;
}
}
}
C++/CLI側の実装(.cpp)は割愛。ソリューションまるごとうpするから読んでやって。
白状すればMVVMってハジメテなの。おもきし我流だし。ガスガス突っ込んでやってくだせ。