次の方法で共有


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

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

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

要求事項

このチュートリアルでは、WPF と Win32 の両方のプログラミングに関する基本的な知識を前提としています。 WPF プログラミングの基本的な概要については、「 作業の開始」を参照してください。 Win32 プログラミングの概要については、このテーマに関する多数の書籍、特に Charles Petzold による プログラミング ウィンドウ を参照する必要があります。

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

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

基本的な手順

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

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

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

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

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

  4. ウィンドウ プロシージャで WM_CREATE通知を処理し、次の操作を行います。

    1. 親ウィンドウをHwndSource パラメーターとして使用して、新しいparent オブジェクトを作成します。

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

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

    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 コントロールで構成されます。 Button コントロールと Cancel コントロールの 2 つのもあります。 ユーザーが [OK] をクリックすると、ボタンの Click イベント ハンドラーは、 TextBox コントロールからデータを収集し、対応するプロパティに割り当て、カスタム イベントを発生 OnButtonClicked。 ユーザーが [ キャンセル] をクリックすると、ハンドラーは単に 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別のクラスとして実装されます。 XAML を使用して WPF コンテンツを実装することもできます。 ただし、これを行うには、別のプロジェクトを設定し、WPF コンテンツを DLL としてビルドする必要があります。 その DLL への参照をプロジェクトに追加し、その参照を使用して WPF コンテンツのインスタンスを作成できます。

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

次のコード行は、イベント ハンドラー ( WPFButtonClicked) を WPF コンテンツ OnButtonClicked イベントにアタッチします。 このハンドラーは、ユーザーが [ OK] または [キャンセル ] ボタンをクリックしたときに呼び出されます。 このイベント ハンドラーの詳細については、 communicating_with_the_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 プロパティは、[true ボタンがクリックされた場合はに設定され、[false] ボタンがクリックされた場合はされます。

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

アプリケーション 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;

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

WPF ページの実装

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

レイアウト

WPF コンテンツの UI 要素は、5 つの TextBox コントロールで構成され、関連付けられた Label コントロール (Name、Address、City、State、Zip) が含まれます。 また、2 つの Button コントロールがあります。 OKCancel

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

WPF コンテンツ コンストラクターは、必要な幅と高さを受け取り、それに応じて Grid のサイズを設定します。 次に、一連の ColumnDefinition オブジェクトと RowDefinition オブジェクトを作成し、 Grid オブジェクトベースの ColumnDefinitionsRowDefinitions コレクションにそれぞれ追加することで、基本的なレイアウトを定義します。 これにより、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に追加します。 最初の要素はタイトル テキストです。これは、グリッドの最初の行の中央に配置される 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);

次の行には、Name 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] ボタンと [キャンセル] ボタンを追加し、イベント ハンドラーを 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;
}

こちらも参照ください