WPF WebBrowser 不可见问题的解析[转]

问题概述:

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

 

posted @ 2014-09-28 11:32  想飞的水  阅读(2938)  评论(2编辑  收藏  举报