wpf*_*abe 5 wpf rendering hwnd webbrowser-control
我想可以肯定地说 WPF 将其内容呈现为窗口背景。不存在传统 HWND 意义上的子窗口。因此,当人们在 WPF 应用程序中引入基于 HWND 的东西(例如 Web 浏览器)时,视觉外观方面的情况就开始出错。
考虑一个窗口,它有一个带有两个子项的网格、WebBrowser 和其他东西,例如文本框。如果 WebBrowser 是一个红色圆圈,则文本框将呈现在其顶部。对于 WebBrowser,在任何地方都找不到 TextBox。这是因为 TextBox 被渲染为主窗口的背景,而 WebBrowser 实际上是主窗口的 HWND 子窗口,遮挡了背景。
所以一切都(不)很好。一个人如何实现期望的行为?我想让 TextBox 在 WebBrowser 之上呈现。有人遇到过这个问题吗?
我正在考虑拥有第二个透明的顶级无边框 WPF 窗口,重新设置它的父级,以便主窗口拥有它,并执行一些其他技巧来实现它。
在深入研究之前,我想知道是否有人有一个明显或更简单的解决方案?
我向任何可以发布 Ray Burns Answer 实现的人提供此赏金AirRepair
。我自己尝试过但没有成功
建议的解决方案
我建议使用以下签名的简单“AirRepair”类:
public class AirRepair : Decorator
{
public HwndHost Win32Host ... // DP bound to HwndHost
public Geometry RepairArea ... // Default is entire decorated control,
// or use OpacityMask
}
Run Code Online (Sandbox Code Playgroud)
使用这种方式:
<Grid>
<WebBrowser x:Name="browser" ... />
<AirRepair Win32Host="{Binding ElementName=browser}"
Margin="10" HorizontalAlignment="Left" ...>
<TextBox ... />
</AirRepair>
</Grid>
Run Code Online (Sandbox Code Playgroud)
WebBrowser
AirRepair 可以与、、WindowsFormsHost
或任何其他一起使用HwndHost
。装饰控件覆盖的区域显示在 Win32 内容内,并且它接受焦点和鼠标事件。RepairArea
对于非矩形修饰控件,可以通过和/或OpacityMask
属性指定要显示的区域。
怎么运行的
AirRepair 通过以下方式解决空域问题:
HwndHost
在给定的using下创建一个子 hWndHwndSource
RootVisual
为a Border
,其是装饰控件的Background
aVisualBrush
WM_MOUSEMOVE
将子 hWnd 接收到的等转发到主 WPF 窗口这样做的结果是,WPF 继续绘制Win32 内容后面的内容,但 AirRepair 的子窗口在单独的 Win32 控件中重新绘制 Win32 内容前面的相同内容。
一些重要的实施细节
获取父级 hWnd
最初设置时Win32Host
,它可能有也可能没有 hWnd。应该PropertyChangedCallback
使用PresentationSource.AddSourceChangedHandler
/PresentationSource.RemoveSourceChangedHandler
来检测可能的 hWnd 更改,然后在回调中更新其自己的 hWnd 指针Dispatcher.BeginInvoke
,以便HwndHost
有机会完成SourceChanged
事件处理。
创建子 hWnd
可以使用该类在托管代码中创建子 hWnd、为其设置父级并挂钩HwndSource
。当 Win32Host 的父 hWnd 不再可用时,请务必将其丢弃。
定位子 hWnd
子 hWnd 的窗口位置(相对于其父窗口)可以计算为:
var compositionTarget = PresentationSource.FromVisual(this).CompositionTarget;
var position = compositionTarget.TransformToDevice(
this.TransformToVisual(Win32Host));
Run Code Online (Sandbox Code Playgroud)
应使用该UIELement.LayoutUpdated
事件来保持最新状态。
计算 hRgn 和不透明度
可选:如果仅支持矩形修复区域,则省略
当设置了RepairArea
orOpacityMask
并且子 hWnd 存在时,使用 a来RenderTargetBitmap
绘制,然后从中创建 hRgn。如果为空,则使用矩形。如果为空,则使用黑色。大小是通过将 AirRepair 装饰器的坐标转换为设备坐标来设置的。请注意,这不能正确处理变量,例如动画画笔或正在变化的画笔。RepairArea
OpacityMask
RepairArea
OpacityMask
RenderTargetBitmap
OpacityMask
VisualBrush
Visual
在子 hWnd 上绘制内容
使用AirRepair 装饰VisualBrush
器Visual
,而不是装饰控件。这允许在不改变内容的情况下替换修饰的控件。
childHwndSource.RootVisual =
new Border
{
Background = new VisualBrush
{
Visual = this,
ViewBoxUnits = BrushMappingMode.Absolute,
ViewPortUnits = BrushMappingMode.Absolute,
}
};
Run Code Online (Sandbox Code Playgroud)
转发鼠标消息
使用 添加钩子,然后在容器中HwndSource.AddHook
使用 Win32 :PostMessage
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);
};
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5550 次 |
最近记录: |