FBro浏览器关闭操作
概述
FBro提供了CloseBrowser方法来安全地关闭浏览器实例。该方法支持强制关闭和优雅关闭两种模式,并可选择是否立即将浏览器对象设置为空,以便更好地进行内存管理和对象生命周期控制。
方法签名
csharp
/// <summary>
/// 关闭浏览器
/// Request that the browser close. The JavaScript 'onbeforeunload' event will be
/// fired. If |force_close| is false the event handler, if any, will be allowed to
/// prompt the user and the user can optionally cancel the close. If |force_close|
/// is true the prompt will not be displayed and the close will proceed. Results
/// in a call to CefLifeSpanHandler::DoClose() if the event handler allows the close
/// or if |force_close| is true.
/// </summary>
/// <param name="force_close">是否强制关闭浏览器,默认为false</param>
/// <param name="set_null">是否立即设置为空,默认为false</param>
void CloseBrowser(bool force_close = false, bool set_null = false);参数详解
force_close 参数
| 值 | 行为 | 适用场景 |
|---|---|---|
| false (默认) | 触发onbeforeunload事件,允许用户确认或取消关闭 | 用户主动关闭、需要保存数据的场景 |
| true | 强制关闭,不显示确认提示,直接执行关闭流程 | 程序退出、强制清理、异常处理 |
set_null 参数
| 值 | 行为 | 适用场景 |
|---|---|---|
| false (默认) | 等待浏览器关闭事件完成后再清理对象引用 | 普通关闭流程,需要处理关闭事件 |
| true | 立即将浏览器对象设置为空,便于数组管理和快速清理 | 批量管理、立即清理、数组元素删除 |
基础用法
1. 优雅关闭(推荐)
csharp
/// <summary>
/// 优雅关闭浏览器 - 允许用户确认
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <returns>是否成功发起关闭请求</returns>
public bool GracefulClose(IFBroSharpBrowser browser)
{
try
{
if (browser != null && browser.IsValid())
{
// 优雅关闭:允许触发onbeforeunload事件,用户可以取消
browser.CloseBrowser(false, false);
Console.WriteLine("浏览器关闭请求已发送,等待用户确认");
return true;
}
else
{
Console.WriteLine("浏览器实例无效,无法关闭");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"关闭浏览器失败: {ex.Message}");
return false;
}
}2. 强制关闭
csharp
/// <summary>
/// 强制关闭浏览器 - 不允许用户取消
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <returns>是否成功发起关闭请求</returns>
public bool ForceClose(IFBroSharpBrowser browser)
{
try
{
if (browser != null && browser.IsValid())
{
// 强制关闭:不触发确认对话框,直接关闭
browser.CloseBrowser(true, false);
Console.WriteLine("浏览器强制关闭请求已发送");
return true;
}
else
{
Console.WriteLine("浏览器实例无效,无法强制关闭");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"强制关闭浏览器失败: {ex.Message}");
return false;
}
}3. 立即清理模式
csharp
/// <summary>
/// 立即清理关闭 - 适用于批量管理
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <returns>是否成功</returns>
public bool ImmediateCleanupClose(IFBroSharpBrowser browser)
{
try
{
if (browser != null && browser.IsValid())
{
// 立即清理:强制关闭并立即设置为空
browser.CloseBrowser(true, true);
Console.WriteLine("浏览器已强制关闭并立即清理");
return true;
}
else
{
Console.WriteLine("浏览器实例无效");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"立即清理关闭失败: {ex.Message}");
return false;
}
}高级用法
浏览器管理器示例
csharp
/// <summary>
/// 浏览器管理器 - 演示不同关闭策略
/// </summary>
public class BrowserManager
{
private readonly List<IFBroSharpBrowser> _browsers = new List<IFBroSharpBrowser>();
private readonly Dictionary<IFBroSharpBrowser, DateTime> _creationTimes = new Dictionary<IFBroSharpBrowser, DateTime>();
/// <summary>
/// 添加浏览器到管理列表
/// </summary>
public void AddBrowser(IFBroSharpBrowser browser)
{
if (browser != null && browser.IsValid())
{
_browsers.Add(browser);
_creationTimes[browser] = DateTime.Now;
Console.WriteLine($"浏览器已添加到管理列表,当前总数: {_browsers.Count}");
}
}
/// <summary>
/// 优雅关闭指定浏览器
/// </summary>
public bool CloseSpecificBrowser(IFBroSharpBrowser browser, bool waitForConfirmation = true)
{
try
{
if (!_browsers.Contains(browser))
{
Console.WriteLine("指定的浏览器不在管理列表中");
return false;
}
if (waitForConfirmation)
{
// 优雅关闭,等待用户确认
browser.CloseBrowser(false, false);
Console.WriteLine("已发送关闭请求,等待用户确认");
}
else
{
// 强制关闭
browser.CloseBrowser(true, false);
Console.WriteLine("浏览器已强制关闭");
// 从管理列表中移除
RemoveBrowserFromList(browser);
}
return true;
}
catch (Exception ex)
{
Console.WriteLine($"关闭指定浏览器失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 批量关闭所有浏览器
/// </summary>
public int CloseAllBrowsers(bool forceClose = false, bool immediateCleanup = false)
{
int closedCount = 0;
var browsersToClose = new List<IFBroSharpBrowser>(_browsers);
foreach (var browser in browsersToClose)
{
try
{
if (browser != null && browser.IsValid())
{
browser.CloseBrowser(forceClose, immediateCleanup);
closedCount++;
if (immediateCleanup)
{
// 立即从列表中移除
RemoveBrowserFromList(browser);
}
Console.WriteLine($"浏览器关闭请求已发送 ({closedCount}/{browsersToClose.Count})");
}
}
catch (Exception ex)
{
Console.WriteLine($"批量关闭浏览器失败: {ex.Message}");
}
}
Console.WriteLine($"批量关闭完成,成功关闭 {closedCount} 个浏览器");
return closedCount;
}
/// <summary>
/// 关闭运行时间超过指定时长的浏览器
/// </summary>
public int CloseOldBrowsers(TimeSpan maxAge, bool forceClose = true)
{
int closedCount = 0;
var cutoffTime = DateTime.Now - maxAge;
var oldBrowsers = new List<IFBroSharpBrowser>();
// 找出需要关闭的旧浏览器
foreach (var kvp in _creationTimes)
{
if (kvp.Value < cutoffTime && _browsers.Contains(kvp.Key))
{
oldBrowsers.Add(kvp.Key);
}
}
// 关闭旧浏览器
foreach (var browser in oldBrowsers)
{
try
{
if (browser != null && browser.IsValid())
{
browser.CloseBrowser(forceClose, true); // 立即清理
RemoveBrowserFromList(browser);
closedCount++;
Console.WriteLine($"已关闭运行时间超过 {maxAge.TotalMinutes:F1} 分钟的浏览器");
}
}
catch (Exception ex)
{
Console.WriteLine($"关闭旧浏览器失败: {ex.Message}");
}
}
Console.WriteLine($"旧浏览器清理完成,关闭了 {closedCount} 个浏览器");
return closedCount;
}
/// <summary>
/// 应急关闭所有浏览器
/// </summary>
public void EmergencyShutdown()
{
Console.WriteLine("执行应急关闭程序...");
try
{
// 强制关闭所有浏览器,立即清理
CloseAllBrowsers(true, true);
// 清空管理列表
_browsers.Clear();
_creationTimes.Clear();
Console.WriteLine("应急关闭完成");
}
catch (Exception ex)
{
Console.WriteLine($"应急关闭失败: {ex.Message}");
}
}
/// <summary>
/// 从管理列表中移除浏览器
/// </summary>
private void RemoveBrowserFromList(IFBroSharpBrowser browser)
{
_browsers.Remove(browser);
_creationTimes.Remove(browser);
}
/// <summary>
/// 获取管理器状态
/// </summary>
public BrowserManagerStatus GetStatus()
{
var validBrowsers = _browsers.Count(b => b != null && b.IsValid());
return new BrowserManagerStatus
{
TotalBrowsers = _browsers.Count,
ValidBrowsers = validBrowsers,
InvalidBrowsers = _browsers.Count - validBrowsers,
OldestBrowserAge = _creationTimes.Count > 0 ? DateTime.Now - _creationTimes.Values.Min() : (TimeSpan?)null,
NewestBrowserAge = _creationTimes.Count > 0 ? DateTime.Now - _creationTimes.Values.Max() : (TimeSpan?)null
};
}
}
/// <summary>
/// 浏览器管理器状态信息
/// </summary>
public class BrowserManagerStatus
{
public int TotalBrowsers { get; set; }
public int ValidBrowsers { get; set; }
public int InvalidBrowsers { get; set; }
public TimeSpan? OldestBrowserAge { get; set; }
public TimeSpan? NewestBrowserAge { get; set; }
public override string ToString()
{
return $"总数: {TotalBrowsers}, 有效: {ValidBrowsers}, 无效: {InvalidBrowsers}";
}
}浏览器关闭事件处理
生命周期事件处理
csharp
/// <summary>
/// 浏览器生命周期事件处理器
/// </summary>
public class BrowserLifeSpanHandler : FBroSharpLifeSpanHandler
{
private readonly Action<IFBroSharpBrowser> _onBrowserClosed;
public BrowserLifeSpanHandler(Action<IFBroSharpBrowser> onBrowserClosed = null)
{
_onBrowserClosed = onBrowserClosed;
}
/// <summary>
/// 浏览器即将关闭事件
/// </summary>
public override bool DoClose(IFBroSharpBrowser browser)
{
try
{
Console.WriteLine("浏览器即将关闭,执行清理操作");
// 这里可以执行关闭前的清理工作
// 返回 false 允许关闭继续进行
// 返回 true 会阻止关闭(不推荐)
return false; // 允许关闭
}
catch (Exception ex)
{
Console.WriteLine($"DoClose事件处理失败: {ex.Message}");
return false; // 即使出错也允许关闭
}
}
/// <summary>
/// 浏览器已关闭事件
/// </summary>
public override void OnBeforeClose(IFBroSharpBrowser browser)
{
try
{
Console.WriteLine("浏览器已关闭,执行最终清理");
// 执行最终的清理工作
_onBrowserClosed?.Invoke(browser);
// 注意:根据FBro事件类传递机制,这里的browser参数只在方法作用域内有效
// 如果需要保存browser引用,应该在其他地方使用强拷贝
}
catch (Exception ex)
{
Console.WriteLine($"OnBeforeClose事件处理失败: {ex.Message}");
}
}
}关闭确认处理
csharp
/// <summary>
/// 关闭确认处理器
/// </summary>
public class BrowserCloseConfirmationHandler
{
/// <summary>
/// 处理关闭确认对话框
/// </summary>
public static bool HandleCloseConfirmation(IFBroSharpBrowser browser, string message = null)
{
try
{
// 注入JavaScript来处理onbeforeunload事件
string script = $@"
window.addEventListener('beforeunload', function(e) {{
var confirmationMessage = '{message ?? "确定要关闭浏览器吗?"}';
e.returnValue = confirmationMessage;
return confirmationMessage;
}});
";
var frame = browser.GetMainFrame();
if (frame != null && frame.IsValid())
{
frame.ExecuteJavaScript(script, "", 0);
Console.WriteLine("关闭确认处理器已设置");
return true;
}
else
{
Console.WriteLine("无法设置关闭确认处理器:主框架无效");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"设置关闭确认处理器失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 移除关闭确认
/// </summary>
public static bool RemoveCloseConfirmation(IFBroSharpBrowser browser)
{
try
{
string script = @"
window.onbeforeunload = null;
window.removeEventListener('beforeunload', arguments.callee);
";
var frame = browser.GetMainFrame();
if (frame != null && frame.IsValid())
{
frame.ExecuteJavaScript(script, "", 0);
Console.WriteLine("关闭确认已移除");
return true;
}
else
{
Console.WriteLine("无法移除关闭确认:主框架无效");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"移除关闭确认失败: {ex.Message}");
return false;
}
}
}使用场景和最佳实践
场景1:用户主动关闭
csharp
/// <summary>
/// 用户点击关闭按钮
/// </summary>
private void OnUserCloseRequest()
{
// 允许用户确认,保护未保存的数据
if (browser != null && browser.IsValid())
{
browser.CloseBrowser(false, false);
}
}场景2:程序退出时清理
csharp
/// <summary>
/// 应用程序退出时的清理
/// </summary>
private void OnApplicationExit()
{
if (browser != null && browser.IsValid())
{
// 强制关闭,不等待用户确认
browser.CloseBrowser(true, true);
}
}场景3:批量管理场景
csharp
/// <summary>
/// 清理浏览器数组
/// </summary>
private void CleanupBrowserArray(List<IFBroSharpBrowser> browsers)
{
for (int i = browsers.Count - 1; i >= 0; i--)
{
var browser = browsers[i];
if (browser != null && browser.IsValid())
{
// 立即清理模式,便于数组管理
browser.CloseBrowser(true, true);
browsers.RemoveAt(i); // 可以立即删除数组元素
}
}
}场景4:异常处理
csharp
/// <summary>
/// 异常情况下的强制清理
/// </summary>
private void HandleBrowserError(IFBroSharpBrowser browser)
{
try
{
if (browser != null)
{
// 异常情况强制关闭
browser.CloseBrowser(true, true);
}
}
catch (Exception ex)
{
Console.WriteLine($"异常处理中的浏览器关闭失败: {ex.Message}");
// 即使关闭失败也要继续其他清理工作
}
}参数组合使用指南
| force_close | set_null | 适用场景 | 行为描述 |
|---|---|---|---|
false | false | 用户主动关闭 | 显示确认对话框,等待事件完成后清理 |
true | false | 程序控制关闭 | 立即关闭,等待事件完成后清理 |
false | true | 需要确认的快速清理 | 显示确认对话框,立即设置对象为空 |
true | true | 强制立即清理 | 立即关闭并设置对象为空,适合批量操作 |
注意事项
1. 事件类传递机制
根据FBro的事件类传递机制,在事件处理器中接收到的浏览器参数只在方法作用域内有效:
csharp
public override void OnBeforeClose(IFBroSharpBrowser browser)
{
// ❌ 错误:直接保存参数引用
// this.savedBrowser = browser; // 会失效
// ✅ 正确:如果需要保存,应该在此之前使用强拷贝
// this.savedBrowser = new FBroSharpBrowser(browser);
// 在方法内直接使用是安全的
Console.WriteLine($"浏览器已关闭: {browser.GetIdentifier()}");
}2. 内存管理
- 使用
set_null = true时,浏览器对象会立即被设置为空 - 适合在数组或列表中快速移除元素
- 可以减少等待事件完成的时间
3. 线程安全
csharp
/// <summary>
/// 线程安全的浏览器关闭
/// </summary>
private readonly object _closeLock = new object();
public bool SafeClose(IFBroSharpBrowser browser, bool force = false)
{
lock (_closeLock)
{
try
{
if (browser != null && browser.IsValid())
{
browser.CloseBrowser(force, false);
return true;
}
return false;
}
catch (Exception ex)
{
Console.WriteLine($"线程安全关闭失败: {ex.Message}");
return false;
}
}
}4. 错误处理最佳实践
csharp
/// <summary>
/// 健壮的浏览器关闭方法
/// </summary>
public static bool RobustClose(IFBroSharpBrowser browser, bool force = false, bool immediate = false)
{
if (browser == null)
{
Console.WriteLine("浏览器实例为null,无需关闭");
return true;
}
try
{
// 检查浏览器是否仍然有效
if (!browser.IsValid())
{
Console.WriteLine("浏览器实例已无效,无需关闭");
return true;
}
// 执行关闭操作
browser.CloseBrowser(force, immediate);
string mode = force ? "强制" : "优雅";
string cleanup = immediate ? "立即清理" : "延迟清理";
Console.WriteLine($"浏览器关闭请求已发送 - {mode}关闭,{cleanup}");
return true;
}
catch (ObjectDisposedException)
{
Console.WriteLine("浏览器对象已被释放");
return true; // 对象已释放视为成功
}
catch (Exception ex)
{
Console.WriteLine($"关闭浏览器时发生错误: {ex.Message}");
return false;
}
}通过这些方法和最佳实践,您可以在各种场景下安全、有效地关闭FBro浏览器实例,确保资源得到正确管理和清理。
browser.CloseBrowser(false, false);