问题概述: 1.在Xaml中加入WebBrowser(不论是WPF中的控件,还是Winform中的控件)
2.设置Window Background="Transparent" AllowsTransparency="True" 结果:WebBroser中的内容将不可见。
问题分析:
本人当时一WPF菜鸟,根本无从下手。实乃WPF已广为人知的问题。原因很简单:
1.所谓WPF中的WebBrowser控件实为利用MS WebBrowser 经过WPF封装,其实质和Winform中的WebBrowser一样无非是加入了一些简单DependencyProperty,使其能够在Xaml中进行配置,其使用看起来和其他WPF控件一致。其内核仍是基于Win32。 2.明白了WPF/Winform 中WebBrowser控件的实质,我们进入主题,众所周知WPF所推崇的乃其划时代的图形渲染技术,这里不做展开。大家明白WPF采用矢量技术,消除了页面缩放过程中锯齿现象。因此WPF实现了于分辨率无关。但是Win32的渲染技术却非基于矢量技术。故WebBrowser的内在渲染和WPF有本质区别。 3.当我们设置Window Background="Transparent" AllowsTransparency="True" 以期实现玻璃窗口时WebBrowser不能完成WPF的渲染,因此出现如上所述WebBrowser内容不可见的问题。
结论: 不能将非WPF元素(例如基于Win32的控件)放入WPF中进行渲染,否则,基于Win32的控件将渲染失败,例如缩放失败,颜色渲染失败等等与矢量技术相关的属性设置。对于本章问题,若要混合使用基于Win32的控件和WPF控件,并且要设置 Window Background="Transparent" AllowsTransparency="True" 以实现多主体支持,应该将Win32元素放入Win32窗口,达到分开渲染的目的。
解决方案: 1.不要将WebBrowser直接在在Xaml中使用, 用以简单元素代替,如Canvas Grid Border等等Container皆可。用于定位 2.将WebBrowser,加为Form的child,自己封装,实现例如缩放等自定义功能。 3.在Window,初始化的时候,实例化经过Form封装的WebBrowser,并定位到步骤一中所述的Container。
Sample Code: Xaml: <Grid Name="IEcontainer" Grid.Column="0" Width="1006" Height="577"/>
WebBrowser封装:
static class Win32 { [StructLayout(LayoutKind.Sequential)] public struct POINT { ....... [DllImport("user32.dll")]
internal static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint);
[DllImport("user32.dll")] internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth,int nHeight, bool bRepaint);
};
class WebBrowserOverlayWF { Window _owner; FrameworkElement _placementTarget; Form _form; // the top-level window holding the WebBrowser control WebBrowser _wb = new WebBrowser(); ....................... public WebBrowserOverlayWF(FrameworkElement placementTarget) { _placementTarget = placementTarget; Window owner = Window.GetWindow(placementTarget); _owner = owner;
_form = new Form(); _form.ShowInTaskbar = false; _form.FormBorderStyle = FormBorderStyle.None; _wb.Dock = DockStyle.Fill; _form.Controls.Add(_wb); _wb.ScrollBarsEnabled = false;
owner.SizeChanged += delegate { OnSizeLocationChanged(); }; owner.LocationChanged += delegate { OnSizeLocationChanged(); }; _placementTarget.SizeChanged += delegate { OnSizeLocationChanged(); };
if (owner.IsVisible) InitialShow(); else owner.SourceInitialized += delegate{InitialShow(););
..........
}
void InitialShow() { NativeWindow owner = new NativeWindow(); owner.AssignHandle( ((HwndSource)HwndSource.FromVisual(_owner)).Handle); _form.Show(owner); owner.ReleaseHandle(); } ............... }
Window Loaded:
WebBrowserOverlayWF wbo = new WebBrowserOverlayWF(IEcontainer);
拓展: 上例中演示了如何将基于Win32的控件封装到WPF中,实现了缩放,和重定位的功能(篇幅限制,如需具体代码,请联系本人)。其实我们无意中已经涉及到了控件的封装和重写。今后将陆续和大家分享更多WPF控件封装和重写的技术。 |
联系客服