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

    需求场景:在查询页面,填写查询条件,查询条件包括上传的图片,根据图片的特征查询,这就需要在提交的时候,使用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浏览器控件实现方式:

https://www.cnblogs.com/s0611163/p/7716692.html

下面是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实例,某些操作不便。

 

posted @ 2018-12-13 18:13  0611163  阅读(1912)  评论(0编辑  收藏  举报