Procedura dettagliata: hosting di contenuto WPF in Win32

Windows Presentation Foundation (WPF) offre un ambiente avanzato per la creazione di applicazioni. Tuttavia, quando si ha un notevole investimento nel codice Win32, potrebbe essere più efficace aggiungere funzionalità WPF all'applicazione invece di riscrivere il codice originale. WPF offre un meccanismo semplice per l'hosting di contenuto WPF in una finestra Win32.

Questa esercitazione descrive come scrivere un'applicazione di esempio, Hosting di contenuto WPF in un esempio di finestra Win32, che ospita contenuto WPF in una finestra Win32. È possibile estendere questo esempio per ospitare qualsiasi finestra Win32. Poiché prevede la combinazione di codice gestito e non gestito, l'applicazione viene scritta in C++/CLI.

Requisiti

Questa esercitazione presuppone una familiarità di base con la programmazione WPF e Win32. Per un'introduzione di base alla programmazione WPF, vedere Introduzione. Per un'introduzione alla programmazione Win32, dovresti fare riferimento a uno dei numerosi libri sull'argomento, in particolare Programmazione di Windows di Charles Petzold.

Poiché l'esempio che accompagna questa esercitazione viene implementato in C++/CLI, questa esercitazione presuppone familiarità con l'uso di C++ per programmare l'API Windows e una conoscenza della programmazione del codice gestito. La familiarità con C++/CLI è utile ma non essenziale.

Nota

Questa esercitazione include numerosi esempi di codice relativi all'esempio associato. Tuttavia, per una questione di leggibilità, il codice di esempio completo non è compreso. Per il codice di esempio completo, vedere Esempio di hosting di contenuto WPF in una finestra Win32.

Procedura di base

Questa sezione descrive la procedura di base usata per ospitare contenuto WPF in una finestra Win32. Le sezioni rimanenti illustrano in dettaglio i vari passaggi.

La chiave per ospitare contenuto WPF in una finestra Win32 è la HwndSource classe . Questa classe esegue il wrapping del contenuto WPF in una finestra Win32, consentendo l'incorporamento nell'interfaccia utente (UI) come finestra figlio. L'approccio seguente combina Win32 e WPF in una singola applicazione.

  1. Implementare il contenuto WPF come classe gestita.

  2. Implementare un'applicazione Windows con C++/CLI. Se si inizia con un'applicazione esistente e un codice C++ non gestito, in genere è possibile abilitarlo per chiamare il codice gestito modificando le impostazioni del progetto in modo da includere il flag del /clr compilatore.

  3. Impostare il modello di threading su apartment a thread singolo (STA).

  4. Gestire la notifica WM_CREATE nella routine della finestra ed eseguire le operazioni seguenti:

    1. Creare un nuovo oggetto HwndSource con la finestra padre come parametro parent.

    2. Creare un'istanza della classe di contenuto WPF.

    3. Assegnare un riferimento all'oggetto contenuto WPF alla RootVisual proprietà dell'oggetto HwndSource.

    4. Ottenere HWND per il contenuto. La proprietà Handle dell'oggetto HwndSource contiene l'handle di finestra (HWND). Per ottenere un HWND utilizzabile nella parte non gestita dell'applicazione, eseguire il cast di Handle.ToPointer() a un HWND.

  5. Implementare una classe gestita che contiene un campo statico per contenere un riferimento al contenuto WPF. Questa classe consente di ottenere un riferimento al contenuto WPF dal codice Win32.

  6. Assegnare il contenuto WPF al campo statico.

  7. Ricevere notifiche dal contenuto WPF collegando un gestore a uno o più eventi WPF.

  8. Comunicare con il contenuto WPF usando il riferimento archiviato nel campo statico per impostare le proprietà e così via.

Nota

È anche possibile usare il contenuto WPF. Tuttavia, dovrai compilarlo separatamente come libreria a collegamento dinamico (DLL) e fare riferimento a tale DLL dall'applicazione Win32. La parte restante della procedura è simile a quella appena descritta.

Implementazione dell'applicazione host

Questa sezione descrive come ospitare contenuto WPF in un'applicazione Win32 di base. Il contenuto stesso viene implementato in C++/CLI come classe gestita. Per la maggior parte, è semplice programmazione WPF. Gli aspetti principali dell'implementazione del contenuto vengono illustrati in Implementazione del contenuto WPF.

Applicazione di base

Il punto di partenza per l'applicazione host consiste nel creare un modello di Visual Studio 2005.

  1. Aprire Visual Studio 2005 e selezionare Nuovo progetto dal menu File .

  2. Selezionare Win32 nell'elenco dei tipi di progetto Visual C++. Se il linguaggio predefinito non è C++, questi tipi di progetto sono disponibili in Altri linguaggi.

  3. Selezionare un modello Progetto Win32, assegnare un nome al progetto e fare clic su OK per avviare la Creazione guidata applicazione Win32.

  4. Accettare impostazioni predefinite della procedura guidata e fare clic su Fine per avviare il progetto.

Il modello crea un'applicazione Win32 di base, tra cui:

  • Un punto di ingresso per l'applicazione.

  • Una finestra, con una procedura di finestra associata (WndProc).

  • Menu con intestazioni File e Guida . Il menu File include un elemento Exit che chiude l'applicazione. Il menu ? contiene un elemento Informazioni su che consente di avviare una finestra di dialogo semplice.

Prima di iniziare a scrivere codice per ospitare il contenuto WPF, è necessario apportare due modifiche al modello di base.

La prima consiste nel compilare il progetto come codice gestito. Per impostazione predefinita, il progetto viene compilato come codice non gestito. Tuttavia, poiché WPF viene implementato nel codice gestito, il progetto deve essere compilato di conseguenza.

  1. Fare clic con il pulsante destro del mouse sul nome del progetto in Esplora soluzioni e scegliere Proprietà dal menu contestuale per avviare la finestra di dialogo Pagine delle proprietà.

  2. Nella visualizzazione albero nel riquadro di sinistra selezionare Proprietà di configurazione.

  3. Selezionare il supportoCommon Language Runtime dall'elenco Impostazioni predefinite progetto nel riquadro di destra.

  4. Selezionare Supporto Common Language Runtime Support (/clr) dall'elenco a discesa.

Nota

Questo flag del compilatore consente di usare codice gestito nell'applicazione, ma il codice non gestito verrà comunque compilato come in precedenza.

WPF usa il modello di threading apartment a thread singolo (STA). Per funzionare correttamente con il codice del contenuto WPF, è necessario impostare il modello di threading dell'applicazione su STA applicando un attributo al punto di ingresso.

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

Hosting del contenuto WPF

Il contenuto WPF è un'applicazione di immissione di indirizzi semplice. È costituito da diversi controlli TextBox nei quali immettere nome utente, indirizzo e così via. Sono disponibili anche due Button controlli, OK e Cancel. Quando l'utente fa clic su OK, il gestore eventi del Click pulsante raccoglie i dati dai TextBox controlli, lo assegna alle proprietà corrispondenti e genera un evento personalizzato, OnButtonClicked. Quando l'utente fa clic su Cancel, il gestore genera semplicemente OnButtonClicked. L'oggetto argomento dell'evento per OnButtonClicked contiene un campo booleano che indica il pulsante scelto.

Il codice per ospitare il contenuto WPF viene implementato in un gestore per la notifica di WM_CREATE nella finestra host.

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;

Il GetHwnd metodo accetta informazioni sulle dimensioni e sulla posizione più l'handle della finestra padre e restituisce l'handle di finestra del contenuto WPF ospitato.

Nota

Non è possibile usare una direttiva #using per lo spazio dei nomi System::Windows::Interop, in quanto si creerebbe un conflitto di nomi tra la struttura MSG nello spazio dei nomi e la struttura MSG dichiarata in winuser.h. Al contrario, occorre usare nomi completi per accedere al contenuto dello spazio dei nomi.

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();
}

Non è possibile ospitare il contenuto WPF direttamente nella finestra dell'applicazione. Al contrario, si crea prima di tutto un HwndSource oggetto per eseguire il wrapping del contenuto WPF. Questo oggetto è fondamentalmente una finestra progettata per ospitare un contenuto WPF. L'oggetto HwndSource viene ospitato nella finestra padre creandolo come figlio di una finestra Win32 che fa parte dell'applicazione. I HwndSource parametri del costruttore contengono molte delle stesse informazioni che verrebbero passate a CreateWindow quando si crea una finestra figlio Win32.

Creare quindi un'istanza dell'oggetto contenuto WPF. In questo caso, il contenuto WPF viene implementato come classe separata, , WPFPageusando C++/CLI. È anche possibile implementare il contenuto WPF con XAML. A tale scopo, tuttavia, è necessario configurare un progetto separato e compilare il contenuto WPF come DLL. È possibile aggiungere un riferimento a tale DLL al progetto e usarlo per creare un'istanza del contenuto WPF.

Il contenuto WPF viene visualizzato nella finestra figlio assegnando un riferimento al contenuto WPF alla RootVisual proprietà dell'oggetto HwndSource.

La riga di codice successiva associa un gestore eventi, WPFButtonClicked, all'evento di contenuto OnButtonClicked WPF. Questo gestore viene chiamato quando l'utente fa clic sul pulsante OK o Cancel. Per altre informazioni su questo gestore eventi, vedere Comunicazione con il contenuto WPF.

La riga finale del codice illustrata restituisce l'handle della finestra (HWND) associato all'oggetto HwndSource. Puoi usare questo handle dal codice Win32 per inviare messaggi alla finestra ospitata, anche se l'esempio non lo fa. L'oggetto HwndSource genera un evento ogni volta che riceve un messaggio. Per elaborare i messaggi, chiamare il metodo AddHook per associare un gestore di messaggi, quindi elaborare i messaggi in tale gestore.

Riferimento al contenuto WPF

Per molte applicazioni, sarà necessario comunicare con il contenuto WPF in un secondo momento. Ad esempio, potrebbe essere necessario modificare le proprietà del contenuto WPF o, ad esempio, che l'oggetto HwndSource ospiti contenuto WPF diverso. A tale scopo, è necessario un riferimento all'oggetto HwndSource o al contenuto WPF. L'oggetto HwndSource e il relativo contenuto WPF associato rimangono in memoria fino a quando non si elimina l'handle della finestra. Tuttavia, la variabile assegnata all'oggetto HwndSource uscirà dall'ambito non appena si esce dalla procedura di finestra. Il modo personalizzato per gestire questo problema con le applicazioni Win32 consiste nell'usare una variabile statica o globale. Sfortunatamente, non è possibile assegnare un oggetto gestito ai suddetti tipi di variabili. È possibile assegnare l'handle della finestra associato all'oggetto HwndSource a una variabile globale o statica, ma ciò non consentirà di accedere all'oggetto in questione.

La soluzione più semplice a questo problema consiste nell'implementare una classe gestita contenente un insieme di campi statici che a loro volta contengono i riferimenti agli oggetti gestiti ai quali si vuole accedere. Nell'esempio viene utilizzata la WPFPageHost classe per contenere un riferimento al contenuto WPF, oltre ai valori iniziali di una serie di proprietà che potrebbero essere modificate in un secondo momento dall'utente. La classe viene definita nell'intestazione.

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;
};

La seconda parte della funzione GetHwnd assegna valori ai suddetti campi che verranno usati in un secondo momento, con myPage ancora nell'ambito.

Comunicazione con il contenuto WPF

Esistono due tipi di comunicazione con il contenuto WPF. L'applicazione riceve informazioni dal contenuto WPF quando l'utente fa clic sui pulsanti OK o Annulla . L'applicazione ha anche un'interfaccia utente che consente all'utente di modificare varie proprietà del contenuto WPF, ad esempio il colore di sfondo o le dimensioni predefinite del carattere.

Come accennato in precedenza, quando l'utente fa clic su uno dei pulsanti il contenuto WPF genera un OnButtonClicked evento. L'applicazione associa un gestore a questo evento per ricevere le notifiche. Se è stato fatto clic sul pulsante OK , il gestore ottiene le informazioni utente dal contenuto WPF e lo visualizza in un set di controlli statici.

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: ");
    }
}

Il gestore riceve un oggetto argomento evento personalizzato dal contenuto WPF, MyPageEventArgs. La proprietà dell'oggetto IsOK è impostata su true se è stato fatto clic sul pulsante OK e false se è stato fatto clic sul pulsante Annulla .

Se è stato fatto clic sul pulsante OK , il gestore ottiene un riferimento al contenuto WPF dalla classe contenitore. Raccoglie quindi le informazioni utente contenute nelle proprietà del contenuto WPF associate e usa i controlli statici per visualizzare le informazioni nella finestra padre. Poiché i dati del contenuto WPF sono sotto forma di stringa gestita, è necessario effettuare il marshalling per l'uso da parte di un controllo Win32. Se è stato fatto clic sul pulsante Cancel, il gestore cancella i dati dai controlli statici.

L'interfaccia utente dell'applicazione fornisce un set di pulsanti di opzione che consentono all'utente di modificare il colore di sfondo del contenuto WPF e diverse proprietà correlate al tipo di carattere. Nell'esempio seguente viene illustrato un estratto della procedura di finestra (WndProc) dell'applicazione, nonché la gestione dei messaggi tramite la quale è possibile impostare varie proprietà in messaggi diversi, incluso il colore di sfondo. La parte restante è simile, pertanto non viene illustrata. Vedere l'esempio completo per i dettagli e il contesto.

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;

Per impostare il colore di sfondo, ottenere un riferimento al contenuto WPF (hostedPage) da WPFPageHost e impostare la proprietà colore di sfondo sul colore appropriato. Nell'esempio vengono usate tre opzioni di colore: il colore originale, verde chiaro o salmone chiaro. Il colore di sfondo originale viene archiviato come campo statico nella classe WPFPageHost. Per impostare gli altri due colori, creare un nuovo oggetto SolidColorBrush e passare al costruttore un valore di colore statico dall'oggetto Colors.

Implementazione della pagina WPF

È possibile ospitare e usare il contenuto WPF senza alcuna conoscenza dell'implementazione effettiva. Se il contenuto WPF era stato incluso in una DLL separata, potrebbe essere stato compilato in qualsiasi linguaggio CLR (Common Language Runtime). Di seguito è riportata una breve procedura dettagliata dell'implementazione di C++/CLI usata nell'esempio. Questa sezione contiene le sottosezioni seguenti.

Layout

Gli elementi dell'interfaccia utente nel contenuto WPF sono costituiti da cinque TextBox controlli, con i controlli associati Label : Nome, Indirizzo, Città, Stato e Zip. Ci sono anche due Button controlli, OK e Cancel

Il contenuto WPF viene implementato nella WPFPage classe . Il layout viene gestito mediante un apposito elemento Grid. La classe eredita da Grid, che lo rende effettivamente l'elemento radice del contenuto WPF.

Il costruttore di contenuto WPF accetta la larghezza e l'altezza necessarie e ridimensiona di Grid conseguenza. Definisce quindi il layout di base creando un set di ColumnDefinition oggetti e RowDefinition e aggiungendoli rispettivamente alla base ColumnDefinitions degli oggetti e RowDefinitions alle Grid raccolte. Viene così definita una griglia di cinque righe e sette colonne, le cui dimensioni sono determinate dal contenuto delle celle.

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]);
  }

Successivamente, il costruttore aggiunge gli elementi dell'interfaccia Gridutente a . Il primo elemento è il testo del titolo, ovvero un controllo Label centrato nella prima riga della griglia.

//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);

La riga successiva contiene il controllo Label Name e il controllo TextBox associato. Dal momento che per ogni coppia etichetta/casella di testo viene usato lo stesso codice, questo viene collocato in una coppia di metodi privati e usato per tutte e cinque le coppie etichetta/casella di testo. I metodi creano il controllo appropriato e chiamano i metodi Grid e SetColumn statici della classe SetRow per posizionare i controlli nella cella appropriata. Una volta creato il controllo, nell'esempio viene chiamato il metodo Add sulla proprietà Children di Grid per aggiungere il controllo alla griglia. Il codice usato per aggiungere le coppie etichetta/casella di testo restanti è simile. Vedere il codice di esempio per i dettagli.

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

D seguito viene riportata l'implementazione dei due metodi:

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;
}

Infine, l'esempio aggiunge i pulsanti OK e Cancel e associa un gestore eventi ai relativi Click eventi.

//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);

Restituzione dei dati alla finestra host

Facendo clic su un pulsante, viene generato il rispettivo evento Click. La finestra host potrebbe semplicemente associare i gestori a questi eventi e ottenere i dati direttamente dai controlli TextBox. Nell'esempio viene usato un approccio meno diretto. Gestisce l'oggetto Click all'interno del contenuto WPF e quindi genera un evento OnButtonClickedpersonalizzato per notificare il contenuto WPF. In questo modo, il contenuto WPF può eseguire una convalida dei parametri prima di inviare una notifica all'host. Il gestore ottiene il testo dai controlli TextBox e lo assegna a proprietà pubbliche, dalle quali l'host può recuperare le informazioni.

Dichiarazione di evento in WPFPage.h:

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

Gestore eventi Click in WPFPage.cpp:

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));
}

Impostazione delle proprietà WPF

L'host Win32 consente all'utente di modificare diverse proprietà del contenuto WPF. Dal lato Win32, è semplicemente una questione di modifica delle proprietà. L'implementazione nella classe di contenuto WPF è leggermente più complessa, perché non esiste una singola proprietà globale che controlla i tipi di carattere per tutti i controlli. La proprietà adatta per ogni controllo viene modificata nelle funzioni di accesso dell'insieme di proprietà. Nell'esempio seguente viene illustrato il codice per la DefaultFontFamily proprietà . Impostando la proprietà, viene chiamato un metodo privato che a sua volta imposta le proprietà FontFamily per i vari controlli.

Da WPFPage.h:

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

Da 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;
}

Vedi anche