WPF i Win32 — Współdziałanie

Ten temat zawiera omówienie współpracy WPF i kodu Win32. Windows Presentation Foundation (WPF) oferuje bogate środowisko do tworzenia aplikacji. Jeśli jednak masz znaczną inwestycję w kod Win32, może być bardziej efektywne ponowne użycie niektórych z tych kodów.

Podstawowe informacje dotyczące WPF i Win32

Istnieją dwie podstawowe metody międzyoperacyjności między WPF i kodem Win32.

  • WPFZawartość hosta w oknie Win32. Korzystając z tej techniki, można użyć zaawansowanych możliwości grafiki w ramach WPF standardowego okna i aplikacji Win32.

  • Hostowanie okna Win32 w WPF zawartości. Korzystając z tej techniki, można użyć istniejącej niestandardowej kontrolki Win32 w kontekście innej WPF zawartości i przekazać dane między granicami.

Każda z tych technik jest koncepcyjnie wprowadzana w tym temacie. Aby zapoznać się z bardziej zorientowanym na kod ilustracją hostingu WPF w systemie Win32, zobacz Przewodnik: hosting zawartości WPF w Win32. Aby zapoznać się z bardziej zorientowanym na kod ilustracją hostingu Win32 w programie WPF , zobacz Przewodnik: hosting kontrolki Win32 w WPF.

Projekty międzyoperacyjności WPF

WPF Interfejsy API są kodem zarządzanym, ale większość istniejących programów Win32 jest zapisywana w niezarządzanym języku C++. Nie można wywoływać WPF interfejsów API z poziomu prawdziwy program niezarządzany. Jednak korzystając /clr z opcji z kompilatorem Microsoft Visual C++, można utworzyć niezarządzany program zarządzany, który pozwala bezproblemowo mieszać zarządzane i niezarządzane wywołania interfejsów API.

Jedną skomplikowanie na poziomie projektu jest to, że nie można kompilować Extensible Application Markup Language (XAML) plików w projekcie języka C++. Istnieje kilka technik dzielenia projektu, aby zrekompensować te.

  • Utwórz bibliotekę DLL języka C#, która zawiera wszystkie XAML strony jako skompilowany zestaw, a następnie, aby plik wykonywalny języka C++ zawierał tę bibliotekę DLL jako odwołanie.

  • Utwórz plik wykonywalny języka C# dla WPF zawartości i odwołuje się do biblioteki DLL języka C++, która zawiera zawartość Win32.

  • Użyj Load , aby załadować dowolne XAML w czasie wykonywania, zamiast kompilować XAML .

  • Nie używaj XAML wcale i napisz cały WPF kod w kodzie, tworząc drzewo elementów z Application .

Użyj dowolnych rozwiązań, które najlepiej sprawdzają się.

Uwaga

Jeśli jeszcze nie korzystasz z języka C++/CLI, możesz zauważyć kilka słów kluczowych "New", takich jak gcnew i nullptr w przykładach kodu międzyoperacyjnego. Te słowa kluczowe zastępują starszej składni podwójnego podkreślenia ( __gc ) i zapewniają bardziej naturalną składnię kodu zarządzanego w języku C++. Aby dowiedzieć się więcej na temat funkcji zarządzanych przez C++/CLI, zobacz rozszerzenia składników dla platform środowiska uruchomieniowego.

Jak WPF używa HWND

Aby najlepiej wykorzystać wartość WPF "HWND Interop", musisz zrozumieć, jak WPF używać HWND. Dla dowolnego elementu HWND nie można mieszać WPF renderowania przy użyciu renderowania DirectX lub renderowania GDI/GDI+. Ma to wiele konsekwencji. Przede wszystkim, aby mieszać te modele renderingu, należy utworzyć rozwiązanie międzyoperacyjne i użyć wydzielonych segmentów międzyoperacyjnych dla każdego modelu renderowania, który będzie używany. Ponadto zachowanie renderowania tworzy ograniczenie "miejsce do obsługi" dla tego, co może być realizowane w rozwiązaniu międzyoperacyjnym. Pojęcie "miejsce w sieci" jest wyjaśnione szczegółowo w temacie Omówienie regionów technologicznych.

Wszystkie WPF elementy na ekranie są ostatecznie obsługiwane przez właściwość HWND. Gdy tworzysz WPF Window , program WPF tworzy właściwość HWND najwyższego poziomu i używa HwndSource do umieszczania Window i jego WPF zawartości wewnątrz elementu HWND. Pozostała część WPF zawartości w aplikacji ma udział w pojedynczej wartości HWND. Wyjątkiem są menu, listy rozwijane pól kombi i inne wyskakujące okienka. Te elementy tworzą własne okno najwyższego poziomu, dlatego WPF menu może potencjalnie przejść do krawędzi HWND okna, która go zawiera. Gdy używasz HwndHost , aby umieścić Właściwość HWND wewnątrz WPF , WPF informuje Win32, jak ustawić nowy element HWND podrzędny względem elementu WPF Window HWND.

Koncepcja powiązana z elementem HWND jest przezroczysta w obrębie i między poszczególnymi elementami HWND. Jest to również omówione w temacie Omówienie regionów technologii.

Hosting zawartości WPF w oknie Microsoft Win32

Kluczem do hostowania WPF w oknie Win32 jest HwndSource Klasa. Ta klasa otacza WPF zawartość w oknie Win32, dzięki czemu WPF zawartość może być włączona do interfejs użytkownika (UI) okna jako podrzędnego. Poniższe podejście łączy Win32 i WPF w pojedynczej aplikacji.

  1. Zaimplementuj WPF zawartość (element główny zawartości) jako klasę zarządzaną. Zazwyczaj Klasa dziedziczy z jednej z klas, które mogą zawierać wiele elementów podrzędnych i/lub użyć jako elementu głównego, takiego jak DockPanel lub Page . W kolejnych krokach Klasa ta jest nazywana WPF klasą zawartości, a wystąpienia klasy są określane jako WPF obiekty zawartości.

  2. Implementowanie aplikacji systemu Windows za pomocą języka C++/CLI. W przypadku rozpoczynania pracy z istniejącą niezarządzaną aplikacją C++ można ją zazwyczaj włączyć do wywołania kodu zarządzanego, zmieniając ustawienia projektu w celu uwzględnienia /clr flagi kompilatora (pełen zakres, co może być niezbędne do obsługi /clr kompilacji, nie został opisany w tym temacie).

  3. Ustaw model wątkowości na Apartament wielowątkowy (STA). WPF używa tego modelu wątków.

  4. Obsłuż powiadomienie WM_CREATE w procedurze okna.

  5. W ramach procedury obsługi (lub funkcji, która wywołuje program obsługi), wykonaj następujące czynności:

    1. Utwórz nowy HwndSource obiekt z HWND okna nadrzędnego jako jego parent parametru.

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

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

    4. HwndSourceWłaściwość Object Handle zawiera uchwyt okna (HWND). Aby uzyskać Właściwość HWND, która może być używana w niezarządzanej części aplikacji, Rzutowanie Handle.ToPointer() na Właściwość HWND.

  6. Zaimplementuj zarządzaną klasę, która zawiera pole statyczne, które przechowuje odwołanie do WPF obiektu zawartości. Ta klasa pozwala uzyskać odwołanie do WPF obiektu zawartości z kodu Win32, ale co ważniejsze, zapobiega przypadkowemu wykorzystaniu HwndSource elementów bezużytecznych.

  7. Odbieraj powiadomienia z WPF obiektu Content, dołączając procedurę obsługi do co najmniej jednego WPF zdarzenia obiektu zawartości.

  8. Komunikuj się z WPF obiektem Content przy użyciu odwołania przechowywanego w polu statycznym, aby ustawić właściwości, wywołać metody itd.

Uwaga

Można wykonać niektóre lub wszystkie WPF definicje klas zawartości dla kroku jeden w XAML , używając domyślnej klasy częściowej klasy zawartości, jeśli tworzysz oddzielny zestaw, a następnie odwołując się do niego. Mimo że zwykle zawierany jest Application obiekt w ramach kompilowania XAML do zestawu, nie można zakończyć korzystania z tego elementu w Application ramach operacji międzyoperacyjnego. wystarczy użyć co najmniej jednej klasy głównej dla plików, do których odwołuje XAML się aplikacja, i odwołania do ich klas częściowych. Pozostała część procedury jest zasadniczo podobna do przedstawionej powyżej.

Każdy z tych kroków ilustruje kod w przewodniku tematu: hosting zawartości WPF w Win32.

Hosting okna środowiska Microsoft Win32 w WPF

Kluczem do hostowania okna Win32 w innej WPF zawartości jest HwndHost Klasa. Ta klasa otacza okno w WPF elemencie, który można dodać do WPF drzewa elementów. HwndHost Program obsługuje również interfejsy API, które umożliwiają wykonywanie takich zadań jako komunikatów przetwarzanych dla hostowanego okna. Podstawowa procedura:

  1. Utwórz drzewo elementów dla WPF aplikacji (może być za pomocą kodu lub znaczników). Znajdź odpowiedni i dopuszczalny punkt w drzewie elementów, w którym HwndHost można dodać implementację jako element podrzędny. W pozostałej części tych kroków ten element jest określany jako rezerwowy element.

  2. HwndHostUtwórz obiekt, który zawiera zawartość systemu Win32.

  3. W tej klasie hosta Zastąp HwndHost metodę BuildWindowCore . Zwraca wartość HWND okna hostowanego. Możesz chcieć otoczyć rzeczywiste formanty jako oknem podrzędnym zwróconego okna; Zawijanie formantów w oknie hosta zapewnia prostą metodę WPF otrzymywania powiadomień z kontrolek. Ta technika pomaga poprawić niektóre problemy z Win32 dotyczące obsługi komunikatów na granicy obsługiwanej kontroli.

  4. Zastąp HwndHost metody DestroyWindowCore i WndProc . Zamiarem tego procesu jest przetworzenie oczyszczania i usunięcie odwołań do hostowanej zawartości, szczególnie w przypadku utworzenia odwołań do obiektów niezarządzanych.

  5. W pliku związanym z kodem Utwórz wystąpienie klasy hostingu kontrolki i Uczyń ją elementem podrzędnym elementu. Zazwyczaj można użyć programu obsługi zdarzeń, takiego jak Loaded lub użyć konstruktora klasy częściowej. Możesz również dodać zawartość międzyoperacyjną za pomocą zachowania środowiska uruchomieniowego.

  6. Przetwarzaj wybrane komunikaty okna, takie jak powiadomienia sterujące. Istnieją dwie metody. Oba zapewniają taki sam dostęp do strumienia komunikatów, dzięki czemu wybór jest w dużej mierze wygodnym programowaniem.

    • Zaimplementuj przetwarzanie komunikatów dla wszystkich komunikatów (nie tylko komunikaty zamknięcia) w przesłonięciu HwndHost metody WndProc .

    • WPFElement hostujący przetwarza komunikaty przez obsługę MessageHook zdarzenia. To zdarzenie jest zgłaszane dla każdego komunikatu, który jest wysyłany do procedury okna głównego okna hostowanego.

    • Nie można przetwarzać komunikatów z systemu Windows, które nie są przetwarzane przy użyciu programu WndProc .

  7. Komunikuj się z hostowanym oknem przy użyciu wywołania platformy, aby wywołać niezarządzaną SendMessage funkcję.

Wykonanie tych kroków powoduje utworzenie aplikacji, która współpracuje z myszą wejściową. Można dodać obsługę tabulacji dla hostowanego okna przez implementację IKeyboardInputSink interfejsu.

Każdy z tych kroków ilustruje kod w przewodniku tematu: hosting kontrolki Win32 w WPF.

Funkcja HWND wewnątrz WPF

Można traktować HwndHost jako specjalną kontrolę. (Technicznie, HwndHost jest FrameworkElement klasą pochodną, a nie Control klasą pochodną, ale można ją traktować jako kontrolkę do celów międzyoperacyjności.) HwndHost stanowi abstrakcyjny podstawowy charakter Win32 zawartości, w taki sposób, że pozostała część WPF uważa, że hostowana zawartość jest innym obiektem podobnym do kontrolki, który powinien renderować i przetwarzać dane wejściowe. HwndHost zwykle zachowuje się jak inne WPF FrameworkElement , chociaż istnieją pewne istotne różnice dotyczące danych wyjściowych (rysowania i grafiki) oraz danych wejściowych (myszy i klawiatury) na podstawie ograniczeń, jakie mogą być obsługiwane przez bazowe HWND.

Istotne różnice w zachowaniu danych wyjściowych

  • FrameworkElement, która jest HwndHost klasą bazową, ma dość kilka właściwości, które oznaczają zmiany w interfejsie użytkownika. Należą do nich właściwości, takie jak FrameworkElement.FlowDirection , które zmieniają układ elementów w tym elemencie jako element nadrzędny. Jednak większość z tych właściwości nie jest zamapowana na możliwe odpowiedniki Win32, nawet jeśli takie odpowiedniki mogą istnieć. Zbyt wiele z tych właściwości, a ich znaczenie jest zbyt nieprzydatne, aby mapowania były praktyczne. W związku z tym Ustawianie właściwości, takich jak FlowDirection on, HwndHost nie ma żadnego wpływu.

  • HwndHost Przekształcanie nie może być obrócone, skalowane, skośne lub w inny sposób.

  • HwndHost nie obsługuje Opacity właściwości (Blend alfa). Jeśli zawartość wewnątrz HwndHost wykonuje System.Drawing operacje, które zawierają informacje alfa, które nie są naruszeniem, ale wartość HwndHost jako całość obsługuje tylko nieprzezroczystość = 1,0 (100%).

  • HwndHost pojawi się nad innymi WPF elementami w tym samym oknie najwyższego poziomu. Jednak ToolTip ContextMenu wygenerowane menu jest osobnym oknem najwyższego poziomu i dlatego będzie działać poprawnie z HwndHost .

  • HwndHost nie respektują regionu wycinka elementu nadrzędnego UIElement . Jest to potencjalnie problem w przypadku próby umieszczenia HwndHost klasy wewnątrz regionu przewijania lub Canvas .

Znaczące różnice w zachowaniu danych wejściowych

  • Ogólnie rzecz biorąc, gdy urządzenia wejściowe są objęte zakresem w HwndHost hostowanym regionie Win32, zdarzenia wejściowe można przechodzić bezpośrednio do Win32.

  • Gdy wskaźnik myszy znajduje się nad HwndHost , aplikacja nie odbiera WPF zdarzeń myszy, a wartość WPF właściwości IsMouseOver będzie false .

  • Gdy HwndHost ma fokus klawiatury, aplikacja nie będzie odbierać WPF zdarzeń klawiatury, a wartość WPF właściwości IsKeyboardFocusWithin będzie false .

  • Gdy fokus znajduje się w obrębie HwndHost i zmieni się na inną kontrolkę wewnątrz HwndHost , aplikacja nie będzie odbierać WPF zdarzeń GotFocus ani LostFocus .

  • Powiązane właściwości i zdarzenia pióra są analogiczne i nie raportują informacji, gdy pióro jest w stanie HwndHost .

Tabulacja, skróty i akceleratory

IKeyboardInputSinkInterfejsy i IKeyboardInputSite umożliwiają tworzenie płynnych funkcji klawiatury dla aplikacji mieszanych WPF i Win32:

  • Tabulacja między Win32 i WPF składnikami

  • Skróty i akceleratory, które działają zarówno wtedy, gdy fokus znajduje się w składniku Win32 i gdy znajduje się w składniku WPF.

HwndHostKlasy i HwndSource umożliwiają implementację programu IKeyboardInputSink , ale mogą nie obsługiwać wszystkich komunikatów wejściowych, które są potrzebne w przypadku bardziej zaawansowanych scenariuszy. Zastąp odpowiednie metody, aby uzyskać żądane zachowanie klawiatury.

Interfejsy zapewniają obsługę tylko tego, co dzieje się na przejściu między WPF regionami i Win32. W regionie Win32 zachowanie tabulacji jest całkowicie kontrolowane przez logikę zaimplementowaną w systemie Win32 na potrzeby tabulacji (jeśli istnieje).

Zobacz też