你的位置:首页 > ASP.net教程

[ASP.net教程]WPF中AllowsTransparency和WebBrowser兼容性问题


最近项目中需要在WPF中加入WebBrowser控件,发现与AllowsTransparency="True" Window有冲突,在网上搜索了一下,找到的解决方案跟我的项目有冲突,只好自己解决。

产生原因:引自http://www.cnblogs.com/SkyD/archive/2009/12/16/1625216.html一段回复

原因在于 WebBrowser 控件是GDI负责呈现的。而WPF是用dx绘制的,但AllowsTransparency="True" Window 时原先由gdi绘制的窗体就没有了。完全用dx绘制。 WebBrowser 也就显示不出来,但能响应事件。

暂时想到最直接简单的解决办法就是做一个无边框不透明的窗体,在这个窗体上放置WebBrowser控件,将这个窗体置于需要WebBroswer的窗体之上(Owner),为了方便使用,封装成控件,包含两部分:

1、包含WebBrowser的窗体

2、自定义用户控件

 

1、窗体的xaml很简单,Web.xaml

<Window x:Class="ZControls.WebBrowserEx.Web"    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    ="http://schemas.microsoft.com/winfx/2006/xaml">  <Grid x:Name="grid"></Grid></Window>

b code,Web.xaml.cs

namespace ZControls.WebBrowserEx{  /// <summary>  /// Web.xaml 的交互逻辑  /// </summary>  public partial class Web : Window  {    public System.Windows.Forms.WebBrowser WebBrowser { get { return web_browser; } }    private System.Windows.Forms.Integration.WindowsFormsHost forms_host;    private System.Windows.Forms.WebBrowser web_browser;    public Web()    {      InitializeComponent();      this.WindowStyle = System.Windows.WindowStyle.None;      this.ResizeMode = System.Windows.ResizeMode.NoResize;      this.ShowInTaskbar = false;      forms_host = new System.Windows.Forms.Integration.WindowsFormsHost();      web_browser = new System.Windows.Forms.WebBrowser();      forms_host.Child = web_browser;      this.grid.Children.Add(forms_host);    }  }}

 

2、用户控件,WebBrowserExControl.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Interop;namespace ZControls.WebBrowserEx{  public class WebBrowserExControl : Canvas  {    public System.Windows.Forms.WebBrowser WebBrowser    {      get      {        return web == null ? null : web.WebBrowser;      }    }    public bool IsShow { get { return show; } }    private bool show = false;    private Web web = null;    private HwndSourceHook hook;    private HwndSource hwndSource;    private Window window;    private const int WM_MOVE = 0x0003;    private const int WM_MOVING = 0x0216;    private const int WM_SIZE = 0x0005;    private const int WM_SIZING = 0x0214;    private const int WM_ENTERSIZEMOVE = 0x231;    private const int WM_EXITSIZEMOVE = 0x232;    private const int WM_PAINT = 0x000F;    private const int WM_GETMINMAXINFO = 0x0024;//此消息发送给窗口当它将要改变大小或位置    private const int WM_WINDOWPOSCHANGING = 0x0046;//发送此消息给那个窗口的大小和位置将要被改变时,来调用setwindowpos函数或其它窗口管理函数    private const int WM_NCCALCSIZE = 0x0083;//当某个窗口的客户区域必须被核算时发送此消息    private const int WM_WINDOWPOSCHANGED = 0x0047;//发送此消息给那个窗口的大小和位置已经被改变时,来调用setwindowpos函数或其它窗口管理函数    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)    {      switch (msg)      {        //case WM_MOVE:        //case WM_MOVING:        //case WM_SIZE:        //case WM_SIZING:        //case WM_ENTERSIZEMOVE:        //case WM_EXITSIZEMOVE:        //case WM_GETMINMAXINFO:        //case WM_WINDOWPOSCHANGING:        //case WM_NCCALCSIZE:        //case WM_WINDOWPOSCHANGED:        case 49849: //case 0xc2b9: 这是一个很神奇的消息,可能是WPF专用                case WM_PAINT:          render_web();          break;      }      //Console.WriteLine(msg);      return IntPtr.Zero;    }    public WebBrowserExControl()    {      //this.Text = "WebBrowserExControl";    }    ~WebBrowserExControl()    {      Hide();    }    public void Show()    {      if (!show)      {        web = new Web();        window = Window.GetWindow(this);        hwndSource = PresentationSource.FromVisual(this) as HwndSource;        if (hwndSource != null)        {          hook = new HwndSourceHook(WndProc);          hwndSource.AddHook(hook);        }        web.Owner = window;        web.Show();        show = true;        render_web();      }    }    public void Hide()    {      if (hwndSource != null)      {        hwndSource.RemoveHook(hook);      }      if (web != null)      {        //try        //{        web.WebBrowser.Dispose();        web.Close();        //}        //catch { }        web = null;      }      show = false;    }    private void render_web()    {      if (show)      {        Point point = this.TransformToAncestor(window).Transform(new Point(0, 0));        //point = this.PointToScreen(point);        web.Left = window.Left + point.X;// -LeftEx;        web.Top = window.Top + point.Y;// -TopEx;        //point = this.PointToScreen(point);        //web.Left = point.X;// -LeftEx;        //web.Top = point.Y;// -TopEx;        web.Width = this.ActualWidth;        web.Height = this.ActualHeight;      }    }  }}

 

最后,直接在需要的地方引用这个控件

<WebBrowserEx:WebBrowserExControl Background="Aquamarine" x:Name="my_web"/>

b code

private void Button_Click(object sender, RoutedEventArgs e) {      var url = txt_url.Text;      my_web.Show();      my_web.WebBrowser.Navigate(url); }


在hook窗体的过程中,需要找一个窗体move与size改变的消息,尝试了半个多小时,找到消息 49849 (0xc2b9),能比较好的满足需求,猜想这个可能是WPF定义的消息。