wpf webBrowser控件 常用的函数和内存泄漏问题

介绍

WebBrowsers可以让我们在窗体中进行导航网页。

WebBrowser控件内部使用ie的引擎,因此使用WebBrowser我们必须安装ie浏览器(windows默认安装的)。

使用

直接在xmal中使用webBrowser控件

xaml 复制代码
<WebBrowser x:Name="WebBrowser1" Source ="xxx.com"></WebBrowser>

其中Source熟悉可以将webBrowser控件指向一个网页(也可以是本地文件的绝对路径)

除了使用Source属性还有以下方法进行导航:

问题

  • js报错
    默认情况下webBrowser用的是比较低的ie内核,这样如果访问的网页有不支持的脚本或者其他问题,就会没有办法正常运行,比如报错 javaScript错误。某些情况下使用ie可以打开的网页,在webBrowser需要管理员权限才可以正常打开,没有管理员权限也会报jabaScript错误。所以一般使用winForm的webBrowser,方便扩展,并且资料多。
    • 避免报错不弹提示框。
c# 复制代码
	WebBrowser1.Navigated += (sender, args) =>
	{
     	SetSilent(wbMain, true)
	}   
c# 复制代码
public static void SetSilent(WebBrowser browser, bool silent)
{
    if (browser == null)
     throw new ArgumentNullException("browser");

    // get an IWebBrowser2 from the document
    IOleServiceProvider sp = browser.Document as IOleServiceProvider;
    if (sp != null)
    {
        Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
        Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");

        object webBrowser;
        sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser);
        if (webBrowser != null)
        {
         webBrowser.GetType().InvokeMember("Silent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.PutDispProperty, null, webBrowser, new object[] { silent });
        }
    }
}
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IOleServiceProvider
{
    [PreserveSig]
    int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}

这种只是让它不出现报错窗口,不能从根本上解决。

  • 修改注册表使用新的ie内核,下面是代码:
c# 复制代码
 static void SetWebBrowserFeatures(int ieVersion)
    {
        if (LicenseManager.UsageMode != LicenseUsageMode.Runtime)
            return;
        var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
        UInt32 ieMode = GeoEmulationModee(ieVersion);
        var featureControlRegKey = @"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\";
        Registry.SetValue(featureControlRegKey + "FEATURE_BROWSER_EMULATION",
            appName, ieMode, RegistryValueKind.DWord);
        Registry.SetValue(featureControlRegKey + "FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION",
            appName, 1, RegistryValueKind.DWord);
    }

    static UInt32 GeoEmulationModee(int browserVersion)
    {
        UInt32 mode = 11000; // Internet Explorer 11. Webpages containing standards-based !DOCTYPE directives are displayed in IE11 Standards mode. 
        switch (browserVersion)
        {
            case 7:
                mode = 7000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE7 Standards mode. 
                break;
            case 8:
                mode = 8000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE8 mode. 
                break;
            case 9:
                mode = 9000; // Internet Explorer 9. Webpages containing standards-based !DOCTYPE directives are displayed in IE9 mode.                    
                break;
            case 10:
                mode = 10000; // Internet Explorer 10.
                break;
            case 11:
                mode = 11000; // Internet Explorer 11
                break;
        }
        return mode;
    }

比如你想使用最新的IE11

c# 复制代码
 SetWebBrowserFeatures(11);

在网页中强制以ie最高级别的可用模式显示内容

c# 复制代码
<meta http-equiv="X-UA-Compatible" content="edge" />

内存泄漏的解决方式

Memory leak when using WPF WebBrowser control in multiple windows

  • 将WebBrowser放到子进程中,每次开关都会重新分配内存
  • 删除掉所有引用,来清理内存泄漏。关闭窗口时调用下面代码。
c# 复制代码
    public void Dispose()
    {
        webBrowser.Dispose();

        var window = GetWindowElement(webBrowser);

        if (window == null)
            return;

        var field = typeof(Window).GetField("_swh", BindingFlags.NonPublic | BindingFlags.Instance);

        var valueSwh = field.GetValue(window);
        var valueSourceWindow = valueSwh.GetType().GetField("_sourceWindow", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(valueSwh);
        var valuekeyboardInput = valueSourceWindow.GetType().GetField("_keyboardInputSinkChildren", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(valueSourceWindow);

        var inputSites = valuekeyboardInput as IEnumerable<IKeyboardInputSite>;

        if (inputSites == null)
            return;

        var currentSite = inputSites.FirstOrDefault(s => ReferenceEquals(s.Sink, webBrowser));

        if (currentSite != null)
            currentSite.Unregister();
    }

    private static Window GetWindowElement(DependencyObject element)
    {
        while (element != null && !(element is Window))
        {
            element = VisualTreeHelper.GetParent(element);
        }

        return element as Window;
    }
相关推荐
hqwest10 小时前
C#WPF实战出真汁08--【消费开单】--餐桌面板展示
c#·wpf·ui设计·wpf界面设计
orangapple10 小时前
WPF 打印报告图片大小的自适应(含完整示例与详解)
c#·wpf
三千道应用题1 天前
WPF&C#超市管理系统(6)订单详情、顾客注册、商品销售排行查询和库存提示、LiveChat报表
开发语言·c#·wpf
✎ ﹏梦醒͜ღ҉繁华落℘2 天前
开发WPF项目时遇到的问题总结
wpf
hqwest3 天前
C#WPF实战出真汁06--【系统设置】--餐桌类型设置
c#·.net·wpf·布局·分页·命令·viewmodel
Vae_Mars3 天前
WPF中使用InputBindings进行快捷键绑定
wpf
hqwest3 天前
C#WPF实战出真汁05--左侧导航
开发语言·c#·wpf·主界面·窗体设计·视图viewmodel
hqwest3 天前
C#WPF实战出真汁01--项目介绍
开发语言·c#·wpf
wuty0074 天前
WPF 实现支持动态调整高度的文本显示控件
wpf·scrollviewer·extentheight·自动高度控件·动态调整高度
范纹杉想快点毕业7 天前
C 语言主控开发与显控开发能力体系及技术栈详解,STM32、QT、嵌入式、边缘系统显示
stm32·单片机·tcp/ip·microsoft·fpga开发·51单片机·wpf