問題概述:
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控件封裝和重寫的技術。
原文: http://hi.baidu.com/leo_han/item/cd1debbf4dfbb3462bebe30a
