次の方法で共有


この記事は機械翻訳されたものです。

Windows ランタイムと C++

Windows ランタイムにデスクトップ アプリケーションを移植する (機械翻訳)

Diego Dagum

コード サンプルのダウンロード

Windows 8 ではマイクロソフトのプラットフォームのための新しいデザイン哲学を体現しています。 Windows 8 では、XAML や HTML5 などの UI の技術を使用してアプリケーションを作成できます。 マイクロソフトは 2 つの新しいアプリケーション モデルを提供します。使用できます、Windows ランタイム ライブラリ (WRL) Windows ストア アプリケーションと c#、Visual Basic、C++、および HTML5 を作成することができます JavaScript (WinJS) 用の Windows ライブラリと JavaScript アプリケーションを開発します。

WRL は Windows 8 には、デスクトップ環境に Microsoft Foundation クラスのフレームワーク (MFC) または C のような Win32 Api ものです。 その結果、既存のデスクトップ アプリケーションは Windows のランタイムの下で実行に適応する必要があります。 ジレンマ MFC、Win32 または他のアプリケーション フレームワークに大きく依存するアプリケーションが付属しています。 彼らは Windows ランタイムに移植している場合何が起こるのか? その後何が起こるか? それは両方を維持するために必要なコードベースです — タブレットとデスクトップ?

この記事では、識別およびアプリケーションのコードベースから実質的な部分を抽出し、2 つの環境間で共有方法紹介します。 あなたはどのようにこのリファクタリングのアクティビティもいくつかの新しい C を活用する機会です表示されます + + 11 の機能の簡潔さと保守性。 メリットよりもちょうど新しい Windows ストア バージョン、既存のアプリケーションを得ています。 アプリケーションの既存のコードベースもアップグレードされています。

移植性とそのジレンマ

常に、移植性と他の非機能要件をそれに応じて設計、最初からアプリケーションを構築するは簡単です。 実際には、しかし、アプリケーション開発者はしばしば不測の要件によって、アプリケーションを展開した後に現れる挑戦されます。 ニーズが証明するかもしれないこれらの後を満たす場合は、アプリケーションのように新しいことができる方法で設計に問題が大きい部分を書き直すことがなく実装することは困難備えています。 新しい部品が慎重にテストしない最終的には、アプリケーションの破損の生産につながることができます。

このため、私は自分のデモを作成する代わりに、既存のアプリケーション例としてを使用することを決めた。 あなたが見るように、マイクロソフトが Visual Studio 2005 の公開 MFC 電卓のサンプルを選択した (bit.ly/OO494I)。

アプリケーション全体の書き換えのオプションは魅力的だコードの解消を取得するので最初は、維持しない — ではなく、最初からやり直すだろうが、この時間はよくそれを行います。 しかし、そのアプリの生産プラットフォームが新しいアプリケーションを実行できないユーザーのために滞在しない限り、元のアプリケーションから期待される投資 (収益率 ROI) でリターンを侵食するため管理と確信することはできません。 場合は、2 つの類似するコードベース コストが増加維持する必要があります (2 倍の作業 — 以上 — 新機能を実装したり、たとえばバグを修正する)。

すべての元のコード (Windows デスクトップと Windows 実行時のこの場合) が異なる環境で再利用することができることがあります。 しかしより多くを共有でき、コストと、その結果より高い利益。

基本に戻る:関心の分離

分離 (SoC) の懸念の既成概念今日、多くのソフトウェア アーキテクチャの書籍の出版です。 その結果、自然の 1 つです API に関連するコードをまとめて (隠し言わないため) グループ化する残りの部分に抽象インターフェイスを提供する細分のコンポーネントに。 したがって、具体的なデータのリポジトリは決して明示的にドメイン ロジック、プレゼンテーション ロジックなどを実行するコードに公開されます。 これらのコンポーネントは「抽象インターフェイスにトーク」。

SoC は、開発者の間で広く採用しています。 90 年代後半に始まった Web 爆発の結果として、多くのスタンドアロン アプリケーション層と層の間では、配布されたモジュールで壊れていた。

Soc を考慮せずに開発されたアプリケーションがある場合、リファクタリングによって、現代の世界にもたらすことができます。 リファクタリングはおそらく働くことができる、単純なものを構築、渡されたすべてのテストを取得とソフトウェアのスループットを最大にする、時間となどを促進するアジャイルのプラクティスの幅広い採用のおかげで最近実行健康的です。 しかし、敏捷性は、これが必要になるまで、新しいチャネルを有効にするために多くの部屋を残していません。 ここでは、その後です。

ポーティングの一般的なシナリオ

私は前述、基本的な電卓サンプル MFC アプリケーションが表示されます図 1

The Microsoft MFC Calculator
図 1 Microsoft MFC 電卓

このサンプルは、次の理由により、移植プロセスを説明するために素晴らしいです。

  • 十分に小さいあなたのためにそれが何の全体的なアイデアを得ることです。
  • 私は、プロセスの詳細に表示できるように十分な大きさです。 平均アプリケーションはおそらく大きなコードベースを持っていますが、移植のここに記載の手順の繰り返しで構成されます。
  • コードを結合十分なリファクタリングをデカップリングを表示します。 それはおそらく意図的にコンパクトでわかりやすいコードベースを保つために結合されていました。 私は分離されます一般的なを取得するまでコード コードベース MFC と Windows 8 のバージョンで使用されます。 私はさらに、切り離すことはありませんが、どのくらい多くのコードが分離できるをお勧めします。

元の電卓アプリケーションに 2 つのクラスが含まれています。CCalc­アプリと CCalcDlg。 CCalcApp その InitInstance 関数は CCalcDlg をインスタンス化します。 実行中のプロセスとしての電卓をモデル化 (を参照してください図 2)。 CCalcDlg は、メインのウィンドウ コントロール (パネルとボタン)、関連付けられたイベントをモデル化します。

Original Calculator Sample Class Diagram Showing Essentials
Essentials を示す図 2 オリジナル電卓サンプル クラス図

CCalcDlg MFC CDialog から派生し、その実装はすべて、そのウィンドウのメッセージをその機能と、これらのイベントへの応答としてトリガー電卓ロジックの実装の基本的なマッピングから。 図 3 [等号] ボタンがクリックしてされたときに何が起こるかを示しています (おそらく 2 つのオペランドと演算子を入力した後)。 図 4 すべてのレベルで動作を追加する CCalcDlg 関数を示しています。イベントの反応、ドメイン ロジック、プレゼンテーション。

Sequence Diagram for an Event—Clicking the Equal Sign Button
図 3 シーケンス図のイベント —、[等号] ボタン

Figure 4 CCalcDlg
// CCalcDlg.cpp
// Window messages trigger CCalcDlg function invocations
BEGIN_MESSAGE_MAP(CCalcDlg, CDialog)
  ON_WM_PAINT()
  ON_COMMAND_RANGE(IDB_0, IDB_9, OnClickedNumber)
  ON_BN_CLICKED(IDB_CLEAR, OnClickedClear)
  ON_BN_CLICKED(IDB_DIVIDE, OnClickedDivide)
  ON_BN_CLICKED(IDB_EQUAL, OnClickedEqual)
  ON_BN_CLICKED(IDB_MINUS, OnClickedMinus)
  ON_BN_CLICKED(IDB_PLUS, OnClickedPlus)
  ON_BN_CLICKED(IDB_TIMES, OnClickedTimes)
  ON_EN_SETFOCUS(IDE_ACCUM, OnSetFocusAccum)
END_MESSAGE_MAP()
 
...
// Event reaction
void CCalcDlg::OnClickedEqual() {
  PerformOperation();
  m_operator = OpNone;
}
 
// Domain logic
void CCalcDlg::PerformOperation() {
  if (m_bOperandAvail) {
    if (m_operator == OpNone)
      m_accum = m_operand;
    else if (m_operator == OpMultiply)
      m_accum *= m_operand;
    else if (m_operator == OpDivide) {
      if (m_operand == 0)
        m_errorState = ErrDivideByZero;
      else
        m_accum /= m_operand;
      }
    else if (m_operator == OpAdd)
      m_accum += m_operand;
    else if (m_operator == OpSubtract)
      m_accum -= m_operand;
  }
 
  m_bOperandAvail = FALSE;
  UpdateDisplay();
}
 
// Presentation logic
void CCalcDlg::UpdateDisplay() {
  CString str;
  if (m_errorState != ErrNone)
    str.LoadString(IDS_ERROR);
  else {
    long lVal = (m_bOperandAvail) ?
m_operand : m_accum;
    str.Format(_T("%ld"), lVal);
  }
  GetDlgItem(IDE_ACCUM)->SetWindowText(str);
}

CCalcDlg は、MFC に結び付けられているため、Windows ストア バージョンのアプリケーションで使用しロジックとして移植することはできません。 いくつかをリファクタリングする必要があるでしょう。

再利用可能なコンポーネントを分離するリファクタリング

この計算機の Windows ストア バージョンを作成するには、私はすべてを変換する必要はありません。 示されているものなど、動作の多く図 4、ので MFC ベースの CCalcDlg に関連付けられていたいない場合再利用できます。 再利用可能な部品 (この場合は電卓の動作) の実装に固有のコンポーネントから独立していること方法でアプリケーションをリファクタリングします。

私だけでなく、モデル-ビュー-コント ローラー (MVC) アーキテクチャ パターンについて聞いたことがあるが、またそれを適用するいると仮定します。 私はちょうどここのパターンを要約します:ドメイン オブジェクトのモデルで構成されます (両方のステートレスとない) と doesn't 知っているまたは気ビュー技術について。 ビューはアプリケーションのデバイスに適しているいくつかのユーザーとの対話技術 (HTML、Qt、MFC、ココア、他の間で) に実装されています。 それはドメイン ロジックの実装方法を知っていない; その機能は、ドメイン データ構造またはそれらの一部を表示するだけです。 コント ローラーは仲介者としてのトリガーのアクションに新しい状態を反映して更新表示されるドメインは、ユーザー入力をキャプチャすることにより機能します。

MVC は広く知られている、しかし、ドメインから UI を分離する唯一の方法ではありません。 電卓のシナリオではプレゼンテーション モデルとして知られている、MVC の変動に依存します (bit.ly/1187Bk)。 私最初、モデル-ビュー-ビューモデル (MVVM)、Microsoft .NET Framework 開発者の間で人気がある別のバリエーションを検討しました。 プレゼンテーション モデルは、このシナリオに合わせてにもかかわらずだった。 プレゼンテーション モデルは、新しいユーザーとの対話技術 (この場合 Windows 8) を実装するが、面での UI の動作に変更がない場合に理想的です。 このパターンはまだ、モデルとビューとして前に、考慮しますが、プレゼンテーション モデルという名前のビューの抽象表現でコント ローラーの役割が再生されます。 このコンポーネントでは、ビューの技術に関係なくその状態の一部を含むビューの共通の動作を実装します。

図 5 変更バージョンの MFC アプリケーションを示しています。

The Namespace Calculator::View Consolidates the View Behavior in Its Associated Presentation Model
図 5 Namespace Calculator::View ビューの動作が関連付けられているプレゼンテーション モデルの統合します。

ビューのステータスが変更されたことを決定したら、UpdateDisplay 関数を呼び出すので CalculatorPresentationModel (ICalculatorView インタ フェースとしてモデル化された) ビューへの参照を保持します。 MFC と直接取引がクラスですので MFC サンプルでは、ビュー自体の CCalcDlg です。

CCalcDlg はそのコンス トラクターでそのプレゼンテーション モデルを作成します。

CCalcDlg::CCalcDlg(CWnd* pParent) 
  : CDialog(CCalcDlg::IDD, pParent)
{
  presentationModel_ = 
    unique_ptr<CalculatorPresentationModel>(
    new CalculatorPresentationModel(this));
  ...
}

ご覧のように、C を活用 + + ここ unique_ptr と呼ばれる 11 のスマート ポインター (を参照してください bit.ly/KswVGy の詳細)。 スマート ポインターは、それはもはや必要がある場合は参照オブジェクトを解放する能力があります。 プレゼンテーション モデルは、ビューのライフ サイクルが終了したときに破棄するのにここでスマート ポインターを使用します。 ビューは、プレゼンテーション モデル、入力をマッサージの有無を示すように委任する、ウィンドウ イベントを捕捉する保持図 6

図 6 委任を示すいくつかのビューの機能

// The parameter nID contains the ASCII code of a digit
void CCalcDlg::OnClickedNumber(UINT nID) {
  ASSERT(nID >= IDB_0 && nID <= IDB_9);
  presentationModel_->ClickedNumber(nID - IDB_0);
}
 
// Unchanged delegation
void CCalcDlg::OnClickedClear() {
  presentationModel_->ClickedClear();
}
 
enum Operator { OpNone, OpAdd, OpSubtract, OpMultiply, OpDivide };
 
// The Presentation Model contains a single method for all binary operations
void CCalcDlg::OnClickedDivide() {
  presentationModel_->ClickedOperator(OpDivide);
}
 
void CalculatorPresentationModel::ClickedOperator(Operator oper) {
  // PerformOperation is now in the PresentationModel;
  // it was in CCalcDlg (now being "the View")
  PerformOperation();
  m_operator = oper;
}
 
void CalculatorPresentationModel::PerformOperation() {
  if (m_errorState != ErrNone)
    return;
 
  if (m_bOperandAvail) {
    if (m_operator == OpNone)
      m_accum = m_operand;
    else if (m_operator == OpMultiply)
      m_accum *= m_operand;
  ...
// Same as in Figure 4
 
  m_bOperandAvail = false;
  // This is an inline function defined just below
  UpdateDisplay();
}
 
// The UI refresh is deferred back to the actual View
inline void CalculatorPresentationModel::UpdateDisplay() {
  if (view_)
    view_->UpdateDisplay();
}

フォルダーの mfccalc サンプルでダウンロード可能なコンパニオンこの再加工バージョンの MFC サンプルを見つけることができます。 モデルはありませんがあります。 この例では、ドメイン ロジックで示されているもののような何か基本的な四則演算、関数を含むクラスしてきただろう図 7

図 7 電卓「モデル」が含まれている純粋な実装

// Namespace Calculator::Model
class CalculatorModel {
public:
  long Add(const long op1, const long op2) const {
    return op1+op2;
  }
 
  long Subtract(const long op1, const long op2) const {
    return op1-op2;
  }
 
  long Multiply(const long op1, const long op2) const {
    return op1*op2;
  }
 
  long Divide(const long op1, const long op2) const {
    if (operand2)
      return operand1/operand2;
    else
      throw std::invalid_argument("Divisor can't be zero.");  }
};
 
// Namespace Calculator::View
class CalculatorPresentationModel {
public:
  ...
void PerformOperation();
  ...
private:
  // The Presentation Model contains a reference to a Model
  unique_ptr<Model::CalculatorModel> model_;
  ...
}
 
void CalculatorPresentationModel::PerformOperation()
{
  if (m_errorState != ErrNone)
    return;
 
  // Same like before, but this time the PresentationModel asks
  // the model to execute domain activities instead of doing it itself
  if (m_bOperandAvail) {
    if (m_operator == OpNone)
      m_accum = m_operand;
    else if (m_operator == OpMultiply)
      m_accum = model_->Multiply(m_accum, m_operand);
    else if (m_operator == OpDivide) {
      if (m_operand == 0)
        m_errorState = ErrDivideByZero;
      else
        m_accum = model_->Divide(m_accum, m_operand);
    }
    else if (m_operator == OpAdd)
      m_accum = model_->Add(m_accum, m_operand);
    else if (m_operator == OpSubtract)
      m_accum = model_->Subtract(m_accum, m_operand);
  }
 
  m_bOperandAvail = false;
  UpdateDisplay();
}

プレゼンテーション モデルの内部ロジックを残してモデルこの小さなシナリオでスキップすることを決めた。 これは、ほとんどの場合、典型的ではありませんし、モデルのロジックは、クラスまたは一連のクラスで実装する必要があります。 場合のように、純粋主義者のアプローチに向けてサンプル運動としてリファクタリングすることができます。 場合は、モデルで自動化されたプロセスではなく、いくつかのユーザーの相互作用と呼ばれるかもしれない、再利用可能なコンポーネントなので、関数 CalculatorModel::Divide を実装するときに特別な注意を払う必要があります。 その場合は、ゼロによる除算例外をスローすること重要でない; その時点でそれは不測の事態になります。 非ゼロの除数チェック プレゼンテーション モデルから削除する必要はありません。 誤ったデータ転送から防止する内側の層には、常に健康です。 他には何が使用可能になったらモデルによりスローされた例外は最後の手段です。

先に行くし、コード、および通知は、以前ちょうど欲しかったのですがそれはまだ動作します仲間にリファクタリングしたソリューション mfccalc を実行します。機能を失うことなくが、コードがポートを設定するには。 深刻なリファクタリングのプロセスは、アプリケーションの動作が結果として発生ではなかったことを確認する自動テストのセットを考慮しなければなりません。 ネイティブの単体テストは、Visual Studio 2012 とは無料エクスプレスの Windows (これは、MFC またはデスクトップ開発のための他のフレームワークにも付属していません) 8 を含むすべての開発者エディションで利用可能です。

ソリューション Calculator\CalculatorTests のコンパニオン コードをご覧ください。 示すように、クラス メソッドがテストの CalculatorPresentationModel、PresentationModelTest Calculator::Testing 名前空間を含む図 8

図 8 エラー ネイティブのユニット テストを分離します。

// Namespace Calculator::Testing
TEST_CLASS(PresentationModelTest) {
private:
  CalculatorPresentationModel presentationModel_;
public:
  TEST_METHOD_INITIALIZE(TestInit) {
    presentationModel_.ClickedClear();
  }
 
  TEST_METHOD(TestDivide) {
    // 784 / 324 = 2 (integer division)
    presentationModel_.ClickedNumber(7);
    presentationModel_.ClickedNumber(8);
    presentationModel_.ClickedNumber(4);
 
    presentationModel_.ClickedOperator(OpDivide);
 
    presentationModel_.ClickedNumber(3);
    presentationModel_.ClickedNumber(2);
    presentationModel_.ClickedNumber(4);
 
    presentationModel_.ClickedOperator(OpNone);
 
    Assert::AreEqual<long>(2, presentationModel_.GetAccum(),
      L"Divide operation leads to wrong result.");
    Assert::AreEqual<CalcError>(ErrNone, 
      presentationModel_.GetErrorState(),
      L"Divide operation ends with wrong error state.");
  }
 
  TEST_METHOD(TestDivideByZero) {
    // 784 / 0 => ErrDivideByZero
    presentationModel_.ClickedNumber(7);
    presentationModel_.ClickedNumber(8);
    presentationModel_.ClickedNumber(4);
 
    presentationModel_.ClickedOperator(OpDivide);
 
    presentationModel_.ClickedNumber(0);
 
    presentationModel_.ClickedOperator(OpNone);
 
    Assert::AreEqual<CalcError>(ErrDivideByZero, 
      presentationModel_.GetErrorState(),
      L"Divide by zero doesn't end with error state.");
  }
 
  ...
// More tests for the remaining calculator operations
};

ところで、単体テストはこのプレゼンテーション モデル パターンの最も評価の結果のいずれかです。UI 行動テストのオートメーションが埋め込まれて、このサンプルでは、プレゼンテーション モデルのドメイン ロジックを同じです。 任意が起きている場合、既存のものではなく、新しいユーザーとの対話コンポーネントしたがって、あなたの新しいチャネル アプリケーション (たとえば、ココア、Qt、wxWidgets または HTML5 や Windows Presentation Foundation なども非ネイティブのもの) に確実にそのエラー開くことができます。 確実にすべての行のコードを少なくとも 1 回テストするためのコード カバレッジ機能を活用できます。

XAML のファサードに電卓アプリケーションを開く

リファクタリングされたコードを新しい Windows UI を作成するための MFC の計算機が整いました。 それは、前に説明したプレゼンテーション モデル パターンの新しいビューを作成するだけです。

Windows 8 では 3 つの技術を提供しています:XAML、HTML、および DirectX。

  • XAML UI コントロールとハンドラーを呼び出すイベントへの応答にバインドするデータのビジュアル UI 要素を宣言できる XML ベースのマークアップ言語です。 これらのイベントは、通常 C++ コンポーネントの拡張機能として知られている Windows ランタイムの拡張の C++ 構文で作成することができますいわゆる分離コード コンポーネントで定義されている (C + + CX)、またはその他のプログラミング言語で作成されました。 XAML ベースの電卓の顔を紹介します。
  • HTML を使用すると、Java で定義されたどの UI 動作を設定­スクリプトの実行、インターネット エクスプ ローラー「チャクラ」にエンジン。 それは可能です — 私は次のセクションで説明するよう — JavaScript コードから C++ ベースのコンポーネントを呼び出す。
  • DirectX は、マルチ メディアを多用するアプリケーションのために最適です。 電卓マルチ メディア アプリケーションではありませんので、私はここでこれを説明しません。 DirectX アプリケーション XAML あなたについてもっとで読むことができる相互運用機能を通じて使用できる bit.ly/NeUhO4

XAML ビューを作成するには、基本的な空白のアプリケーション Visual の C++ の Windows 8 テンプレートの一覧から選択し、XamlCalc と呼ばれるプロジェクトを作成します。

この空白のテンプレートには、MFC のバージョンでの元の CCalcDlg コントロールに対応する Windows の 8 のようにコントロールをいっぱいによただ、空 MainPage.xaml が含まれます。 これは、すべてのそれだけ、1 つのウィンドウの [ナビゲーションなし] とで構成されていますので、電卓アプリケーションをポートする必要がありますです。 UX は、直感的で予測可能なを提供するページ ナビゲーション機構を提供できるようにアプリケーションを移植する際に、他のテンプレートを考慮するかもしれない これについてガイダンス「アプリの UX の設計」のページを見つけることができます (bit.ly/Izbxky)。

空のテンプレートは、App.xaml ファイルを目的でと同様に、mfc でのクラス CCalcApp でまた来ます (を参照してください図 2)。 それは、残りのコンポーネントを初期化し、それらにコントロールを渡しますブートス トラップ ローダーです。 関数 CCalcApp::InitInstance では、UI として機能し、CCalcDlg ウィンドウを作成します。 (あなた XamlCalc ソリューションでこれらのすべてのダウンロード可能なコンパニオン コード見つける。)XAML の場合 App::OnLaunched デフォルト分離コード ソース ファイル、App.xaml.cpp、によって生成され、初期ナビゲーション MainPage をトリガーします。

void App::OnLaunched(
  Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ pArgs) {
  ...
// Create a Frame to act navigation context and navigate to the first page
  auto rootFrame = ref new Frame();
  if (!rootFrame->Navigate(TypeName(MainPage::typeid))) {
    throw ref new FailureException("Failed to create initial page");
  }
  ...
}

コントロールをツールボックスからドラッグして、編集などのユーザー定義のスタイル、データ バインディングでは、関連するイベントなど、いくつかのマニュアルを完了する没入型の電卓ページを作成するのに Visual Studio の組み込み XAML エディターを使用します。 結果の XAML コードのように見える図 9。 電卓が表示されます図 10

図 9 の XAML バージョンの MFC 電卓

<Page
  Loaded="Page_Loaded"
  x:Class="XamlCalc.MainPage" ...>
 
  <Grid Background="Maroon">
    ...
<Border Grid.Row="1" Background="White" Margin="20,0">
      <TextBlock x:Name="display_" TextAlignment="Right" FontSize="90"
        Margin="0,0,20,0" Foreground="Maroon" HorizontalAlignment="Right"
        VerticalAlignment="Center"/>
    </Border>
    <Grid Grid.Row="2">
      ...
<Button Grid.Column="0" Style="{StaticResource Number}"
        Click="Number_Click">7</Button>
      <Button Grid.Column="1" Style="{StaticResource Number}"
        Click="Number_Click">8</Button>
      <Button Grid.Column="2" Style="{StaticResource Number}"
        Click="Number_Click">9</Button>
      <Button Grid.Column="3" Style="{StaticResource Operator}"
        Click="Plus_Click">+</Button>
    </Grid>
    ...
<Grid Grid.Row="5">
      ...
<Button Grid.Column="0" Style="{StaticResource Number}"
        Click="Number_Click">0</Button>
      <Button Grid.Column="1" Style="{StaticResource Operator}"
        Click="Clear_Click">C</Button>
      <Button x:Name="button_equal_" Grid.Column="2"
        Style="{StaticResource Operator}" Click="Equal_Click"
        KeyUp="Key_Press">=</Button>
      <Button Grid.Column="3" Style="{StaticResource Operator}"
        Click="Divide_Click">/</Button>
    </Grid>
  </Grid>
</Page>

The Look and Feel of the XAML Calculator
図 10 の XAML 電卓の外観

(数字と演算子の両方) のボタンのスタイルを App.xaml で定義色、アライメント、フォントおよびその他のプロパティの各ボタンを繰り返す必要はありませんので。 同様をクリック プロパティ各ボタンのイベント ハンドラーを関連付けられた; ハンドラーは、分離コード ソース ファイル MainPage.xaml.cpp で定義された MainPage メソッドです。 ここでは例として、1 つの除算操作のためのクリック数とのカップル:

void MainPage::Number_Click(Platform::Object^ sender,
  Windows::UI::Xaml::RoutedEventArgs^ e)
{
  Button^ b = safe_cast<Button^>(sender);
  long nID = (safe_cast<String^>(b->Content)->Data())[0] - L'0';
  presentationModel_->ClickedNumber(nID);
}
 
void MainPage::Divide_Click(Platform::Object^ sender,
  Windows::UI::Xaml::RoutedEventArgs^ e)
{
  presentationModel_->ClickedOperator(OpDivide);
}

ご覧のとおり、これら C + +/MainPage CX メソッドはちょうどイベント情報を取る、それは私の標準の C++ クラス、実際の UI のアクティビティを実行する CalculatorPresentationModel のインスタンスに与えます。 これは、標準 C++ のロジック既存のネイティブ アプリケーションからを取る、それはブランドの新しい C + で再利用することが可能であることを示しています c++/cli CX Windows ストア アプリケーション。 彼らは両方とも共通のコンポーネント内の任意の更新プログラムを活用できるため、この再利用性の両方のバージョンを維持するコストを削減 — この場合 CalculatorPresentationModel。

彼らは明確に定義された抽象インタ フェースを実装する限り、共通コンポーネントによって戻って実装固有のコンポーネントを呼び出すことができます。 私の例では、例えば、電卓­PresentationModel::UpdateDisplay ICalculatorView のインスタンスに実際の仕事を委任します。

inline void CalculatorPresentationModel::UpdateDisplay(void) {
  if (view_)
    view_->UpdateDisplay();
}

MFC のバージョンでは、ICalculatorView CCalcDlg の MFC ベース クラスによって実装されます。 リファクタリングされたシーケンス図でを見て図 11 のオリジナルと比較図 3

The Sequence Diagram for the Equal Sign Button in the Decoupled MFC Version
図 11 分離の MFC バージョンの等号記号ボタン用のシーケンス図

XAML バージョンの MFC の場合に類似して保つために、私は ICalculatorView MainPage で実装しましたする必要があります。 代わりに、MainPage C + であるために、別のクラスとして ICalculatorView を実装しなければならなかった +/CX クラスし、したがって、標準の C++ クラスから派生できません。 C++ およびその Windows ランタイムへの投影 (C + +/CX) 異なる種類のシステムがある — は相互素敵ないずれの場合で。 純粋な C++ ICalculatorView インターフェイスを実装するには、大したことではなかった。

namespace XamlCalc {
  class CalcView : public ICalculatorView {
  public:
    CalcView() {}
    CalcView(MainPage^ page) : page_(page) {}
    inline void UpdateDisplay()
      { page_->UpdateDisplay(); }
  private:
    MainPage^ page_;
  };
}

標準 C++ と C++/cli CX クラスはお互いから派生することはできませんが、彼らはまだ互いへの参照を保持することができます — この場合は、プライベート メンバー page _ は C + への参照を c++/cli CX MainPage。 表示コントロールの XAML のバージョンを更新するには、私はちょうど通と呼ばれる MainPage.xaml TextBlock コントロールの Text プロパティを変更します。

void MainPage::UpdateDisplay() {
  display_->Text = (presentationModel_->GetErrorState() != ErrNone) ?
L"ERROR!" :
    safe_cast<int64_t>(presentationModel_->GetValue()).ToString();
}

図 12 、XAML を示しています電卓クラス図。

The XAML-C++/CX Calculator Application Class Diagram
XAML を図 12-C + + CX 電卓アプリケーションのクラス図

図 13 の XAML バージョンで等号 (=) のボタンを押すと、アクションに対応するシーケンスを示しています。

The Sequence Diagram for the Equal Sign Button in the XAML version.
図 13 の XAML バージョンで等号記号ボタン シーケンス図

WRL は大きくその Api イベント処理のためのすべての非同期処理を促進することを言及する必要があります。 私も 100% 同期、です。 私は、非同期タスク ベース並列パターン タスクと Windows 8 非同期性の概念に基づく継続を実装しているライブラリを使用して作ったことが. これは私の小さな例では、正当化ではなかったが、それは Windows デベロッパー センターで"非同期プログラミングで C++"ページの詳細については読んで価値がある (bit.ly/Mi84D1)。

F5 キーを押してしてアクションで XAML バージョンを参照するアプリケーションを実行します。 移行または Windows ストア アプリケーションを作成する場合は、マイクロソフト デベロッパー センターに記載されている新しい Windows エクスペリエンスのデザイン パターンに基づく UI アプリケーションを設計することが重要です (bit.ly/Oxo3S9)。 指揮の推奨パターンに従う、タッチは、反転の向き、魅力、初めてのユーザーのための UX 直感的なアプリケーションを維持するためにより多く。

別の例:新しい Windows UI HTML 電卓

XAML の例と並んで Windows 8 を実行して MFC ベースの初期の電卓のサンプルを取得するのに十分です。 ただし、(専門知識のあなたのチームのまたは既存の資産を活用する) などの特定の状況では、HTML および JavaScript の XAML ではなく UI を検討可能性があります。

UI ロジックを C++ 以外の言語の JavaScript のようなが含まれている場合でも、この資料に記載のプレゼンテーション モデルの設計パターンはまだ便利です。 Windows 8 の環境では、JavaScript のプロジェクトを Windows ランタイム C++ として多くは、両方で WRL 設立型システム共有としての相互運用可能この奇跡が可能です。

コンパニオン コードでは、MainPage.xaml に類似の default.html ページが含まれている HtmlCalc と呼ばれるソリューションを見つけます。 図 14 UI の説明で示した XAML バージョンに匹敵する示しています図 9

図 14 電卓 UI の HTML マークアップ

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>HTMLCalc</title>
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
    <!-- HTMLCalc references -->
    <link href="/css/default.css" rel="stylesheet">
    <script src="/js/default.js"></script>
  </head>
  <body onkeypress="Key_Press()">
    <table border="0">
      <tr>
        <td class="Display" colspan="7" id="display_">0 </td>
      </tr>
      <tr>
        <td>
          <button class="Number" onclick="Number_Click(7)">7</button>
        </td>
        <td>
          <button class="Number" onclick="Number_Click(8)">8</button>
        </td>
        <td>
          <button class="Number" onclick="Number_Click(9)">9</button>
        </td>
        <td>
          <button class="Operator" onclick="Plus_Click()">+</button>
        </td>
      </tr>
      ...
<tr>
        <td>
          <button class="Number" onclick="Number_Click(0)">0</button>
        </td>
        <td>
          <button class="Operator" onclick="Clear_Click()">C</button>
        </td>
        <td>
          <button class="Operator" onclick="Equal_Click()">=</button>
        </td>
        <td>
          <button class="Operator" onclick="Divide_Click()">/</button>
        </td>
      </tr>
    </table>
  </body>
</html>

HTML ページの分離コードの役割は、JavaScript コードが再生されます。 確かに、あなたのファイル js\default.js このようなコードを見つけます。 私の電卓­PresentationModel、標準 C++ のクラスのためできません呼び出す JavaScript の部分から直接、しかし、それを直接、C + ブリッジ経由でできるないこと c++/cli CX コンポーネント — Calculator::View::CalcView。

この JavaScript からコンポーネントのインスタンス化は default.js ファイルで、次の宣言と同様に簡単です:

// This is JavaScript code, instancing a C++/CX proxy to my PresentationModel
var nativeBridge = new Calculator.View.CalcView();

このアプローチの例としては、等号 (=) のボタンを押すと次の JavaScript 関数の呼び出しをトリガーされます。

function Equal_Click() {
    display_.textContent = nativeBridge.equal_click();
}

CalcView::equal_click は、「ネイティブ私標準 C++ CalculatorPresentationModel との協議」への呼び出しを伝播します。

String^ CalcView::equal_click() {
  presentationModel_->ClickedOperator(OpNone);
  return get_display();
}
 
String^ CalcView::get_display() {
  return (presentationModel_->GetErrorState() != ErrNone) ?
L"ERROR!" :
    safe_cast<int64_t>(presentationModel_->GetValue()).ToString();
}

この特定のシナリオで、C + + CX コンポーネント CalcView ちょうど標準 C++ PresentationModel に、すべての要求を転送します (シーケンス図でを参照してください図 15)。 我々 が再利用可能な C++ コンポーネントへの道も避けることはできません (を参照してください図 15)。

The Sequence Diagram for the Equal Sign Button in the Hybrid HTML-C++ Version図 15 ハイブリッド HTML C++ バージョンで等号 (=) のボタンのシーケンス図

C + + CX プロキシを手動で作成する必要があります、関連付けられているコストを無視するべきではないです。 それでも、私は私のシナリオで CalculatorPresentationModel で行うにコンポーネントを再利用することによる利点分散できます。

先に行くし、アクションの HTML バージョンを表示するには、f5 キーを押します。 Windows 8 で新規のフレームワークに元のチャンネル (MFC 私の場合) を落とすことがなく拡大する、既存の C++ コードを再利用する方法を説明しました。 我々 は今、いくつかの最終的な反射準備ができました。

こんにちは (現実) の世界 !

私への移植のシナリオは、特定のケースで誰かの特定のケースではないかもしれないあなたの特定のケースではないかもしれないです。 多くの私がここで示した MFC 電卓のシナリオに適用され、いたを移植する場合、別のアプリケーションに、WRL な決定を下す可能性があります。 その結果、アプリケーションの移植に関するいくつかの一般的な結論はここにあります。

  • プレーンの標準オブジェクト — これらのサードパーティ製 Api と特定の関係のない — 最大再利用性と、いいえまたは低コストの移植性があります。 対照的に、オブジェクトが MFC、Qt、WRL などの非標準の Api への明示的な関係があると再利用性が拘束されます。 たとえば、MFC は、Windows のデスクトップでのみ利用可能です。 Qt, すべてではありません、他の一方で、他の環境で現在です。 このような場合に、アプリケーション オブジェクトの「話」クラスを抽象化することによって、再利用性をむしばむ混合物を避けます。 その後 3 番目パーティー注意して実装を作成するこれらのクラスから派生します。 ICalculatorView (抽象クラス) とその実装を CCalcDlg と XamlCalc::CalcView で何を見てください。 Windows 8 開発 WRL Api とこれに精通して得る Win32 Api の彼らが交換しています。 多くの情報を見つけることができます bit.ly/IBKphR
  • 私の目標は、デスクトップ上で既に持っていた Windows ランタイムでを模倣するだったのでプレゼンテーション モデル パターンを適用します。 彼らは多くの意味をなさない場合機能をカットする場合があります — など携帯電話の電子メール アプリケーション内のテキストにスタイルを適用します。 またはあなたの新しいターゲットのプラットフォームを活用して機能を追加するかもしれない — 例えば、画像イメージ ビューアー アプリケーションでマルチタッチを介してストレッチについて考える。 その場合は、別のデザイン パターンはより適するかもしれない。
  • 昔、プレゼンテーション モデルと低いメンテナンス費用のビジネス継続性を維持するために最適です。 これは私が Windows ストア バージョンのアプリの関係を切断せず元の MFC オプションを好むお客様に提供できます。 私は CalculatorPresentationModel のような再利用可能なコンポーネントがある限り、2 つのチャンネル (XAML と MFC または HTML および MFC) を維持する 2 倍のコストではありません。
  • アプリケーションの全体的な再利用性は、対 (第三者によって維持されるコンポーネントと見なされます) 特定のバージョンを維持するためのコードの行のすべてのバージョンに共通するコード行の割合によって決定されます。 どこアプリケーションが大きく (OpenGL と iOS のセンサーを活用して、拡張現実アプリ) などの非標準の Api に依存している場合があります。 再利用率は、あなたが最終的にコンポーネントの再利用性概念の 1 つ以外のことがなくアプリケーションを移植する場合がありますので、低することができます。
  • 人が悪い、既存のアプリケーション設計が求める、あなたへの移植の仕事は非常に難しくなってを開始しないでください。 それは代わりにリファクタリングを開始します。 アジャイル方法論で成熟した、堅牢な高い再利用アーキテクチャ向けではないと注意してください。 彼らが強調するソフトウェア配信です。 それは暗闇の中で設計を決定するは容易ではない、一般的な将来の再利用性と移植性のための拡張可能なソフトウェアを作る多くの経験が必要です。
  • あなたは、Windows 8、iOS や Android にアプリケーションが意図それをこれらのプラットフォームの市場を通じ販売を移植可能性があります。 この場合、アプリケーションが承認される前に認証プロセスを渡す必要があります注意してください (bit.ly/L0sY9i)。 これは、ことはのあなたの元のバージョン (タッチ最初、魅力となど) などで意図 UI 動作をサポートするを強制的でした。 一定の基準を満たすために失敗して拒否されてアプリケーションに可能性があります。 このような「コンプライアンス」見過ごしてはいけないときコストを見積もる。

挑戦

新しい Windows ランタイムおよびまだユビキタスの Windows デスクトップには、余分な支払いをしたくない開発者に挑戦を提起のプラットフォームごとの個別のアプリケーションを維持するコスト。 この資料では、私は実証既存コードベースのことだけでなく新しいチャネルを有効に活用できますが、既存の品質のリファクタリングを改善するためにもコードベースします。

Diego Dagumソフトウェア アーキテクトと 20 年以上の業界での経験を持つトレーナーです。 彼は到達することができます email@diegodagum.com

この記事のレビュー、次技術専門家のおかげで。 マリウス Bancila、エンジェル イエス ヘルナンデスと Windows 8 チーム