Udostępnij za pośrednictwem


Wskazówki: Hosting zawartości WPF w Win32

Program Windows Presentation Foundation (WPF) udostępnia bogate środowisko do tworzenia aplikacji. Jednak jeśli masz znaczną inwestycję w kod Win32, może być bardziej skuteczne dodanie funkcji WPF do aplikacji zamiast ponownego zapisywania oryginalnego kodu. WPF zapewnia prosty mechanizm hostowania zawartości WPF w oknie Win32.

W tym samouczku opisano sposób pisania przykładowej aplikacji hostingu zawartości WPF w przykładzie okna Win32 hostującego zawartość WPF w oknie Win32. Ten przykład można rozszerzyć tak, aby hostować dowolne okno Win32. Ponieważ obejmuje mieszanie kodu zarządzanego i niezarządzanego, aplikacja jest napisana w języku C++/CLI.

Wymagania

W tym samouczku założono podstawową znajomość programowania zarówno WPF, jak i Win32. Aby zapoznać się z podstawowym wprowadzeniem do programowania WPF, zobacz Wprowadzenie. Aby zapoznać się z wprowadzeniem do programowania Win32, należy odwołać się do dowolnej z licznych książek na ten temat, w szczególności programowania windows autorstwa Charlesa Petzolda.

Ponieważ przykład dołączony do tego samouczka jest implementowany w języku C++/CLI, w tym samouczku przyjęto założenie znajomości używania języka C++ do programowania interfejsu API systemu Windows oraz zrozumienia programowania kodu zarządzanego. Znajomość języka C++/CLI jest przydatna, ale nie jest niezbędna.

Uwaga

Ten samouczek zawiera szereg przykładów kodu ze skojarzonego przykładu. Jednak w celu zapewnienia czytelności nie zawiera kompletnego przykładowego kodu. Pełny przykładowy kod można znaleźć w temacie Hostowanie zawartości WPF w przykładzie okna Win32.

Procedura podstawowa

W tej sekcji opisano podstawową procedurę służącą do hostowania zawartości WPF w oknie Win32. W pozostałych sekcjach opisano szczegóły poszczególnych kroków.

Kluczem do hostowania zawartości WPF w oknie Win32 jest HwndSource klasa . Ta klasa opakowuje zawartość WPF w oknie Win32, co pozwala na włączenie jej do interfejsu użytkownika jako okna podrzędnego. Poniższe podejście łączy win32 i WPF w jednej aplikacji.

  1. Zaimplementuj zawartość WPF jako klasę zarządzaną.

  2. Zaimplementuj aplikację systemu Windows przy użyciu języka C++/interfejsu wiersza polecenia. Jeśli zaczynasz od istniejącej aplikacji i niezarządzanego kodu języka C++, zwykle możesz włączyć wywoływanie kodu zarządzanego przez zmianę ustawień projektu w celu uwzględnienia flagi kompilatora /clr .

  3. Ustaw model wątkowy na jednowątkowy apartament (STA).

  4. Obsłuż powiadomienie WM_CREATEw procedurze okna i wykonaj następujące czynności:

    1. Utwórz nowy HwndSource obiekt z oknem nadrzędnym jako jego parent parametrem.

    2. Utwórz wystąpienie klasy zawartości WPF.

    3. Przypisz odwołanie do obiektu zawartości WPF do RootVisual właściwości HwndSource.

    4. Pobierz nazwę HWND dla zawartości. Właściwość HandleHwndSource obiektu zawiera uchwyt okna (HWND). Aby uzyskać HWND, którego można użyć w niezarządzanej części aplikacji, rzutuj Handle.ToPointer() na HWND.

  5. Zaimplementuj klasę zarządzaną zawierającą pole statyczne do przechowywania odwołania do zawartości WPF. Ta klasa umożliwia uzyskanie odwołania do zawartości WPF z kodu Win32.

  6. Przypisz zawartość WPF do pola statycznego.

  7. Odbieranie powiadomień z zawartości WPF przez dołączenie programu obsługi do co najmniej jednego zdarzenia WPF.

  8. Komunikacja z zawartością WPF przy użyciu odwołania przechowywanego w polu statycznym w celu ustawienia właściwości itd.

Uwaga

Możesz również użyć zawartości WPF. Należy jednak skompilować ją oddzielnie jako bibliotekę DLL (dynamic-link) i odwołać się do tej biblioteki DLL z aplikacji Win32. Pozostała część procedury jest podobna do przedstawionej powyżej.

Implementowanie aplikacji hosta

W tej sekcji opisano sposób hostowania zawartości WPF w podstawowej aplikacji Win32. Sama zawartość jest implementowana w języku C++/CLI jako klasa zarządzana. W większości przypadków jest to proste programowanie WPF. Kluczowe aspekty implementacji zawartości zostały omówione w temacie Implementowanie zawartości WPF.

Podstawowa aplikacja

Punktem wyjścia dla aplikacji hosta było utworzenie szablonu programu Visual Studio 2005.

  1. Otwórz program Visual Studio 2005 i wybierz pozycję Nowy projekt z menu Plik .

  2. Wybierz pozycję Win32 z listy typów projektów Visual C++. Jeśli domyślny język nie jest językiem C++, te typy projektów znajdziesz w obszarze Inne języki.

  3. Wybierz szablon projektu Win32, przypisz nazwę do projektu i kliknij przycisk OK, aby uruchomić Kreatora aplikacji Win32.

  4. Zaakceptuj ustawienia domyślne kreatora i kliknij przycisk Zakończ , aby uruchomić projekt.

Szablon tworzy podstawową aplikację Win32, w tym:

  • Punkt wejścia dla aplikacji.

  • Okno ze skojarzona procedura okna (WndProc).

  • Menu z nagłówkami Plik i Pomoc . W menu Plik znajduje się element Zakończ , który zamyka aplikację. Menu Pomoc zawiera element Informacje , który uruchamia proste okno dialogowe.

Przed rozpoczęciem pisania kodu do hostowania zawartości WPF należy wprowadzić dwie modyfikacje szablonu podstawowego.

Pierwszym z nich jest skompilowanie projektu jako kodu zarządzanego. Domyślnie projekt kompiluje się jako niezarządzany kod. Jednak ze względu na to, że WPF jest implementowany w kodzie zarządzanym, projekt musi być odpowiednio skompilowany.

  1. Kliknij prawym przyciskiem myszy nazwę projektu w Eksplorator rozwiązań i wybierz polecenie Właściwości z menu kontekstowego, aby uruchomić okno dialogowe Strony właściwości.

  2. Wybierz pozycję Właściwości konfiguracji w widoku drzewa w okienku po lewej stronie.

  3. Wybierz pozycję Obsługa środowiska uruchomieniowego języka wspólnego z listy Project Defaults (Ustawienia domyślne projektu) w okienku po prawej stronie.

  4. Z listy rozwijanej wybierz pozycję Obsługa środowiska uruchomieniowego języka wspólnego (/clr ).

Uwaga

Ta flaga kompilatora umożliwia używanie kodu zarządzanego w aplikacji, ale niezarządzany kod będzie nadal kompilowany tak jak poprzednio.

WPF używa modelu wątkowania jednowątkowego (STA). Aby prawidłowo pracować z kodem zawartości WPF, należy ustawić model wątków aplikacji na STA, stosując atrybut do punktu wejścia.

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

Hostowanie zawartości WPF

Zawartość WPF jest prostą aplikacją do wprowadzania adresów. Składa się z kilku TextBox kontrolek, które mają przyjmować nazwę użytkownika, adres itd. Istnieją również dwie Button kontrolki: OK i Anuluj. Gdy użytkownik kliknie przycisk OK, program obsługi zdarzeń przycisku Click zbiera dane z TextBox kontrolek, przypisuje je do odpowiednich właściwości i zgłasza zdarzenie niestandardowe. OnButtonClicked Gdy użytkownik kliknie przycisk Anuluj, program obsługi po prostu zgłosi OnButtonClickedelement . Obiekt argumentu zdarzenia dla OnButtonClicked elementu zawiera pole logiczne wskazujące, który przycisk został kliknięty.

Kod hostowania zawartości WPF jest implementowany w programie obsługi dla powiadomienia WM_CREATE w oknie hosta.

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;

Metoda GetHwnd pobiera informacje o rozmiarze i pozycji oraz uchwyt okna nadrzędnego i zwraca uchwyt okna hostowanej zawartości WPF.

Uwaga

Nie można użyć #using dyrektywy dla System::Windows::Interop przestrzeni nazw. Spowoduje to utworzenie kolizji nazw między strukturą MSG w tej przestrzeni nazw a strukturą MSG zadeklarowaną w pliku winuser.h. Zamiast tego należy używać w pełni kwalifikowanych nazw, aby uzyskać dostęp do zawartości tej przestrzeni nazw.

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

Nie można hostować zawartości WPF bezpośrednio w oknie aplikacji. Zamiast tego należy najpierw utworzyć HwndSource obiekt w celu opakowania zawartości WPF. Ten obiekt jest w zasadzie oknem przeznaczonym do hostowania zawartości WPF. Obiekt jest hostowany HwndSource w oknie nadrzędnym, tworząc go jako element podrzędny okna Win32 będącego częścią aplikacji. HwndSource Parametry konstruktora zawierają wiele tych samych informacji, które należy przekazać do polecenia CreateWindow podczas tworzenia okna podrzędnego Win32.

Następnie utworzysz wystąpienie obiektu zawartości WPF. W takim przypadku zawartość WPF jest implementowana jako oddzielna klasa , WPFPageprzy użyciu języka C++/CLI. Możesz również zaimplementować zawartość WPF za pomocą języka XAML. Jednak w tym celu należy skonfigurować oddzielny projekt i skompilować zawartość WPF jako bibliotekę DLL. Możesz dodać odwołanie do tej biblioteki DLL do projektu i użyć tego odwołania, aby utworzyć wystąpienie zawartości WPF.

Zawartość WPF jest wyświetlana w oknie podrzędnym, przypisując odwołanie do zawartości WPF do RootVisual właściwości HwndSource.

Następny wiersz kodu dołącza procedurę obsługi zdarzeń do WPFButtonClickedzdarzenia zawartości OnButtonClicked WPF. Ta procedura obsługi jest wywoływana, gdy użytkownik kliknie przycisk OK lub Anuluj . Zobacz communicating_with_the_WPF zawartości , aby uzyskać dalszą dyskusję na temat tego programu obsługi zdarzeń.

Ostatni wiersz pokazanego kodu zwraca uchwyt okna (HWND), który jest skojarzony z obiektem HwndSource . Możesz użyć tego uchwytu z kodu Win32 do wysyłania komunikatów do okna hostowanego, chociaż przykład nie robi tego. Obiekt HwndSource zgłasza zdarzenie za każdym razem, gdy otrzymuje komunikat. Aby przetworzyć komunikaty, wywołaj metodę AddHook , aby dołączyć procedurę obsługi komunikatów, a następnie przetworzyć komunikaty w tej procedurze obsługi.

Przechowywanie odwołania do zawartości WPF

W przypadku wielu aplikacji warto później komunikować się z zawartością WPF. Możesz na przykład zmodyfikować właściwości zawartości WPF lub hostować HwndSource inną zawartość WPF. W tym celu potrzebne jest odwołanie do HwndSource obiektu lub zawartości WPF. Obiekt HwndSource i skojarzona zawartość WPF pozostają w pamięci do momentu zniszczenia uchwytu okna. Jednak zmienna przypisana do HwndSource obiektu będzie wychodzić z zakresu zaraz po powrocie z procedury okna. Niestandardowym sposobem obsługi tego problemu z aplikacjami Win32 jest użycie zmiennej statycznej lub globalnej. Niestety nie można przypisać obiektu zarządzanego do tych typów zmiennych. Uchwyt okna skojarzony z obiektem HwndSource można przypisać do zmiennej globalnej lub statycznej, ale nie zapewnia dostępu do samego obiektu.

Najprostszym rozwiązaniem tego problemu jest zaimplementowanie klasy zarządzanej zawierającej zestaw pól statycznych do przechowywania odwołań do wszystkich zarządzanych obiektów, do których potrzebujesz dostępu. W przykładzie WPFPageHost użyto klasy do przechowywania odwołania do zawartości WPF oraz początkowych wartości wielu jego właściwości, które mogą zostać później zmienione przez użytkownika. Jest to zdefiniowane w nagłówku.

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

Druga część GetHwnd funkcji przypisuje wartości do tych pól do późniejszego użycia, chociaż myPage jest nadal w zakresie.

Komunikacja z zawartością WPF

Istnieją dwa typy komunikacji z zawartością WPF. Aplikacja odbiera informacje z zawartości WPF, gdy użytkownik kliknie przyciski OK lub Anuluj . Aplikacja ma również interfejs użytkownika, który umożliwia użytkownikowi zmianę różnych właściwości zawartości WPF, takich jak kolor tła lub domyślny rozmiar czcionki.

Jak wspomniano powyżej, gdy użytkownik kliknie dowolny przycisk, zawartość WPF zgłasza OnButtonClicked zdarzenie. Aplikacja dołącza program obsługi do tego zdarzenia, aby otrzymywać te powiadomienia. Jeśli przycisk OK został kliknięty, program obsługi pobiera informacje o użytkowniku z zawartości WPF i wyświetla go w zestawie kontrolek statycznych.

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

Procedura obsługi odbiera niestandardowy obiekt argumentu zdarzenia z zawartości WPF. MyPageEventArgs Właściwość obiektu IsOK jest ustawiona na true wartość , jeśli przycisk OK został kliknięty, a false jeśli przycisk Anuluj został kliknięty.

Jeśli przycisk OK został kliknięty, program obsługi pobiera odwołanie do zawartości WPF z klasy kontenera. Następnie zbiera informacje o użytkowniku przechowywane przez skojarzone właściwości zawartości WPF i używa kontrolek statycznych do wyświetlania informacji w oknie nadrzędnym. Ponieważ dane zawartości WPF są w postaci ciągu zarządzanego, musi być marshalowane do użytku przez kontrolkę Win32. Jeśli przycisk Anuluj został kliknięty, program obsługi czyści dane z kontrolek statycznych.

Interfejs użytkownika aplikacji udostępnia zestaw przycisków radiowych, które umożliwiają użytkownikowi modyfikowanie koloru tła zawartości WPF oraz kilka właściwości związanych z czcionką. W poniższym przykładzie przedstawiono fragment procedury okna aplikacji (WndProc) i jego obsługi komunikatów, który ustawia różne właściwości różnych komunikatów, w tym kolor tła. Pozostałe są podobne i nie są wyświetlane. Zobacz kompletny przykład, aby uzyskać szczegółowe informacje i kontekst.

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;

Aby ustawić kolor tła, pobierz odwołanie do zawartości WPF (hostedPage) z WPFPageHost i ustaw właściwość koloru tła na odpowiedni kolor. W przykładzie użyto trzech opcji kolorów: oryginalny kolor, jasnozielony lub jasny łosoś. Oryginalny kolor tła jest przechowywany jako pole statyczne w WPFPageHost klasie. Aby ustawić pozostałe dwa, należy utworzyć nowy SolidColorBrush obiekt i przekazać konstruktorowi wartość kolorów statycznych z Colors obiektu.

Implementowanie strony WPF

Możesz hostować i używać zawartości WPF bez znajomości rzeczywistej implementacji. Jeśli zawartość WPF została spakowana w osobnej biblioteki DLL, mogła zostać skompilowana w dowolnym języku środowiska uruchomieniowego języka wspólnego (CLR). Poniżej przedstawiono krótki przewodnik po implementacji języka C++/interfejsu wiersza polecenia, która jest używana w przykładzie. Ta sekcja zawiera następujące podsekcje.

Układ

Elementy interfejsu użytkownika w zawartości WPF składają się z pięciu TextBox kontrolek, z skojarzonymi Label kontrolkami: Name, Address, City, State i Zip. Istnieją również dwie Button kontrolki: OK i Anuluj

Zawartość WPF jest implementowana w WPFPage klasie . Układ jest obsługiwany za pomocą Grid elementu układu. Klasa dziedziczy z Gridklasy , co skutecznie sprawia, że element główny zawartości WPF.

Konstruktor zawartości WPF przyjmuje wymaganą szerokość i wysokość oraz odpowiednio rozmiary Grid . Następnie definiuje podstawowy układ, tworząc zestaw ColumnDefinition obiektów i RowDefinition i dodając je odpowiednio do Grid bazy ColumnDefinitions obiektów i RowDefinitions kolekcji. Definiuje siatkę pięciu wierszy i siedem kolumn z wymiarami określonymi przez zawartość komórek.

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

Następnie konstruktor dodaje elementy interfejsu użytkownika do elementu Grid. Pierwszy element to tekst tytułu, który jest kontrolką Label wyśrodkowaną w pierwszym wierszu siatki.

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

Następny wiersz zawiera kontrolkę Nazwa Label i skojarzona z nią TextBox kontrolka. Ponieważ ten sam kod jest używany dla każdej pary etykiet/pola tekstowego, jest umieszczany w parze metod prywatnych i używany dla wszystkich pięciu par etykiet/pola tekstowego. Metody tworzą odpowiednią kontrolkę i nazywają klasę Grid statyczną SetColumn i SetRow metodami, aby umieścić kontrolki w odpowiedniej komórce. Po utworzeniu kontrolki przykład wywołuje Add metodę we Children właściwości Grid obiektu , aby dodać kontrolkę do siatki. Kod dodawania pozostałych par etykiet/pola tekstowego jest podobny. Aby uzyskać szczegółowe informacje, zobacz przykładowy kod.

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

Implementacja tych dwóch metod jest następująca:

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

Na koniec przykład dodaje przyciski OK i Anuluj oraz dołącza procedurę obsługi zdarzeń do ich Click zdarzeń.

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

Zwracanie danych do okna hosta

Po kliknięciu dowolnego przycisku zostanie zgłoszone jego Click zdarzenie. Okno hosta może po prostu dołączyć programy obsługi do tych zdarzeń i pobrać dane bezpośrednio z TextBox kontrolek. W przykładzie użyto nieco mniej bezpośredniego podejścia. Obsługuje Click on zawartość WPF, a następnie zgłasza zdarzenie OnButtonClickedniestandardowe , aby powiadomić zawartość WPF. Dzięki temu zawartość WPF może przeprowadzić weryfikację parametru przed powiadomieniem hosta. Program obsługi pobiera tekst z TextBox kontrolek i przypisuje go do właściwości publicznych, z których host może pobrać informacje.

Deklaracja zdarzenia w pliku WPFPage.h:

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

Procedura Click obsługi zdarzeń w pliku 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));
}

Ustawianie właściwości WPF

Host Win32 umożliwia użytkownikowi zmianę kilku właściwości zawartości WPF. Z boku Win32 jest to po prostu kwestia zmiany właściwości. Implementacja w klasie zawartości WPF jest nieco bardziej skomplikowana, ponieważ nie ma jednej właściwości globalnej, która kontroluje czcionki dla wszystkich kontrolek. Zamiast tego właściwość właściwa dla każdej kontrolki jest zmieniana w zestawach dostępu właściwości. W poniższym przykładzie pokazano kod właściwości DefaultFontFamily . Ustawienie właściwości wywołuje metodę prywatną, która z kolei ustawia FontFamily właściwości dla różnych kontrolek.

Z pliku WPFPage.h:

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

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

Zobacz też