CefSharp 实现多标签页 调用ChromiumWebBrowser的SetAsPopup()后浏览页卡死,的另一种解决方案
最进想使用WPF+CefSharp实现浏览器多标签页, 所以直接实现ILifeSpanHandler接口添加窗口处理,但是在OnBeforePopup方法中,设置好窗口句柄后触发弹出新页时发现一个尴尬的问题:
问题
OnBeforePopup方法中调用SetAsPopup()方法,会导致浏览器首页卡死(仅在WPF中发现,Winform不会),新窗口页正常操作(后续窗口页中都不会有这个问题)。
如果不调用SetAsPopup()方法,会导致新窗口页的事件全部失效(处理器不会),比如TitleChanged事件在浏览器标题更改后,需要及时更新浏览器标题到控件上,这样就无法触发浏览器标题更改事件(TitleChanged)。
解决办法
既然调用SetAsPopup会卡死,那我们就不调用,但是不调用SetAsPopup会导致新打开的窗口页事件丢失,那就想办法手动实现这个方法的一部分功能(赋值事件、处理器等信息)。
SetAsPopup方法中最后有一个out IWebBrowser newBrowser 参数,这个参数作用是新打开窗口页的浏览器对象需不需要我们提供,一般设置这个参数为null,不需要我们提供。
如果不为null时,新窗口浏览器对象将使用newBrowser作为新窗口页的浏览器对象。
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess,
out IWebBrowser newBrowser) {
所以在方法中显示给newBrowser赋上值,(相当于实现一部分SetAsPopup方法工作...):
public class CefLifeSpanHandler : ILifeSpanHandler { //省略其他ILifeSpanHandler接口实现方法...
//构造函数传入窗口对象,方便控制窗口中的控件 MainWindow mainWindow; public CefLifeSpanHandler(MainWindow _mainWindow) { this.mainWindow = _mainWindow; } //浏览器新窗口弹出时调用方法 public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser) { //为新弹窗创建一个浏览器对象 ChromiumWebBrowser newChromeBrowser = new ChromiumWebBrowser(); //为新弹窗复制窗口处理 newBrowser.LifeSpanHandler = this; //省略赋值其他处理器... //赋值标题修改事件 newChromeBrowser.TitleChanged += mainWindow.Chrome_TitleChange; //省略赋值其他事件.... //留下创建的浏览器对象引用,windowList(List<ChromiumWebBrowser>)是在MainWindow下声明的变量,窗口关闭时要释放,不然退出程序会跨线程访问控件错误 mainWindow.windowList.Add(newChromeBrowser); //为浏览器赋值 newBrowser = newChromeBrowser; //.... return false; } }
到这里,在新窗口页打开时,即触发了标题修改事件,又没有导致浏览器首页卡死,但在关闭窗口时,会报跨线程访问错误,需要在窗口关闭时释放掉创建的窗口浏览器对象:
private void Window_Closed(object sender, EventArgs e) { //释放每一个chrome窗口资源 for (int i = 0; i < windowList.Count; i ++) { windowList[i].Dispatcher.Invoke(delegate { windowList[i].Dispose(); }); } }
到这里,基本上解决了阻止浏览器弹窗时调用 SetAsPopup 首页卡死问题。
如果本人有理解不对的地方,希望前辈们评论区指导,非常感谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!