当前位置: 移动技术网 > IT编程>开发语言>.net > CefSharp.v49.0.1浏览器控件完全WPF版,实现禁止弹出新窗口,在同一窗口打开链接,并且支持带type="POST" target="_blank"的链接

CefSharp.v49.0.1浏览器控件完全WPF版,实现禁止弹出新窗口,在同一窗口打开链接,并且支持带type="POST" target="_blank"的链接

2018年12月14日  | 移动技术网IT编程  | 我要评论

魏海娜,爱意文学,位面征战传奇

    需求场景:在查询页面,填写查询条件,查询条件包括上传的图片,根据图片的特征查询,这就需要在提交的时候,使用post提交,因为get提交无法提交图片数据,提交查询条件之后,在新的窗口展示查询结果。(当然查询结果页面可能不支持f5刷新页面)

表单html代码示意(注意method="post" target="_blank" action指向新页面):

<!doctype html>
<html>
<head>
    <title>提交表单查询</title>
    <script type="text/javascript" src='jquery.js'></script>
    <script type="text/javascript">
        //保存
        function save() {
            $("#frm").submit();
        }
    </script>
</head>
<body>
    <form id="frm" action="searchresult" enctype="multipart/form-data" method="post" target="_blank">
        <input type="text" class="input-text" id="title" name="title" value="测试title" style="width: 300px;" />
        <input type="text" class="input-text" id="name" name="name" value="测试name" style="width: 300px;" />
        <a href="javascript:void(0);" onclick="save()">保存</a>
    </form>
</body>
</html>
view code

请先大致看下winform版的cefsharp浏览器控件实现方式:

下面是wpf版的cefsharp浏览器控件的实现方式,与winform版相同的代码这里不再粘贴:

using cefsharp;
using log4net;
using suncreate.vipf.base;
using suncreate.vipf.client.bussiness;
using system;
using system.collections.generic;
using system.componentmodel;
using system.linq;
using system.runtime.interopservices;
using system.text;
using system.threading;
using system.threading.tasks;
using system.windows;
using system.windows.controls;
using system.windows.data;
using system.windows.documents;
using system.windows.input;
using system.windows.interop;
using system.windows.media;
using system.windows.media.imaging;
using system.windows.navigation;
using system.windows.shapes;

namespace suncreate.vipf.client.ui
{
    /// <summary>
    /// 浏览器用户控件
    /// </summary>
    public partial class browserctrl : usercontrol, idisposable
    {
        [dllimport("user32.dll", setlasterror = true)]
        private static extern intptr setparent(intptr hwndchild, intptr hwndnewparent);
        [dllimport("user32.dll", setlasterror = true)]
        public static extern intptr findwindowex(intptr parenthandle, intptr childafter, string classname, string windowtitle);
        [dllimport("user32.dll", setlasterror = true)]
        public static extern int movewindow(intptr hwnd, int x, int y, int nwidth, int nheight, bool brepaint);
        [dllimport("user32.dll", setlasterror = true)]
        public static extern int closewindow(intptr hwnd);
        [dllimport("user32.dll", entrypoint = "getwindowtext")]
        private static extern int getwindowtext(intptr hwnd, stringbuilder lpstring, int nmaxcount);

        private ilog _log = logmanager.getlogger(typeof(browserctrl));

        private static bool _iscefinited = false;

        private static object _lockobject = new object();

        private jsobject _jsobject;

        private bool _firstload = true;

        /// <summary>
        /// 在此事件中设置url(此事件已在线程中执行,此事件已对错误情况进行处理)
        /// </summary>
        public event eventhandler seturlevent;

        /// <summary>
        /// url
        /// </summary>
        public string url { get; set; }

        /// <summary>
        /// 浏览器frameloadend事件
        /// </summary>
        public event eventhandler frameloadend;

        private extchromiumbrowser _browser;

        public extchromiumbrowser browser
        {
            get
            {
                return this._browser;
            }
        }

        public browserctrl()
        {
            initializecomponent();
            if (designerproperties.getisindesignmode(this)) return;

            this.loaded += browserctrl_loaded;

            lock (_lockobject)
            {
                if (!_iscefinited)
                {
                    _iscefinited = true;
                    initcef(true);//初始化cefsharp
                }
            }

            _browser = new extchromiumbrowser();
            bindbrowser(_browser);
            grid.children.add(_browser);
        }

        /// <summary>
        /// 设置map控件接口,用于c#和js互操作
        /// </summary>
        public void setmapctrl(imapctrl mapctrl)
        {
            _jsobject.mapctrl = mapctrl;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void dispose()
        {
            //如果有弹出窗口则先释放它
            foreach (uielement item in grid.children)
            {
                if (item is browsercontainer)
                {
                    (item as browsercontainer).clearresource();
                }
            }

            if (_browser != null && !_browser.isdisposed)
            {
                _browser.dispose();
            }
        }

        private void browserctrl_loaded(object sender, routedeventargs e)
        {

        }

        private void loadurl()
        {
            if (_firstload)
            {
                _firstload = false;
                system.threading.tasks.task.factory.startnew(() =>
                {
                    thread.sleep(100);

                    if (url == null && seturlevent != null)
                    {
                        try
                        {
                            seturlevent(this, null);
                        }
                        catch (exception ex)
                        {
                            _log.error("browserctrl loadurl error 获取url失败", ex);
                        }
                    }

                    this.dispatcher.invoke(new action(() =>
                    {
                        _browser.load(url);
                    }));
                });
            }
        }

        private void bindbrowser(extchromiumbrowser browser)
        {
            _jsobject = new jsobject();
            browser.registerjsobject("jsobj", _jsobject, false);
            browser.startnewwindow += (s, e) =>
            {
                try
                {
                    intptr hwndchild = intptr.zero; //浏览器弹出窗口句柄

                    browsercontainer browsercontainer = new browsercontainer();
                    system.windows.forms.control control = new system.windows.forms.control();
                    control.dock = system.windows.forms.dockstyle.fill;
                    control.createcontrol();
                    browsercontainer.host.child = control;
                    browsercontainer.clearresourceevent += (ss, ee) =>
                    {
                        closewindow(hwndchild);
                        control.dispose();
                        browsercontainer.host.dispose();
                    };

                    //释放上一个弹出窗口
                    foreach (uielement item in grid.children)
                    {
                        if (item is browsercontainer)
                        {
                            (item as browsercontainer).clearresource();
                        }
                    }

                    grid.children.clear();
                    grid.children.add(browsercontainer);

                    e.windowinfo.setaschild(control.handle, 0, 0, (int)browsercontainer.actualwidth, (int)browsercontainer.actualheight);

                    browsercontainer.sizechanged += (ss, ee) =>
                    {
                        hwndchild = findwindowex(control.handle, intptr.zero, null, null);
                        movewindow(hwndchild, 0, 0, (int)browsercontainer.actualwidth, (int)browsercontainer.actualheight, true);
                    };
                }
                catch (exception ex)
                {
                    _log.error("browserctrl bindbrowser error", ex);
                }
            };
            browser.isbrowserinitializedchanged += (ss, ee) =>
            {
                loadurl();
            };
            browser.frameloadstart += (ss, ee) =>
            {
                this.dispatcher.begininvoke(new action(() =>
                {
                    (ss as extchromiumbrowser).focus();
                }));
            };
            browser.frameloadend += (ss, ee) =>
            {
                this.dispatcher.begininvoke(new action(() =>
                {
                    loadingwait.visibility = visibility.collapsed;
                }));
                if (frameloadend != null)
                {
                    frameloadend(null, null);
                }
            };
            browser.keydown += (ss, ee) =>
            {
                if (ee.key == key.d)
                {
                    //_browser.executescriptasync("dayornightmap", 0);
                }
                if (ee.key == key.n)
                {
                    //_browser.executescriptasync("dayornightmap", 1);
                }
            };
            browser.loaderror += (ss, ee) =>
            {
                _log.error("extchromiumbrowser loaderror 错误码:" + ee.errorcode + ",错误信息:" + ee.errortext + ",错误url:" + ee.failedurl);

                return; //下面代码不执行
                system.threading.tasks.task.factory.startnew(() =>
                {
                    if (url == null && seturlevent != null)
                    {
                        try
                        {
                            seturlevent(this, null);
                        }
                        catch (exception ex)
                        {
                            _log.error("browserctrl loadurl error 获取url失败", ex);
                        }
                    }

                    thread.sleep(500);
                    this.dispatcher.begininvoke(new action(() =>
                    {
                        (ss as extchromiumbrowser).load(url);
                    }));
                });
            };
        }

        #region 初始化cefsharp
        public static void initcef(bool multithreadedmessageloop)
        {
            string cefsharpfolder = "cefsharp.v49.0.1";

            var settings = new cefsettings();
            //the location where cache data will be stored on disk. if empty an in-memory cache will be used for some features and a temporary disk cache for others.
            //html5 databases such as localstorage will only persist across sessions if a cache path is specified. 
            // settings.cachepath = cefsharpfolder + "/cache"; //注释掉,不使用cache

            settings.multithreadedmessageloop = multithreadedmessageloop;
            settings.focusednodechangedenabled = true;

            cef.oncontextinitialized = delegate
            {
                var cookiemanager = cef.getglobalcookiemanager();
                cookiemanager.setstoragepath(cefsharpfolder + "/cookies", true);
                cookiemanager.setsupportedschemes("custom");
            };

            settings.browsersubprocesspath = appdomain.currentdomain.basedirectory + cefsharpfolder + "/cefsharp.browsersubprocess.exe";
            settings.logfile = cefsharpfolder + "/debug.log";
            settings.cefcommandlineargs.add("disable-gpu", "1");
            settings.cefcommandlineargs.add("enable-media-stream", "1");

            if (!cef.initialize(settings, shutdownonprocessexit: true, performdependencycheck: true))
            {
                throw new exception("unable to initialize cef");
            }
        }
        #endregion

    }
}
view code

 核心代码(startnewwindow):

browser.startnewwindow += (s, e) =>
{
    try
    {
        intptr hwndchild = intptr.zero; //浏览器弹出窗口句柄

        browsercontainer browsercontainer = new browsercontainer();
        system.windows.forms.control control = new system.windows.forms.control();
        control.dock = system.windows.forms.dockstyle.fill;
        control.createcontrol();
        browsercontainer.host.child = control;
        browsercontainer.clearresourceevent += (ss, ee) =>
        {
            closewindow(hwndchild);
            control.dispose();
            browsercontainer.host.dispose();
        };

        //释放上一个弹出窗口
        foreach (uielement item in grid.children)
        {
            if (item is browsercontainer)
            {
                (item as browsercontainer).clearresource();
            }
        }

        grid.children.clear();
        grid.children.add(browsercontainer);

        e.windowinfo.setaschild(control.handle, 0, 0, (int)browsercontainer.actualwidth, (int)browsercontainer.actualheight);

        browsercontainer.sizechanged += (ss, ee) =>
        {
            hwndchild = findwindowex(control.handle, intptr.zero, null, null);
            movewindow(hwndchild, 0, 0, (int)browsercontainer.actualwidth, (int)browsercontainer.actualheight, true);
        };
    }
    catch (exception ex)
    {
        _log.error("browserctrl bindbrowser error", ex);
    }
};
view code

核心代码(资源释放):

/// <summary>
/// 释放资源
/// </summary>
public void dispose()
{
    //如果有弹出窗口则先释放它
    foreach (uielement item in grid.children)
    {
        if (item is browsercontainer)
        {
            (item as browsercontainer).clearresource();
        }
    }

    if (_browser != null && !_browser.isdisposed)
    {
        _browser.dispose();
    }
}
view code

 难点:弹出窗口和原来的窗口似乎共用同一个chromiumwebbrowser实例的某些东西,但是弹出的窗口本身又获取不到chromiumwebbrowser实例,某些操作不便。

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网