说明:在同一窗口打开链接,只要稍加改造就可以实现,这里实现的是在新Tab页打开链接,并且支持带type="POST" target="_blank"的链接
github和bitbucket上相关问题:
1、WPF empty POST data when using custom popup https://github.com/cefsharp/CefSharp/issues/1267
2、CefLifeSpanHandler,customized OnBeforePopup problem https://bitbucket.org/chromiumembedded/cef/issues/1949/
解决(CefSharp版本75.1.143.0):
一、实现IRequestHandler接口
using CefSharp; System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks; System.Security.Cryptography.X509Certificates; namespace CefSharpDemo { public class RequestHandler : IRequestHandler { private ExtChromiumbrowser _browser; public RequestHandler(ExtChromiumbrowser browser) { _browser = browser; } bool GetAuthCredentials(IWebbrowser chromiumWebbrowser,Ibrowser browser,string originUrl,1)">bool isProxy,1)">string host,1)">int port,1)">string realm,1)">string scheme,IAuthCallback callback) { return false; } public IResourceRequestHandler GetResourceRequestHandler(IWebbrowser chromiumWebbrowser,IFrame frame,IRequest request,1)">bool isNavigation,1)">bool isDownload,1)">string requestinitiator,1)">ref bool disableDefaultHandling) { if (request.Method.toupper() == "POST" && request.PostData != null) { if (request.PostData.Elements.Count > 0) { _browser.PostData = new byte[request.PostData.Elements[].Bytes.Length]; request.PostData.Elements[0].Bytes.copyTo(_browser.PostData,); } } bool OnBeforebrowse(IWebbrowser chromiumWebbrowser,1)">bool userGesture,1)"> isRedirect) { bool OnCertificateError(IWebbrowser chromiumWebbrowser,CefErrorCode errorCode,1)"> requestUrl,ISslInfo sslInfo,IRequestCallback callback) { bool OnopenUrlFromTab(IWebbrowser chromiumWebbrowser,1)">string targetUrl,WindowOpendisposition targetdisposition,1)"> userGesture) { void OnPluginCrashed(IWebbrowser chromiumWebbrowser,1)"> pluginPath) { } bool OnQuotaRequest(IWebbrowser chromiumWebbrowser,1)">long newSize,1)">void OnRenderProcessterminated(IWebbrowser chromiumWebbrowser,CefTerminationStatus status) { } OnRenderViewReady(IWebbrowser chromiumWebbrowser,Ibrowser browser) { } bool OnSelectClientCertificate(IWebbrowser chromiumWebbrowser,1)">int port,X509Certificate2Collection certificates,ISelectClientCertificateCallback callback) { ; } } }
二、实现ILifeSpanHandler接口
System.Collections.Specialized; System.Runtime.InteropServices; System.Threading; System.Windows; System.Windows.Interop; Utils; CefLifeSpanHandler : CefSharp.ILifeSpanHandler { private static LimitedTaskScheduler _scheduler = new LimitedTaskScheduler(2); CefLifeSpanHandler() { } DoClose(IWebbrowser browserControl,CefSharp.Ibrowser browser) { if (browser.Isdisposed || browser.IsPopup) { ; } true OnAfterCreated(IWebbrowser browserControl,1)"> OnBeforeClose(IWebbrowser browserControl,Ibrowser browser) { } bool OnBeforePopup(IWebbrowser browserControl,1)">string targetFrameName,IPopupFeatures popupFeatures,IWindowInfo windowInfo,IbrowserSettings browserSettings,1)">bool noJavascriptAccess,1)">out IWebbrowser newbrowser) { var chromiumWebbrowser = (ExtChromiumbrowser)browserControl; chromiumWebbrowser.dispatcher.Invoke(new Action(() => { browserPopupWin win = new browserPopupWin(); win.ShowInTaskbar = ; win.Height = ; win.Width = ; win.Show(); IntPtr handle = WindowInteropHelper(win).Handle; windowInfo.SetAsChild(handle); _scheduler.Run(() => { WaitUtil.Wait(() => chromiumWebbrowser.PostData); IRequest request = ; if (chromiumWebbrowser.PostData != ) { request = frame.CreateRequest(); request.Url = targetUrl; request.Method = "; request.InitializePostData(); var element = request.PostData.CreatePostDataElement(); element.Bytes = chromiumWebbrowser.PostData; request.PostData.AddElement(element); chromiumWebbrowser.PostData = ; } chromiumWebbrowser.dispatcher.Invoke( { NewWindowEventArgs e = NewWindowEventArgs(targetUrl,request); chromiumWebbrowser.OnNewWindow(e); })); chromiumWebbrowser.dispatcher.Invoke( { win.Close(); })); }); })); newbrowser = ; ; } } }
三、扩展ChromiumWebbrowser
CefSharp.Wpf; System.Threading.Tasks; ExtChromiumbrowser : ChromiumWebbrowser { byte[] PostData { get; set; } ExtChromiumbrowser() : base() { this.LifeSpanHandler = CefLifeSpanHandler(); this.DownloadHandler = new DownloadHandler(this); this.MenuHandler = MenuHandler(); this.KeyboardHandler = KeyboardHandler(); this.RequestHandler = new RequestHandler(); } event EventHandler<NewWindowEventArgs> StartNewWindow; OnNewWindow(NewWindowEventArgs e) { if (StartNewWindow != ) { StartNewWindow(,e); } } ClearHandlers() { //如果不清理Handler,会导致子进程CefSharp.browserSubprocess.exe无法释放 ; } } }
四、封装ExtChromiumbrowser(browserCtrl控件)
System.ComponentModel; System.IO; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input; System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes; CefSharpDemo { /// <summary> /// 浏览器用户控件 </summary> partial browserCtrl : UserControl,Idisposable { #region 外部方法 /* [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); */ #endregion #region 变量属性事件 static bool _isCefInited = ; object _lockObject = object(); JSObject _jsObject; bool _firstLoad = ; <summary> 在此事件中设置URL(此事件已在线程中执行,此事件已对错误情况进行处理) </summary> event EventHandler SetUrlEvent; URL string Url { public IRequest Request { ; } 浏览器FrameLoadEnd事件 EventHandler FrameLoadEnd; ExtChromiumbrowser browser { get { WaitUtil.Wait(() => this._browser != null && this._browser.IsInitialized && _isCefInited); ._browser; } } ); #region 构造函数 browserCtrl() { InitializeComponent(); if (DesignerProperties.GetIsInDesignMode(this)) return; this.Loaded += browserCtrl_Loaded; lock (_lockObject) { if (!_isCefInited) { _isCefInited = ; InitCef();初始化CefSharp } } _browser = ExtChromiumbrowser(); Bindbrowser(_browser); grid.Children.Add(_browser); } #region browserCtrl_Loaded void browserCtrl_Loaded( sender,RoutedEventArgs e) { } #region SetMapCtrl 设置Map控件接口,用于C#和JS互操作 SetMapCtrl(IMapCtrl mapCtrl) { _jsObject.MapCtrl = mapCtrl; } #region dispose 释放资源 释放资源 dispose() { 如果有弹出窗口则先释放它 foreach (UIElement item in grid.Children) { if (item is browserContainer) { (item as browserContainer).ClearResource(); } } _browser.ClearHandlers(); if (_browser != null && !_browser.Isdisposed) { _browser.dispose(); } } #region Load void Load( url) { .IsNullOrWhiteSpace(url)) { loadingWait.Visibility = Visibility.Visible; Url = url; _scheduler.Run(() => { #region Wait WaitUtil.Wait(() => { if (this._browser == null) ; this._browser.IsInitialized) if (!_isCefInited) bool isbrowserInitialized = this.dispatcher.Invoke(() => { isbrowserInitialized = ._browser.IsbrowserInitialized; }); if (!isbrowserInitialized) ; }); #endregion _browser.Load(Url); }); } } #region LoadUrl LoadUrl() { if (_firstLoad) { _firstLoad = ; _scheduler.Run(() =>#endregion if (Url == null && SetUrlEvent != ) { try { SetUrlEvent(this,1)">); } catch (Exception ex) { LogUtil.Error(ex,browserCtrl LoadUrl error 获取URL失败); } } elsethis.dispatcher.Invoke( { loadingWait.Visibility = Visibility.Collapsed; })); } if (Url != { if (Request == ) { _browser.Load(Url); } { _browser.Load(Url); _browser.GetMainFrame().LoadRequest(Request); Request = ; } } browserCtrl LoadUrl error Load URL失败 Visibility.Collapsed; })); } }); } } #region Bindbrowser Bindbrowser(ExtChromiumbrowser browser) { _jsObject = JSObject(); browser.RegisterJsObject(jsObj",_jsObject,1)">new CefSharp.BindingOptions { CamelCaseJavascriptNames = }); browser.IsbrowserInitializedChanged += (ss,ee) => { LoadUrl(); }; browser.FrameLoadStart += (ss,1)"> { this.dispatcher.BeginInvoke( { (ss as ExtChromiumbrowser).Focus(); })); }; browser.FrameLoadEnd += (ss,1)"> { loadingWait.Visibility = Visibility.Collapsed; })); if (FrameLoadEnd != ) { FrameLoadEnd(null,1)">); } }; browser.KeyDown += (ss,1)">if (ee.Key == Key.F5) { { browser.Reload(); } (Exception ex) { LogUtil.Error(ex,1)">ExtChromiumbrowser Reload error); } } }; browser.PreviewTextInput += (o,e) =>foreach (var character in e.Text) { 把每个字符向浏览器组件发送一遍 browser.Getbrowser().GetHost().SendKeyEvent((int)WM.CHAR,(int)character,1)">); } 不让cef自己处理 e.Handled = ; }; browser.LoadError += (s,1)"> Visibility.Collapsed; })); }; } #region RegisterJsObject void RegisterJsObject(string name,1)">object objectToBind,BindingOptions options = ) { ) { _browser.RegisterJsObject(name,objectToBind,options); } } (Exception ex) { LogUtil.Error(ex,1)">browserCtrl RegisterJsObject 错误); } } #region 初始化CefSharp InitCef() { string cefsharpFolder = CefSharpvar settings = 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 = ; CefSharpSettings.FocusednodeChangedEnabled = ; CefSharpSettings.LegacyJavascriptBindingEnabled = ; CefSharpSettings.ShutdownOnExit = ; CefSharpSettings.SubprocessExitIfParentProcessClosed = string logDir = AppDomain.CurrentDomain.BaseDirectory + cefsharpFolder + /log/Directory.Exists(logDir)) { Directory.CreateDirectory(logDir); } settings.browserSubprocesspath = AppDomain.CurrentDomain.BaseDirectory + cefsharpFolder + /CefSharp.browserSubprocess.exe; settings.LogFile = logDir + DateTime.Now.ToString(yyyyMMdd") + .log; settings.LocalesDirPath = AppDomain.CurrentDomain.BaseDirectory + cefsharpFolder + /locales; settings.CefCommandLineArgs.Add(disable-gpu1); settings.CefCommandLineArgs.Add(enable-media-stream); if (!Cef.Initialize(settings,performDependencyCheck: true,browserProcessHandler: browserProcessHandler())) { throw new Exception(Unable to Initialize Cef } }
五、MainWindow测试代码
CefSharp Demo 窗体 MainWindow : Window { MainWindow() { InitializeComponent(); tabControl.AddTabItemEvent += tabControl_AddTabItemEvent; Application.Current.MainWindow = void tabControl_AddTabItemEvent(CreateTabItem("https://www.cnblogs.com/"); CreateTabItem(file:///D:/_程序/CefSharpDemo/post.html); } 新增Tab页 void CreateTabItem(string url = ) { TabItem tabItem = TabItem(); tabItem.Header = 新标签页; browserDemoCtrl ctrl = browserDemoCtrl(); ctrl.browserCtrl.browser.StartNewWindow += (s,1)"> { CreateTabItem(e.TargetUrl,e.Request); }; ctrl.browserCtrl.SetUrlEvent += (s,1)"> { ctrl.browserCtrl.Url = url; ctrl.browserCtrl.Request = request; }; tabItem.Content = ctrl; tabControl.Items.Add(tabItem); tabControl.SelectedItem = tabItem; ScrollViewer scrollViewer = tabControl.Template.FindName(scrollViewer ScrollViewer; scrollViewer.ScrollToRightEnd(); } void Window_Closed(关闭窗体清理资源 程序退出时删除cache CefSharp.Cef.Shutdown(); string cachePath = AppDomain.CurrentDomain.BaseDirectory + CefSharp\\cache (Directory.Exists(cachePath)) { string path Directory.GetDirectories(cachePath)) { Directory.Delete(path,); } string file Directory.GetFiles(cachePath)) { if (!file.ToLower().Contains(cookies)) { File.Delete(file); } } } } } }
六、测试HTML代码post.html
<!DOCTYPE html> <htmlhead> title>CefSharpDemo</> Meta charset="utf-8" /> http-equiv="X-UA-Compatible" content="IE=edge"name="viewport"="width=device-width,initial-scale=1"style type="text/css"stylescript ="text/javascript"scriptbody<!--enctype="multipart/form-data"--> form method="post" action="http://localhost:1209/netcms/" target="_blank"> span>name:><input ="text" name="name" value="测试名称" /> >code:="code"="测试编码" /> button ="submit">Post提交buttonform>
ActionResult index() { string name = Request.Params[name]; string code = Request.Params[code]; ViewBag.name = name; ViewBag.code = code; View(); }
@using Models; @{ Layout = "~/Views/Shared/_SiteLayout.cshtml"; } div ="font-size:50px; height:1200px;">@ViewBag.namebr /><>@ViewBag.codediv>
九:关键代码段:
1、RequestHandler类中获取并保存PostData
disableDefaultHandling) { ) { ) { _browser.PostData = ].Bytes.Length]; request.PostData.Elements[); } } ; }
2、CefLifeSpanHandler类中创建IRequest
IWebbrowser newbrowser) { (ExtChromiumbrowser)browserControl; chromiumWebbrowser.dispatcher.Invoke( { browserPopupWin win = browserPopupWin(); win.ShowInTaskbar = ; win.Height = ; win.Width = ; win.Show(); IntPtr handle = WindowInteropHelper(win).Handle; windowInfo.SetAsChild(handle); _scheduler.Run(() => { WaitUtil.Wait(() => chromiumWebbrowser.PostData); IRequest request = ) { request = frame.CreateRequest(); request.Url = targetUrl; request.Method = ; request.InitializePostData(); request.PostData.CreatePostDataElement(); element.Bytes = chromiumWebbrowser.PostData; request.PostData.AddElement(element); chromiumWebbrowser.PostData = ; } chromiumWebbrowser.dispatcher.Invoke( { NewWindowEventArgs e = browser.OnNewWindow(e); })); chromiumWebbrowser.dispatcher.Invoke( { win.Close(); })); }); })); newbrowser = ; ; }
说明:OnBeforePopup方法要return false,用browserPopupWin和windowInfo.SetAsChild方法弹出一个不可见的窗体,这样才能拿到PostData
3、在browserCtrl控件中用LoadRequest方法打开新的URL,并把post数据带过去
) { _browser.Load(Url); } { _browser.Load(Url); _browser.GetMainFrame().LoadRequest(Request); Request = ; }
十、效果图:
完整代码下载:https://files-cdn.cnblogs.com/files/s0611163/CefSharpDemo.zip
源码说明:为了减少源码压缩包的大小,代码中没有依赖的CefSharp文件,请自己下载(使用x86版本),用于测试的网页后台代码也没有,请自己制作测试后台
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。