WPF i Win32 — Współdziałanie
Ten temat zawiera omówienie sposobu współdziałania kodu WPF i Win32. Windows Presentation Foundation (WPF) zapewnia rozbudowane środowisko do tworzenia aplikacji. Jeśli jednak masz znaczną inwestycję w kod Win32, bardziej efektywne może być ponowne użycie niektórych z tych kodów.
WPF i Win32 — podstawy współdziałania
Istnieją dwie podstawowe techniki współpracy między kodem WPF i Win32.
Hostuj zawartość WPF w oknie Win32. Ta technika umożliwia korzystanie z zaawansowanych możliwości graficznych platformy WPF w ramach standardowego okna Win32 i aplikacji.
Hostuj okno Win32 w zawartości WPF. Za pomocą tej techniki można użyć istniejącej niestandardowej kontrolki Win32 w kontekście innej zawartości WPF i przekazać dane przez granice.
Każda z tych technik została koncepcyjnie wprowadzona w tym temacie. Aby uzyskać bardziej zorientowaną na kod ilustrację hostowania platformy WPF w Win32, zobacz Przewodnik: hosting zawartości WPF w Win32. Aby uzyskać bardziej zorientowaną na kod ilustrację hostowania systemu Win32 w WPF, zobacz Przewodnik: hosting kontrolki Win32 w WPF.
Projekty międzyoperacyjne WPF
Interfejsy API WPF są kodem zarządzanym, ale większość istniejących programów Win32 jest napisanych w nieza zarządzanym języku C++. Nie można wywołać interfejsów API WPF z prawdziwego programu niezafakcjowego. Jednak przy użyciu /clr opcji z kompilatorem Microsoft Visual C++ można utworzyć mieszany program zarządzany-nieza zarządzany, w którym można bezproblemowo mieszać zarządzane i nieza zarządzanie wywołania interfejsu API.
Jedną z komplikacji na poziomie projektu jest to, że nie można Extensible Application Markup Language plików XAML do projektu w języku C++. Istnieje kilka technik dzielenia projektów, które kompensują to.
Utwórz bibliotekę DLL języka C#, która zawiera wszystkie strony XAML jako skompilowany zestaw, a następnie dołącz plik wykonywalny języka C++ jako odwołanie do tej biblioteki DLL.
Utwórz plik wykonywalny języka C# dla zawartości WPF i odwołuj się do biblioteki DLL języka C++ zawierającej zawartość Win32.
Użyj Load elementu , aby załadować dowolny kod XAML w czasie działania, zamiast kompilować kod XAML.
Nie używaj platformy WPF w kodzie, budowania drzewa elementów z .Application
Użyj dowolnego podejścia, które będzie dla Ciebie najlepsze.
Uwaga
Jeśli wcześniej nie używaliśmy języka C++/INTERFEJSU WIERSZA POLECENIA, niektóre "nowe" gcnewnullptr słowa kluczowe, takie jak i, można zauważyć w przykładach kodu międzyoperacyjnego. Te słowa kluczowe stanowią alternatywę dla starszej składni z podwójnym podkreśleniem (__gc) i zapewniają bardziej naturalną składnię kodu zarządzanego w języku C++. Aby dowiedzieć się więcej na temat funkcji zarządzanych w języku C++/interfejsie wiersza polecenia, zobacz Component Extensions for Runtime Platforms (Rozszerzenia składników dla platform środowiska uruchomieniowego).
Jak WPF używa Hwnds
Aby w pełni wykorzystują "międzyplatopę HWND" WPF, musisz zrozumieć, jak WPF używa identyfikatorów HWND. W przypadku dowolnej wizualizacji HWND nie można mieszać renderowania WPF z renderowaniem DirectX ani GDI/GDI+ renderowaniem. Ma to wiele implikacji. Przede wszystkim, aby w ogóle mieszać te modele renderowania, należy utworzyć rozwiązanie międzyoperacyjne i użyć wyznaczonych segmentów współdziałania dla każdego modelu renderowania, który ma być używany. Ponadto zachowanie renderowania powoduje ograniczenie "przestrzeni powietrza" dotyczące możliwości rozwiązania międzyoperacyjnego. Koncepcja "przestrzeni powietrza" została szczegółowo wyjaśniona w temacie Omówienie regionów technologicznych.
Wszystkie elementy WPF na ekranie są ostatecznie oparte na zawartości HWND. Podczas tworzenia WPF Window, WPF tworzy HWND najwyższego poziomu i HwndSourceWindow używa do umieścić i jego zawartość WPF wewnątrz HWND. Pozostała zawartość WPF w udziałach aplikacji, które są pojedynczej 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 menu WPF może potencjalnie przejść przez krawędź okna HWND, która je zawiera. Gdy używasz funkcji , HwndHost aby umieścić HWND wewnątrz WPF, WPF informuje Win32, jak umieścić nowy element podrzędny HWND względem HWND WPF Window .
Koncepcją powiązaną z HWND jest przezroczystość w obrębie i między poszczególnymi HWND. Omówiono to również w temacie Omówienie regionów technologicznych.
Hostowanie zawartości WPF w oknie Microsoft Win32
Kluczem do hostowania WPF w oknie Win32 jest HwndSource klasa . Ta klasa opakuje zawartość WPF w oknie Win32, dzięki czemu zawartość WPF może zostać włączona do WPF w jednej aplikacji.
Zaim implementuj zawartość WPF (element główny zawartości) jako klasę zarządzaną. Zazwyczaj klasa dziedziczy z jednej z klas, która może zawierać wiele elementów podrzędnych i/lub używana jako element główny, taki jak DockPanel lub Page. W kolejnych krokach ta klasa jest określana jako klasa zawartości WPF, a wystąpienia klasy są określane jako obiekty zawartości WPF.
Implementowanie aplikacji Windows za pomocą języka C++/interfejsu wiersza polecenia. Jeśli rozpoczynasz pracę z istniejącą nieza zarządzaną aplikacją C++, zazwyczaj możesz ją włączyć do wywołania kodu zarządzanego, zmieniając ustawienia projektu tak, aby zawierały flagę kompilatora (
/clrpełny zakres tego,/clrco może być konieczne do obsługi kompilacji, nie jest opisany w tym temacie).Ustaw model wątkowych na single Threaded (STA). WPF używa tego modelu wątkowego.
Obsługuj WM_CREATE powiadomień w procedurze okna.
W programie obsługi (lub funkcji, która wywołuje program obsługi), wykonaj następujące czynności:
Utwórz nowy obiekt HwndSource z oknem nadrzędnym HWND jako parametrem
parent.Utwórz wystąpienie klasy zawartości WPF.
Przypisz odwołanie do obiektu zawartości WPF do właściwości HwndSourceRootVisual obiektu .
Właściwość HwndSource obiektu Handle zawiera dojście okna (HWND). Aby uzyskać element HWND, który może być pomocny w niezaiemzanych elementach aplikacji,
Handle.ToPointer()rzutuj na element HWND.
Implementowanie klasy zarządzanej zawierającej pole statyczne, które zawiera odwołanie do obiektu zawartości WPF. Ta klasa umożliwia uzyskiwanie odwołania do obiektu zawartości WPF z kodu Win32, HwndSource ale co ważniejsze, zapobiega przypadkowemu odśmiecaniu pamięci.
Odbieraj powiadomienia z obiektu zawartości WPF, dołączając program obsługi do co najmniej jednego zdarzenia obiektu zawartości WPF.
Komunikacja z obiektem zawartości WPF przy użyciu odwołania przechowywanego w polu statycznym w celu ustawienia właściwości, metod wywołania itp.
Uwaga
Możesz wykonać część lub całą definicję klasy zawartości WPF dla kroku 1 w języku XAML przy użyciu domyślnej częściowej klasy klasy zawartości, jeśli wytniesz oddzielny zestaw, a następnie odwołasz się do niego. Application Mimo że zwykle obiekt jest dołączany w ramach kompilowania kodu XAML do zestawu, Application nie jest używany jako część współdziałania, wystarczy użyć co najmniej jednej klasy głównej dla plików XAML, do których odwołuje się aplikacja, i odwoływać się do ich klas częściowych. Pozostała część procedury jest zasadniczo podobna do przedstawionej powyżej.
Każdy z tych kroków został zilustrowany za pomocą kodu w temacie Przewodnik: hostowanie zawartości WPF w Win32.
Hostowanie okna Microsoft Win32 w WPF
Kluczem do hostowania okna Win32 w innej zawartości WPF jest HwndHost klasa . Ta klasa opakuje okno w element WPF, który można dodać do drzewa elementów WPF. HwndHost Obsługuje również interfejsy API, które umożliwiają wykonywanie takich zadań, jak przetwarzanie komunikatów dla hostowanych okien. Podstawowa procedura jest:
Utwórz drzewo elementów dla aplikacji WPF (może to być za pośrednictwem kodu lub znaczników). Znajdź odpowiedni i dozwolony punkt w drzewie elementów, w którym HwndHost implementację można dodać jako element podrzędny. W pozostałej części tych kroków ten element jest określany jako element rezerwowania.
Utwórz obiekt HwndHost , który przechowuje zawartość Win32.
W tej klasie hostów zastąp metodę HwndHostBuildWindowCore. Zwróć HWND hostowanych okna. Rzeczywiste kontrolki można opakować jako okno podrzędne zwróconego okna. Zawijanie kontrolek w oknie hosta zapewnia prosty sposób na odbieranie powiadomień z kontrolek przez zawartość WPF. Ta technika pomaga rozwiązać niektóre problemy Win32 dotyczące obsługi komunikatów na granicy hostowanej kontrolki.
Zastąp metody HwndHost i DestroyWindowCoreWndProc. Celem tego procesu jest przetwarzanie oczyszczania i usuwanie odwołań do hostowanej zawartości, szczególnie w przypadku tworzenia odwołań do obiektów nieza pomocą zarządzania.
W pliku code-behind utwórz wystąpienie klasy hostingu kontrolki i nadaj jej element podrzędny elementu rezerwowania. Zazwyczaj należy użyć procedury obsługi zdarzeń, takiej jak Loaded, lub konstruktora klasy częściowej. Można jednak również dodać zawartość współdziałania za pomocą zachowania środowiska uruchomieniowego.
Przetwarzaj wybrane komunikaty okna, takie jak powiadomienia sterowania. Istnieją dwa podejścia. Oba zapewniają identyczny dostęp do strumienia komunikatów, więc wybór jest w dużej mierze kwestią wygody programistycznej.
Implementowanie przetwarzania komunikatów dla wszystkich komunikatów (nie tylko komunikatów zamykania) w zastąpień metody HwndHostWndProc.
Hostowanie elementu WPF przetwarza komunikaty przez obsługę MessageHook zdarzenia. To zdarzenie jest wywoływane dla każdego komunikatu, który jest wysyłany do procedury okna głównego w oknie hostowanych.
Nie można przetwarzać komunikatów z okien, które są poza procesem, przy użyciu programu WndProc.
Komunikuj się z hostowaną oknem przy użyciu wywołania platformy w celu wywołania funkcji niezamażowanej
SendMessage.
Poniższe kroki tworzą aplikację, która działa z wprowadzaniem myszy. Obsługę tabulatorów dla hostowanych okien można dodać, implementując IKeyboardInputSink interfejs .
Każdy z tych kroków został zilustrowany za pomocą kodu w temacie Przewodnik: hostowanie kontrolki Win32 w WPF.
Identyfikatory wewnętrzne WPF
Można myśleć o tym HwndHost jak o specjalnej kontrolce. (Technicznie rzecz HwndHost ujmuje FrameworkElement się, że jest klasą pochodną, a Control nie klasą pochodną, ale można ją uznać za kontrolkę na potrzeby współdziałania). HwndHost Abstraduje podstawową naturę win32 hostowanej zawartości, tak aby reszta WPF uważała hostowaną zawartość za inny obiekt podobny do formantu, który powinien renderować i przetwarzać dane wejściowe. HwndHost ogólnie zachowuje się jak inne WPF FrameworkElement, chociaż istnieją pewne istotne różnice dotyczące danych wyjściowych (rysunek i grafiki) i danych wejściowych (mysz i klawiatura) w oparciu o ograniczenia dotyczące tego, co mogą obsługiwać podstawowe identyfikatory HWND.
Istotne różnice w zachowaniu danych wyjściowych
FrameworkElement, która jest klasą HwndHost bazową, ma dość kilka właściwości, które implikują zmiany w interfejsie użytkownika. Obejmują one właściwości, takie jak FrameworkElement.FlowDirection, które zmienia układ elementów w tym elemencie jako element nadrzędny. Jednak większość tych właściwości nie jest mapowana na możliwe odpowiedniki Win32, nawet jeśli takie odpowiedniki mogą istnieć. Zbyt wiele z tych właściwości i ich znaczenia jest zbyt specyficzne dla technologii renderowania, aby mapowania były praktyczne. W związku z tym ustawienie właściwości, takich FlowDirection jak on HwndHost , nie ma wpływu.
HwndHost Przekształcenia nie mogą być obracane, skalowane, skośne ani w inny sposób objęte przekształceniem.
HwndHost Nie obsługuje właściwości Opacity (mieszania alfa). Jeśli zawartość wewnątrz HwndHostSystem.Drawing operacji wykonuje operacje, które obejmują informacje alfa, samo w sobie nie jest naruszeniem, HwndHost ale jako całość obsługuje tylko przezroczystość = 1,0 (100%).
HwndHost Zostanie wyświetlony na innych elementach WPF w tym samym oknie najwyższego poziomu. Jednak menu lub ToolTipContextMenu wygenerowane jest osobnym oknem najwyższego poziomu, dlatego będzie działać poprawnie w przypadku polecenia HwndHost.
HwndHost nie przestrzega obszaru przycinania elementu nadrzędnego UIElement. Może to być problem, jeśli spróbujemy umieścić HwndHost klasę wewnątrz przewijanych regionów lub Canvas.
Istotne różnice w zachowaniu danych wejściowych
Ogólnie rzecz biorąc, chociaż zakres urządzeń wejściowych jest ograniczony HwndHost do hostowanych regionów Win32, zdarzenia wejściowe są bezpośrednio trafiać do win32.
Gdy wskaźnik myszy znajduje się nad HwndHostobiektem , aplikacja nie odbiera zdarzeń myszy WPF, a wartość właściwości WPF IsMouseOver będzie mieć wartość
false.Gdy obiekt ma HwndHost fokus klawiatury, aplikacja nie będzie odbierać zdarzeń klawiatury WPF, a wartość właściwości WPF IsKeyboardFocusWithin będzie mieć wartość
false.Gdy fokus znajduje się w obrębie HwndHostHwndHostobiektu i zmienia się na inną kontrolkę wewnątrz obiektu , aplikacja nie będzie odbierać zdarzeń WPF GotFocus ani LostFocus.
Powiązane właściwości i zdarzenia pisaka są analogiczne i nie raportują informacji, gdy pisak jest już na .HwndHost
Tabbing, Mnemonics i Akceleratory
Interfejsy IKeyboardInputSink i IKeyboardInputSite umożliwiają tworzenie bezproblemowego interfejsu klawiatury dla mieszanych aplikacji WPF i Win32:
Tabulatory między składnikami Win32 i WPF
Mnemonika i akceleratory, które działają zarówno wtedy, gdy fokus znajduje się w składniku Win32, jak i w składniku WPF.
Klasy HwndHost i HwndSource zapewniają implementacje IKeyboardInputSinkklasy , ale mogą nie obsługiwać wszystkich komunikatów wejściowych, które mają być obsługiwane w bardziej zaawansowanych scenariuszach. Zastąp odpowiednie metody, aby uzyskać odpowiednie zachowanie klawiatury.
Interfejsy zapewniają tylko obsługę tego, co się dzieje w przypadku przejścia między regionami WPF i Win32. W regionie Win32 zachowanie tabulatora jest całkowicie kontrolowane przez zaimplementowaną logikę win32 do tabulatorów, jeśli istnieje.