ネイティブとマネージドの橋渡し部分の作成
さて、CounterはC++すなわちnativeなので、.NETのmanaged世界と繋ぐためmanagedの薄皮でくるんでやらにゃなりません。この役にはnativeとmanagedの2つの顔を持つC++/CLIが適任でしょうね。
プロジェクト:C++/CLRクラスライブラリ「CounterModel」を起こし、薄皮クラス CounterModelを実装します。CounterModelはCounterを内包し、カウンタを+1/-1するアクション:Increment/Decrement、そしてカウンタ値が変化したときの処理を登録できるイベント:CountUpdatedを公開します。
#ifndef COUNTERMODEL_H__
#define COUNTERMODEL_H__
namespace DataBindingSample {
class Counter;
public ref class CounterModel {
public:
CounterModel();
!CounterModel();
~CounterModel();
// Model→ViewModel
event System::Action<int>^ CountUpdated;
// ViewModel→Model
property System::Action<Object^>^ Increment { System::Action<Object^>^ get(); }
property System::Action<Object^>^ Decrement { System::Action<Object^>^ get(); }
private:
Counter* counter_;
void Notify();
void inc(Object^ dummy);
void dec(Object^ dummy);
};
}
#endif
#include "Counter.h"
#include "CounterModel.h"
using namespace System;
/*
* CounterModel impl.
*/
namespace DataBindingSample {
CounterModel::CounterModel() { counter_ = new Counter(); }
CounterModel::!CounterModel() { this->~CounterModel(); }
CounterModel::~CounterModel() { delete counter_; }
Action<Object^>^ CounterModel::Increment::get()
{ return gcnew Action<Object^>(this, &CounterModel::inc); }
Action<Object^>^ CounterModel::Decrement::get()
{ return gcnew Action<Object^>(this, &CounterModel::dec); }
void CounterModel::Notify() { CountUpdated(counter_->count()); }
void CounterModel::inc(Object^ dummy) { counter_->inc(); Notify(); }
void CounterModel::dec(Object^ dummy) { counter_->dec(); Notify(); }
}
これでnativeなCounterをmanagedの皮でくるむことができたハズ。おためしにC#から呼び出してみましょう。
namespace CounterModelTestRun {
class Program {
static void Main() {
var counter = new DataBindingSample.CounterModel();
counter.CountUpdated += count => System.Console.WriteLine("count: {0}", count);
var inc = counter.Increment;
var dec = counter.Decrement;
inc(null); inc(null); inc(null);
dec(null); dec(null); dec(null);
}
}
}
/* 実行結果:
count: 1
count: 2
count: 3
count: 2
count: 1
count: 0
*/
