Ich habe ein Win32 (OpenGL) -Steuerelement, das ich in unsere WPF-Anwendung einbetten muss. Es muss auf Maus- und Tastaturereignisse reagieren und diese weitergeben.
Ich habe eine von HwndHost abgeleitete Instanz zum Hosten des systemeigenen Fensters erstellt und die WndProc-Funktion in dieser Klasse überschrieben. Um Win32-Nachrichten an WPF zu propagieren, handhabe ich bestimmte Mausnachrichten und ordnet sie WPF-Ereignissen zu. Verwenden Sie dann die statische InputManager-Klasse, um sie zu erhöhen.
Das Problem ist, wenn ich sie handhabe, sind die Mauskoordinaten durcheinander.
Hier ist ein Beispiel des Codes, den ich verwende, um die Ereignisse zu erhöhen:
%Vor% Wenn meine WPF-Ereignishandler ausgelöst werden und ich versuche, die Mauskoordinaten abzurufen (zB e.GetPosition((IInputElement) sender)
), erhalte ich die falschen Werte (und sie sind immer die gleichen Werte, unabhängig davon, wo das ursprüngliche Ereignis in meinem Steuerelement aufgetreten ist) / p>
Die Werte scheinen mit der Bildschirmposition des WPF-Fensters zu korrelieren, in dem sich die Anwendung befindet, da sie sich ändern, wenn sich die Fensterposition ändert, aber sie entsprechen auch nicht der tatsächlichen Position des Anwendungsfensters.
Ich denke, das kann etwas mit dem internen Status des WPF InputManagers zu tun haben, und der Tatsache, dass das private Feld MouseDevice._inputSource
null
ist, wenn meine Ereignisse ausgelöst werden, aber meine Experimente mit .net Reflexion haben dort keine Ergebnisse erbracht.
Ich weiß nicht wirklich, was ich noch versuchen soll. Keyboard-Unterstützung funktionierte aus der Box, es ist nur die Maus-Standort-Unterstützung, die ich nicht richtig funktionieren kann.
Nachdem ich einen weiteren Tag in Reflector verbracht habe, um den fraglichen .net Quellcode zu analysieren, habe ich die Lösung gefunden. Man muss zuerst den WPF-InputManager initialisieren, indem man ein PreviewInputReportEventArgs
router-Ereignis auslöst.
Leider sind dieses Ereignis und die Ereignisargumentstrukturen, die für die Erhöhung erforderlich sind, alle mit internal
gekennzeichnet, sodass die Reflexion die einzige Möglichkeit ist, dieses Ereignis auszulösen. Für jeden mit dem gleichen Problem ist hier der C # -Code erforderlich:
wo:
timestamp
ist die Anzahl der Systemticks beim Auftreten des Mausereignisses (normalerweise Environment.TickCount
) pointX
und pointY
sind die Mauskoordinaten relativ zum Clientbereich der obersten Ebene des Anwendungsfensters wheel
ist das Mausrad-Delta li>
Beachten Sie, dass das Ereignis "Vorschau" nur ausgelöst werden muss. Nach dem Auslösen dieses Ereignisses können die Standardmausereignisse ausgelöst werden, und WPF gibt die korrekten Mauspositionskoordinaten zurück, wenn e.GetPosition()
aufgerufen wird.
Die Art, wie ich es mache, ist mit einem anderen Ansatz. Ich übertrage transparentes WPF-Fenster auf meinem HwndHost mit AllowsTransparency
-Eigenschaft. Ich verknüpfe interessante Ereignisse im Overlay-Fenster und leite sie mit RaiseEvent
wie folgt zu meinem Steuerelement:
Sie müssen nur HwndHost und Overlay-Fensterpositionen synchronisieren, was nicht so schwer ist.