チュートリアル: Win32 での WPF コンテンツのホスト

Windows Presentation Foundation (WPF) では、アプリケーションを作成するための充実した環境が提供されます。 ただし、Win32 コードにかなりの投資がある場合は、元のコードを書き換えるより、アプリケーションに WPF の機能を追加するほうがより効果的であることがあります。 WPF では、Win32 ウィンドウで WPF コンテンツをホストする簡単なメカニズムが提供されます。

このチュートリアルでは、Win32 ウィンドウで WPF コンテンツをホストするサンプル アプリケーション (Win32 ウィンドウでの WPF コンテンツのホストのサンプル) の作成方法について説明します。 このサンプルを拡張すると、いずれの Win32 ウィンドウでもホストできます。 マネージド コードとアンマネージド コードの混在が関係しているため、このアプリケーションは C++/CLI で記述されます。

必要条件

このチュートリアルでは、WPF と Win32 の両方のプログラミングについて基本的な知識があることを前提としています。 WPF のプログラミングの基本的な概要については、概要に関する記事を参照してください。 Win32 のプログラミングの概要については、この主題に関する数多くの書籍、特に『Programming Windows (プログラミング Windows) 』(Charles Petzold 著) を参照することをお勧めします。

このチュートリアルに付属するサンプルは C++/CLI で実装されているため、このチュートリアルでは C++ を使用した Windows API のプログラミングの知識があることと、マネージド コード プログラミングを理解していることを前提としています。 C++/CLI の知識があることは、役立ちますが、必須ではありません。

注意

このチュートリアルには、関連するサンプルからのコード例が多数含まれています。 しかし、読みやすくするため、完全なサンプル コードは含まれていません。 完全なサンプル コードについては、Win32 ウィンドウでの WPF コンテンツのホストのサンプルに関するページを参照してください。

基本手順

このセクションでは、Win32 ウィンドウで WPF コンテンツをホストするために使用する基本手順について概説します。 残りのセクションでは、各手順の詳細について説明します。

Win32 のウィンドウで WPF コンテンツをホストするときに鍵となるのは、HwndSource クラスです。 このクラスは、Win32 ウィンドウ内の WPF コンテンツをラップして、それを子ウィンドウとしてユーザー インターフェイス (UI) に組み込めるようにします。 次の方法では、Win32 と WPF を 1 つのアプリケーションに統合します。

  1. WPF コンテンツをマネージド クラスとして実装します。

  2. C++/CLI を使用して Windows アプリケーションを実装します。 既存のアプリケーションとアンマネージドの C++ コードで始める場合は、通常、/clr コンパイラ フラグを含むようにプロジェクトの設定を変更することで、マネージド コードを呼び出せるようにすることができます。

  3. スレッド処理モデルをシングル スレッド アパートメント (STA: Single Threaded Apartment) に設定します。

  4. ウィンドウのプロシージャで WM_CREATE 通知を処理してから、次のようにします。

    1. 新しい HwndSource オブジェクトを、親ウィンドウがその parent パラメーターとなるように指定して作成します。

    2. WPF コンテンツ クラスのインスタンスを作成します。

    3. WPF コンテンツ オブジェクトへの参照を、HwndSourceRootVisual プロパティに割り当てます。

    4. コンテンツの HWND を取得します。 Handle オブジェクトの HwndSource プロパティにウィンドウ ハンドル (HWND) が格納されます。 アプリケーションのアンマネージ部分で使用できる HWND を取得するには、Handle.ToPointer() を HWND にキャストします。

  5. WPF コンテンツへの参照を保持する静的フィールドを含むマネージド クラスを実装します。 このクラスを使用すると、Win32 コードから WPF コンテンツへの参照を取得できます。

  6. WPF コンテンツを静的フィールドに割り当てます。

  7. ハンドラーを 1 つ以上の WPF イベントにアタッチすることで、WPF コンテンツから通知を受け取ります。

  8. 静的フィールドに格納した参照を使用して WPF コンテンツと通信し、プロパティの設定などを行います。

注意

WPF コンテンツを使用することもできます。 ただし、その場合は、ダイナミックリンク ライブラリ (DLL) として別にコンパイルし、その DLL を Win32 アプリケーションから参照する必要があります。 手順の残りの部分は、前述の手順と同様です。

ホスト アプリケーションの実装

このセクションでは、基本的な Win32 アプリケーションで WPF コンテンツをホストする方法について説明します。 コンテンツ自体は、マネージド クラスとして C++/CLI で実装します。 ほとんどの部分が、簡単な WPF のプログラミングです。 コンテンツの実装の重要な側面については、「WPF ページの実装」で説明します。

基本的なアプリケーション

ホスト アプリケーションの開始点は、Visual Studio 2005 テンプレートを作成することでした。

  1. Visual Studio 2005 を開き、 [ファイル] メニューで [新しいプロジェクト] を選択します。

  2. Visual C++ プロジェクトの種類の一覧から、Win32 を選択します。 既定の言語が C++ ではない場合、このプロジェクトの種類は [他の言語] の下にあります。

  3. [Win32 プロジェクト] テンプレートを選択し、プロジェクトに名前を割り当ててから、 [OK] をクリックして、Win32 アプリケーション ウィザードを開始します。

  4. ウィザードの既定の設定をそのまま使用し、 [完了] をクリックしてプロジェクトを開始します。

このテンプレートでは、次のような基本的な Win32 アプリケーションが作成されます。

  • アプリケーションのエントリ ポイント。

  • 関連するウィンドウ プロシージャ (WndProc) を含むウィンドウ。

  • [ファイル][ヘルプ] の見出しのメニュー。 [ファイル] メニューには、アプリケーションを閉じる [終了] 項目があります。 [ヘルプ] メニューには、簡単なダイアログ ボックスを起動する [バージョン情報] 項目があります。

WPF コンテンツをホストするコードの記述を始める前に、基本のテンプレートに対して 2 つの変更を行う必要があります。

1 つ目は、プロジェクトをマネージド コードとしてコンパイルすることです。 既定では、プロジェクトはアンマネージ コードとしてコンパイルされます。 ただし、WPF はマネージド コードで実装されているため、プロジェクトは状況に応じてコンパイルする必要があります。

  1. ソリューション エクスプローラーで、プロジェクト名を右クリックし、コンテキスト メニューの [プロパティ] を選択して、 [プロパティ ページ] ダイアログ ボックスを開始します。

  2. 左ペインのツリー ビューで、 [構成プロパティ] を選択します。

  3. 右ペインの [プロジェクトの既定値] の一覧から、 [共通言語ランタイム] のサポートを選択します。

  4. ドロップダウン リスト ボックスから [共通言語ランタイム サポート (/clr)] を選択します。

注意

このコンパイラ フラグを使用すると、アプリケーションでマネージド コードを使用できますが、アンマネージド コードは以前と同様にコンパイルされます。

WPF では、シングル スレッド アパートメント (STA) スレッド処理モデルが使用されます。 WPF コンテンツのコードで正常に機能するためには、エントリ ポイントに属性を適用することで、アプリケーションのスレッド モデルを STA に設定する必要があります。

[System::STAThreadAttribute] //Needs to be an STA thread to play nicely with WPF
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{

WPF コンテンツのホスティング

WPF コンテンツは、単純な住所入力アプリケーションです。 それは、ユーザー名やアドレスなどを取得する複数の TextBox コントロールで構成されています。 また、 [OK][Cancel] という 2 つの Button コントロールがあります。 ユーザーが [OK] をクリックすると、ボタンの Click イベント ハンドラーで TextBox コントロールからデータが収集され、それが対応するプロパティに割り当てられて、カスタム イベント OnButtonClicked が生成されます。 ユーザーが [Cancel] をクリックすると、ハンドラーでは単に OnButtonClicked が生成されます。 OnButtonClicked のイベント引数オブジェクトには、どのボタンをクリックしたかを示すブール型フィールドが含まれています。

WPF コンテンツをホストするコードは、ホスト ウィンドウの WM_CREATE 通知用ハンドラーに実装されます。

case WM_CREATE :
  GetClientRect(hWnd, &rect);
  wpfHwnd = GetHwnd(hWnd, rect.right-375, 0, 375, 250);
  CreateDataDisplay(hWnd, 275, rect.right-375, 375);
  CreateRadioButtons(hWnd);
break;

GetHwnd メソッドは、サイズおよび位置の情報と親ウィンドウ ハンドルを受け取り、ホストされている WPF コンテンツのウィンドウ ハンドルを返します。

注意

#using 名前空間に System::Windows::Interop ディレクティブを使用することはできません。 使用すると、その名前空間の MSG 構造体と winuser.h で宣言した MSG 構造体の間で名前の競合が発生します。 代わりに、その名前空間のコンテンツにアクセスするための完全修飾名を使用する必要があります。

HWND GetHwnd(HWND parent, int x, int y, int width, int height)
{
    System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew System::Windows::Interop::HwndSourceParameters(
    "hi" // NAME
    );
    sourceParams->PositionX = x;
    sourceParams->PositionY = y;
    sourceParams->Height = height;
    sourceParams->Width = width;
    sourceParams->ParentWindow = IntPtr(parent);
    sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD; // style
    System::Windows::Interop::HwndSource^ source = gcnew System::Windows::Interop::HwndSource(*sourceParams);
    WPFPage ^myPage = gcnew WPFPage(width, height);
    //Assign a reference to the WPF page and a set of UI properties to a set of static properties in a class
    //that is designed for that purpose.
    WPFPageHost::hostedPage = myPage;
    WPFPageHost::initBackBrush = myPage->Background;
    WPFPageHost::initFontFamily = myPage->DefaultFontFamily;
    WPFPageHost::initFontSize = myPage->DefaultFontSize;
    WPFPageHost::initFontStyle = myPage->DefaultFontStyle;
    WPFPageHost::initFontWeight = myPage->DefaultFontWeight;
    WPFPageHost::initForeBrush = myPage->DefaultForeBrush;
    myPage->OnButtonClicked += gcnew WPFPage::ButtonClickHandler(WPFButtonClicked);
    source->RootVisual = myPage;
    return (HWND) source->Handle.ToPointer();
}

WPF コンテンツをアプリケーション ウインドウで直接ホストすることはできません。 代わりに、まず WPF コンテンツをラップするための HwndSource オブジェクトを作成します。 このオブジェクトは、基本的に、WPF コンテンツをホストするように設計されたウィンドウです。 HwndSource オブジェクトをアプリケーションの一部である Win32 ウィンドウの子として作成することで、このオブジェクトを親ウィンドウでホストします。 HwndSource コンストラクターのパラメーターには、Win32 の子ウィンドウの作成時に CreateWindow に渡す情報とほとんど同じ情報が含まれています。

次に、WPF コンテンツ オブジェクトのインスタンスを作成します。 この場合、WPF コンテンツは、C++/CLI を使用して、個別のクラス WPFPage として実装されます。 さらに、WPF コンテンツを XAML で実装することもできます。 ただし、これを行うためには、別のプロジェクトをセットアップしてから、WPF コンテンツを DLL としてビルドする必要があります。 その DLL への参照をプロジェクトに追加し、その参照を使用して WPF コンテンツのインスタンスを作成できます。

HwndSourceRootVisual プロパティに WPF コンテンツへの参照を割り当てて、子ウィンドウに WPF コンテンツを表示します。

次のコード行は、イベント ハンドラー WPFButtonClicked を WPF コンテンツの OnButtonClicked イベントにアタッチしています。 このハンドラーは、ユーザーが [OK] または [Cancel] ボタンをクリックすると呼び出されます。 このイベント ハンドラーの詳細な説明については、「WPF コンテンツとの通信」を参照してください。

示されているコードの最後の行は、HwndSource オブジェクトに関連付けられているウィンドウ ハンドル (HWND) を返します。 このハンドルを Win32 コードから使用して、ホストされたウィンドウにメッセージを送信できます。ただし、サンプルでは行っていません。 HwndSource オブジェクトは、メッセージを受信するたびにイベントを発生させます。 メッセージを処理するには、AddHook メソッドを呼び出してメッセージ ハンドラーをアタッチしてから、そのハンドラーでメッセージを処理します。

WPF コンテンツへの参照の保持

多くのアプリケーションでは、後で WPF コンテンツと通信する必要があります。 たとえば、WPF コンテンツのプロパティを変更したり、場合によっては HwndSource オブジェクトで異なる WPF コンテンツをホストするようにしたりできます。 そのためには、HwndSource オブジェクトまたは WPF コンテンツへの参照が必要です。 HwndSource オブジェクトとそれに関連する WPF コンテンツは、ウィンドウ ハンドルを破棄するまでメモリに残ります。 ただし、HwndSource オブジェクトに割り当てる変数は、ウィンドウ プロシージャから戻ると同時にスコープの外に出ます。 Win32 アプリケーションでこの問題を処理するためによく使用される方法は、静的変数またはグローバル変数を使用することです。 残念ながら、このような変数の種類に対してマネージド オブジェクトを割り当てることはできません。 HwndSource オブジェクトに関連付けられているウィンドウ ハンドルを、グローバル変数または静的変数に割り当てることができますが、オブジェクト自体にアクセスすることはできません。

この問題の最も簡単な解決法は、静的フィールドのセットを含むマネージド クラスを実装して、アクセスが必要なすべてのマネージド オブジェクトへの参照を保持することです。 サンプルでは、WPFPageHost クラスを使用して、WPF コンテンツへの参照、および後でユーザーが変更する可能性があるプロパティの数の初期値を保持します。 これは、ヘッダーで定義します。

public ref class WPFPageHost
{
public:
  WPFPageHost();
  static WPFPage^ hostedPage;
  //initial property settings
  static System::Windows::Media::Brush^ initBackBrush;
  static System::Windows::Media::Brush^ initForeBrush;
  static System::Windows::Media::FontFamily^ initFontFamily;
  static System::Windows::FontStyle initFontStyle;
  static System::Windows::FontWeight initFontWeight;
  static double initFontSize;
};

GetHwnd 関数の後半部分では、後に、myPage がスコープ内にある間に使用するため、対象のフィールドに値を割り当てます。

WPF コンテンツとの通信

WPF コンテンツとの通信には次の 2 種類があります。 ユーザーが [OK] または [キャンセル] をクリックすると、アプリケーションは WPF コンテンツから情報を受け取ります。 アプリケーションには、背景色や既定のフォント サイズなどのさまざまな WPF コンテンツのプロパティをユーザーが変更できるようにする UI があります。

前述のとおり、ユーザーがいずれかのボタンをクリックすると、WPF コンテンツによって OnButtonClicked イベントが発生します。 アプリケーションは、これらの通知を受信するため、このイベントにハンドラーをアタッチします。 [OK] ボタンがクリックされた場合は、ハンドラーによって WPF コンテンツからユーザー情報が取得され、一連の静的コントロールにそれが表示されます。

void WPFButtonClicked(Object ^sender, MyPageEventArgs ^args)
{
    if(args->IsOK) //display data if OK button was clicked
    {
        WPFPage ^myPage = WPFPageHost::hostedPage;
        LPCWSTR userName = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("Name: " + myPage->EnteredName).ToPointer();
        SetWindowText(nameLabel, userName);
        LPCWSTR userAddress = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("Address: " + myPage->EnteredAddress).ToPointer();
        SetWindowText(addressLabel, userAddress);
        LPCWSTR userCity = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("City: " + myPage->EnteredCity).ToPointer();
        SetWindowText(cityLabel, userCity);
        LPCWSTR userState = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("State: " + myPage->EnteredState).ToPointer();
        SetWindowText(stateLabel, userState);
        LPCWSTR userZip = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("Zip: " + myPage->EnteredZip).ToPointer();
        SetWindowText(zipLabel, userZip);
    }
    else
    {
        SetWindowText(nameLabel, L"Name: ");
        SetWindowText(addressLabel, L"Address: ");
        SetWindowText(cityLabel, L"City: ");
        SetWindowText(stateLabel, L"State: ");
        SetWindowText(zipLabel, L"Zip: ");
    }
}

ハンドラーでは、WPF コンテンツからカスタム イベント引数オブジェクト MyPageEventArgs を受信します。 オブジェクトの IsOK プロパティは、 [OK] ボタンがクリックされると true に設定され、 [Cancel] ボタンがクリックされると false に設定されます。

[OK] ボタンがクリックされた場合、ハンドラーによってコンテナー クラスから WPF コンテンツへの参照が取得されます。 その後、関連する WPF コンテンツのプロパティによって保持されるユーザー情報が収集され、静的コントロールを使用して情報が親ウィンドウに表示されます。 WPF コンテンツのデータはマネージド文字列の形式であるため、Win32 コントロールで使用するにはマーシャリングする必要があります。 [Cancel] ボタンがクリックされた場合、ハンドラーでは、スタティック コントロールからのデータがクリアされます。

アプリケーション UI には、ユーザーが WPF コンテンツの背景色を変更するために使用できるラジオ ボタンのセット、および複数のフォント関連のプロパティが用意されています。 次の例は、アプリケーションのウィンドウ プロシージャ (WndProc)、および背景色など、各種のメッセージに対してさまざまなプロパティを設定するそのプロシージャのメッセージ処理からの抜粋です。 その他は類似しているため、示していません。 詳細とコンテキストについては、完全なサンプルを参照してください。

case WM_COMMAND:
  wmId    = LOWORD(wParam);
  wmEvent = HIWORD(wParam);

  switch (wmId)
  {
  //Menu selections
    case IDM_ABOUT:
      DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
    break;
    case IDM_EXIT:
      DestroyWindow(hWnd);
    break;
    //RadioButtons
    case IDC_ORIGINALBACKGROUND :
      WPFPageHost::hostedPage->Background = WPFPageHost::initBackBrush;
    break;
    case IDC_LIGHTGREENBACKGROUND :
      WPFPageHost::hostedPage->Background = gcnew SolidColorBrush(Colors::LightGreen);
    break;
    case IDC_LIGHTSALMONBACKGROUND :
      WPFPageHost::hostedPage->Background = gcnew SolidColorBrush(Colors::LightSalmon);
    break;

背景色を設定するには、WPFPageHost から WPF コンテンツ (hostedPage) への参照を取得して、背景色のプロパティを適切な色に設定します。 サンプルでは、元の色、明るい緑、または明るいサーモン色の 3 つの色のオプションを使用します。 元の背景色は静的フィールドとして WPFPageHost クラスに格納されます。 他の 2 つの色を設定するには、新しい SolidColorBrush オブジェクトを作成して、Colors オブジェクトからコンストラクターに静的な色の値を渡します。

WPF ページの実装

実際の実装についての知識がなくても、WPF コンテンツをホストして使用することができます。 WPF コンテンツが別の DLL にパッケージ化されている場合は、任意の共通言語ランタイム (CLR) 言語でビルドされている可能性があります。 以下は、このサンプルで使用する C++/CLI の実装の簡単なチュートリアルです。 このセクションには、次のサブセクションが含まれています。

レイアウト

WPF コンテンツの UI 要素は、5 つの TextBox コントロール (名前、住所、市区町村、都道府県、郵便番号) と、関連する Label コントロールで構成されます。 また、 [OK][Cancel] という 2 つの Button コントロールがあります

WPF コンテンツは WPFPage クラスに実装されます。 レイアウトは、Grid レイアウト要素で処理されます。 クラスは Grid から継承され、実質的に WPF コンテンツのルート要素になります。

WPF コンテンツのコンストラクターは、必要な幅と高さを受け取り、それに合わせて Grid のサイズを調整します。 その後、ColumnDefinition オブジェクトと RowDefinition オブジェクトのセットが作成され、それらが Grid オブジェクトの基本の ColumnDefinitions および RowDefinitions コレクションにそれぞれ追加されることで、基本のレイアウトが定義されます。 これにより、5 つの行と、7 つの列のグリッドが定義され、セルの内容によって大きさが決定します。

WPFPage::WPFPage(int allottedWidth, int allotedHeight)
{
  array<ColumnDefinition ^> ^ columnDef = gcnew array<ColumnDefinition ^> (4);
  array<RowDefinition ^> ^ rowDef = gcnew array<RowDefinition ^> (6);

  this->Height = allotedHeight;
  this->Width = allottedWidth;
  this->Background = gcnew SolidColorBrush(Colors::LightGray);
  
  //Set up the Grid's row and column definitions
  for(int i=0; i<4; i++)
  {
    columnDef[i] = gcnew ColumnDefinition();
    columnDef[i]->Width = GridLength(1, GridUnitType::Auto);
    this->ColumnDefinitions->Add(columnDef[i]);
  }
  for(int i=0; i<6; i++)
  {
    rowDef[i] = gcnew RowDefinition();
    rowDef[i]->Height = GridLength(1, GridUnitType::Auto);
    this->RowDefinitions->Add(rowDef[i]);
  }

次に、コンストラクターは UI 要素を Grid に追加します。 最初の要素はタイトルのテキストです。これは、グリッドの 1 行目の中央に表示される Label コントロールです。

//Add the title
titleText = gcnew Label();
titleText->Content = "Simple WPF Control";
titleText->HorizontalAlignment = System::Windows::HorizontalAlignment::Center;
titleText->Margin = Thickness(10, 5, 10, 0);
titleText->FontWeight = FontWeights::Bold;
titleText->FontSize = 14;
Grid::SetColumn(titleText, 0);
Grid::SetRow(titleText, 0);
Grid::SetColumnSpan(titleText, 4);
this->Children->Add(titleText);

次の行には、名前の Label コントロールと関連する TextBox コントロールが格納されます。 ラベルとテキスト ボックスの各ペアに同じコードが使用されるため、コードはプライベート メソッドのペアに配置され、5 つのラベルとテキスト ボックスのペアすべてに使用されます。 メソッドは適切な制御を作成し、Grid クラスの静的な SetColumn および SetRow メソッドを呼び出して、適切なセルにコントロールを配置します。 コントロールが作成されると、サンプルは AddChildren プロパティの Grid メソッドを呼び出して、グリッドにコントロールを追加します。 残りのラベルとテキスト ボックスのペアを追加するコードは似ています。 詳細については、サンプル コードを参照してください。

//Add the Name Label and TextBox
nameLabel = CreateLabel(0, 1, "Name");
this->Children->Add(nameLabel);
nameTextBox = CreateTextBox(1, 1, 3);
this->Children->Add(nameTextBox);

2 つのメソッドの実装は、次のとおりです。

Label ^WPFPage::CreateLabel(int column, int row, String ^ text)
{
  Label ^ newLabel = gcnew Label();
  newLabel->Content = text;
  newLabel->Margin = Thickness(10, 5, 10, 0);
  newLabel->FontWeight = FontWeights::Normal;
  newLabel->FontSize = 12;
  Grid::SetColumn(newLabel, column);
  Grid::SetRow(newLabel, row);
  return newLabel;
}
TextBox ^WPFPage::CreateTextBox(int column, int row, int span)
{
  TextBox ^newTextBox = gcnew TextBox();
  newTextBox->Margin = Thickness(10, 5, 10, 0);
  Grid::SetColumn(newTextBox, column);
  Grid::SetRow(newTextBox, row);
  Grid::SetColumnSpan(newTextBox, span);
  return newTextBox;
}

最後に、サンプルでは [OK] ボタンと [Cancel] ボタンが追加され、Click イベントにイベント ハンドラーがアタッチされます。

//Add the Buttons and atttach event handlers
okButton = CreateButton(0, 5, "OK");
cancelButton = CreateButton(1, 5, "Cancel");
this->Children->Add(okButton);
this->Children->Add(cancelButton);
okButton->Click += gcnew RoutedEventHandler(this, &WPFPage::ButtonClicked);
cancelButton->Click += gcnew RoutedEventHandler(this, &WPFPage::ButtonClicked);

データをホスト ウィンドウに返す

いずれかのボタンをクリックすると、その Click イベントが発生します。 ホスト ウィンドウはこれらのイベントにハンドラーをアタッチして、TextBox コントロールから直接データを取得します。 サンプルは、いくぶん直接的ではない方法を使用します。 WPF コンテンツ内の Click を処理し、カスタム イベント OnButtonClicked を発生させて、WPF コンテンツに通知します。 これにより、ホストに通知する前に、WPF コンテンツでパラメーターを検証することができます。 ハンドラーは、TextBox コントロールからテキストを取得し、パブリック プロパティに割り当てます。ここからホストは情報を取得します。

WPFPage.h でのイベント宣言:

public:
  delegate void ButtonClickHandler(Object ^, MyPageEventArgs ^);
  WPFPage();
  WPFPage(int height, int width);
  event ButtonClickHandler ^OnButtonClicked;

WPFPage.cpp での Click イベント ハンドラー:

void WPFPage::ButtonClicked(Object ^sender, RoutedEventArgs ^args)
{

  //TODO: validate input data
  bool okClicked = true;
  if(sender == cancelButton)
    okClicked = false;
  EnteredName = nameTextBox->Text;
  EnteredAddress = addressTextBox->Text;
  EnteredCity = cityTextBox->Text;
  EnteredState = stateTextBox->Text;
  EnteredZip = zipTextBox->Text;
  OnButtonClicked(this, gcnew MyPageEventArgs(okClicked));
}

WPF のプロパティを設定する

Win32 ホストでは、ユーザーはいくつかの WPF コンテンツのプロパティを変更できます。 Win32 側では、これはプロパティの変更の問題にすぎません。 WPF コンテンツ クラスの実装は多少複雑になります。これは、1 つですべてのコントロールのフォントを制御するグローバル プロパティがないためです。 代わりに、各コントロールの適切なプロパティは、プロパティの set アクセサーで変更されます。 次の例では、DefaultFontFamily プロパティのコードを示します。 プロパティを設定すると、プライベート メソッドが呼び出され、さまざまなコントロールに FontFamily プロパティが設定されます。

WPFPage.h から:

property FontFamily^ DefaultFontFamily
{
  FontFamily^ get() {return _defaultFontFamily;}
  void set(FontFamily^ value) {SetFontFamily(value);}
};

WPFPage.cpp から:

void WPFPage::SetFontFamily(FontFamily^ newFontFamily)
{
  _defaultFontFamily = newFontFamily;
  titleText->FontFamily = newFontFamily;
  nameLabel->FontFamily = newFontFamily;
  addressLabel->FontFamily = newFontFamily;
  cityLabel->FontFamily = newFontFamily;
  stateLabel->FontFamily = newFontFamily;
  zipLabel->FontFamily = newFontFamily;
}

関連項目