The problem of WPF rendering with HWND children on the way

I believe it is safe to say that WPF displays its contents as the background of the window. In the traditional sense of HWND there are no child windows. So, when you enter something HWND, based on a WPF application, such as WebBrowser, everything starts to go wrong, as in terms of appearance.

Consider a grid window with two children, WebBrowser and something else, for example. Text box If the WebBrowser were a red circle, the TextBox would display on top of it. In the case of WebBrowser, no text field will be found anywhere. This is because the TextBox is displayed as the background of the main window, and WebBrowser is actually an HWND descendant of the main window that hides the background.

So, all is well (no). How to achieve the desired behavior? I want the TextBox to appear on top of the WebBrowser. Has anyone encountered this issue?

I’m thinking that I have a second transparent WPF window without borders without borders, redefining it so that the main window possesses it and performs some other tricks to make this happen.

Before I burst in, I was wondering if anyone has an obvious or simpler solution?


Update with Meleak

I offer this Bounty to anyone who can post a Ray Burns Answer AirRepair . I tried myself, but in vain

+4
source share
4 answers

Proposed solution

I suggest a simple "AirRepair" class with this signature:

 public class AirRepair : Decorator { public HwndHost Win32Host ... // DP bound to HwndHost public Geometry RepairArea ... // Default is entire decorated control, // or use OpacityMask } 

Used as follows:

 <Grid> <WebBrowser x:Name="browser" ... /> <AirRepair Win32Host="{Binding ElementName=browser}" Margin="10" HorizontalAlignment="Left" ...> <TextBox ... /> </AirRepair> </Grid> 

AirRepair can be used with WebBrowser , WindowsFormsHost or any other HwndHost . The area covered by the decorated control is displayed inside Win32 content and receives focus and mouse events. For controls that do not have a rectangular decoration, the displayed area can be set with the RepairArea and / or OpacityMask .

How it works

AirRepair solves airspace issues:

  • Creating a child hWnd under a given HwndHost using HwndSource
  • Setting hRgn to the appropriate area
  • Configure RootVisual on a Border whose Background is a VisualBrush Decorated Control
  • Redirection WM_MOUSEMOVE etc. received by the hWnd child to the main WPF window

The result of this is that WPF continues to draw content behind Win32 content, but the AirRepair child window redraws the same content before the Win32 content in a separate Win32 control.

Some important implementation details

Getting parent hWnd

When Win32Host initially installed, it may or may not have hWnd. PropertyChangedCallback should use PresentationSource.AddSourceChangedHandler / PresentationSource.RemoveSourceChangedHandler to detect possible hWnd changes, and then update its own hWnd pointer in the Dispatcher.BeginInvoke HwndHost so that HwndHost can finish processing the SourceChanged event.

Creating a child hWnd

The hWnd child can be created, registered, and connected to managed code using the HwndSource class. Be sure to delete it when the parent Win32Host hWnd is no longer available.

Child placement hWnd

The position of the child hWnd window (relative to its parent) can be calculated as:

  var compositionTarget = PresentationSource.FromVisual(this).CompositionTarget; var position = compositionTarget.TransformToDevice( this.TransformToVisual(Win32Host)); 

The UIELement.LayoutUpdated event should be used to update this update.

HRgn calculation and opacity

Optional: omit if only rectangular repair areas are supported

When RepairArea or OpacityMask and there is a child hWnd, use RenderTargetBitmap to draw RepairArea with OpacityMask , then create hRgn. If RepairArea is null, use a rectangle. If OpacityMask is null, use black. The RenderTargetBitmap size RenderTargetBitmap set by converting the coordinates of the AirRepair decorator to the coordinates of the device. Note that this does not properly handle the OpacityMask variable, such as an animated brush, or VisualBrush , a Visual change.

Drawing content on child hWnd

Use VisualBrush , whose Visual is an AirRepair decorator, not a decorated control. This allows you to replace the decorated control without changing the content.

 childHwndSource.RootVisual = new Border { Background = new VisualBrush { Visual = this, ViewBoxUnits = BrushMappingMode.Absolute, ViewPortUnits = BrushMappingMode.Absolute, } }; 

Forwarding mouse messages

Add the hook using HwndSource.AddHook , then use Win32 PostMessage in the container:

 childHwndSource.AddHook((hwnd, msg, wParam, lParam, handled) => { // Check if message needs forwarding and update parameters if necessary switch(msg) { default: return; // Not recognized - do not forward case WM_MOUSEMOVE: ... } var target = PresentationSource.FromVisual(this).CompositionTarget as HwndTarget; if(target!=null) Win32Methods.PostMessage(target.Handle, msg, wParam, lParam); }; 
+1
source

If you are looking for a quick and easy solution, just use the popup menu, here is an example

http://karlshifflett.wordpress.com/2009/06/13/wpf-float-buttons-over-web-browser-control/

+1
source

If you specifically targeted your web browser, these were a few attempts. Chris Cavanagh has created a great Chrome-based solution.

0
source

Source: https://habr.com/ru/post/1303686/


All Articles