从 WebView2 迁移至 DotNetBrowser:第一部分
本指南面向正在评估从 WebView2 迁移至 DotNetBrowser 的 .NET 开发者。这是由两部分组成的系列文章的第一部分。
本指南的每一节都侧重于嵌入 WebView2
控件的应用程序中常见的一个功能领域。
我们将提供现有代码的直接替换,重点介绍 DotNetBrowser 和 WebView2 之间的细微差别,并提供相关文档的实用链接。
本指南主要介绍如何迁移至 DotNetBrowser。如需了解为何要迁移,请查看 DotNetBrowser 与 WebView2 的对比文章。
安装依赖项
将 DotNetBrowser 添加到项目最简便的方式是通过 NuGet。安装与应用程序匹配的特定于 UI 的包,NuGet 将自动引入所需的 核心 API 包和平台 Chromium 二进制文件。
例如,以下是如何为在 Windows x64 上运行的 WPF 项目添加 DotNetBrowser:
-
DotNetBrowser.Wpf.x64
– WPF 集成。 -
(传递引用)
DotNetBrowser.Win-x64
– 核心 API。 -
(传递引用)
DotNetBrowser.Chromium.Win-x64
– 捆绑的 Chromium。
您可以在安装指南中查看适用于不同 UI 库和平台的完整 NuGet 包列表。
若不使用 NuGet,您可以将 DotNetBrowser 作为 DLL 文件或 VSIX 包添加到项目中。
初始化浏览器
初始化 WebView2 和 DotNetBrowser 在概念上是相似的。在基于 XAML 的库中,您需要在 XAML 中添加浏览器控件,然后在代码后台文件中初始化 Chromium engine。
MainWindow.xaml:
WebView2
<Window ...x:Class="WebView2Example.MainWindow"xmlns:local="clr-namespace:WebView2Example"Title="WebView2" Width="800" Height="600" Closed="Window_Closed"><Grid><Wpf:WebView2 Name="webView"/></Grid>
</Window>
DotNetBrowser
<Window ...x:Class="DotNetBrowserExample.MainWindow"xmlns:local="clr-namespace:DotNetBrowserExample"Title="DotNetBrowser" Width="800" Height="600" Closed="Window_Closed"><Grid><WPF:BrowserView Name="browserView"/></Grid>
</Window>
MainWindow.xaml.cs:
WebView2
public partial class MainWindow : Window
{private const string Url = "https://example.com/";public MainWindow(){InitializeComponent();InitializeWebViewAsync();}async void InitializeWebViewAsync(){await webView.EnsureCoreWebView2Async(null);webView.CoreWebView2.Navigate(Url);}private void Window_Closed(object sender, EventArgs e){webView.Dispose();}
}
DotNetBrowser
public partial class MainWindow : Window
{private const string Url = "https://example.com/";private readonly IBrowser browser;private readonly IEngine engine;public MainWindow(){IEngine engine = EngineFactory.Create(RenderingMode.HardwareAccelerated);browser = engine.CreateBrowser();InitializeComponent();browserView.InitializeFrom(browser);browser.Navigation.LoadUrl(Url);}private void Window_Closed(object sender, EventArgs e){engine?.Dispose();}
}
在 WebView2 中,Engine 基本是隐藏的。您可以在 XAML 中放置一个 WebView2
控件,并调用 EnsureCoreWebView2Async()
在后台启动运行时。初始化完成后,您可以使用 CoreWebView2
进行导航或与页面交互。
在 DotNetBrowser 中,Engine 是显式的。您可以创建一个 IEngine
对象,然后创建 IBrowser
,最后将浏览器连接到 BrowserView
UI 控件。
这种分离使您可以更好地控制浏览器生命周期、资源使用和会话隔离。您可以在一个应用程序中创建多个 Engine,并在每个 Engine 中创建多个 Browser。IBrowser
实例从一开始就功能齐全,它们可以在无头模式下工作。
关闭浏览器
WebView2 将 Edge 的生命周期与最后一个活跃控件绑定;一旦所有 WebView2 实例关闭,整个 Engine 就会退出。
DotNetBrowser 允许您关闭单个 Browser 或整个 Engine。请注意,Engine 的生命周期独立于单个 Browser:您始终需要显式关闭 IEngine
。
WebView2
// 关闭单个 WebView2 控件。
webView.Dispose();
// 一旦所有控件都关闭,Edge 进程就会退出。
DotNetBrowser
// 关闭单个 Browser。
browser.Dispose();
browser.Disposed += (sender, args) =>
{Console.WriteLine("The browser was closed!");
};// 关闭单个 Engine。它将自动关闭其中的所有 Browser。
//
// 它不会关闭其他 IEngine 实例。
engine.Dispose();
engine.Disposed += (sender, args) =>
{Console.WriteLine("The engine was closed!");
};
请注意,browser.Disposed
事件与 WebView2 的 WindowCloseRequested
事件不等效。后者仅在 JavaScript 在顶层视图上调用 window.close()
时才会引发。前者始终在 Browser 被处置时引发,无论处置方式如何。
导航
WebView2 和 DotNetBrowser 中的导航 API 基本等效:
WebView2
webView.CoreWebView2.Navigate("https://www.example.com");
webView.CoreWebView2.GoBack();
webView.CoreWebView2.GoForward();
webView.CoreWebView2.Reload();
webView.CoreWebView2.Stop();
bool canGoBack = webView.CoreWebView2.CanGoBack;
bool canGoForward = webView.CoreWebView2.CanGoForward;
DotNetBrowser
browser.Navigation.LoadUrl("https://example.com");
browser.Navigation.GoBack();
browser.Navigation.GoForward();
browser.Navigation.Reload();
browser.Navigation.Stop();
bool canGoBack = browser.Navigation.CanGoBack;
bool canGoForward = browser.Navigation.CanGoForward;
导航事件
本节介绍了 DotNetBrowser 中与 WebView2 导航事件最接近的等效项。在多个情况下,您需要组合多个事件或处理程序来完全复制 WebView2 语义。
将 NavigationStarting
替换为 NavigationStarted
以检测导航何时开始,并使用 StartNavigationHandler
取消导航。
WebView2
// 当 Browser 开始加载新页面时触发。
webView.CoreWebView2.NavigationStarting += (sender, args) =>
{Console.WriteLine("Navigation started.");// 取消导航。args.Cancel = true;
};
DotNetBrowser
// 当 Browser 开始加载新页面时触发。
browser.Navigation.NavigationStarted += (sender, args) =>
{Console.WriteLine("Navigation started.");
};// 取消导航。
browser.Navigation.StartNavigationHandler =new Handler<StartNavigationParameters, StartNavigationResponse>(p => StartNavigationResponse.Ignore());
将 ContentLoading
替换为 LoadStarted
以检测加载何时开始,并使用 FrameLoadFailed
来处理错误。
WebView2
webView.CoreWebView2.ContentLoading += (sender, args) =>
{Console.WriteLine("Loading started.");// 如果加载的内容是错误页面,则返回 True。bool isErrorPage = args.IsErrorPage;
};
DotNetBrowser
browser.Navigation.LoadStarted += (sender, args) =>
{ Console.WriteLine("Loading started.");
};// 内容加载失败时触发。
browser.Navigation.FrameLoadFailed += (sender, args) =>
{NetError errorCode = args.ErrorCode;
};
将 NavigationCompleted
事件替换为 NavigationFinished
事件:
WebView2
webView.CoreWebView2.NavigationCompleted += (sender, args) =>
{var webErrorStatus = args.WebErrorStatus;var isSuccess = args.IsSuccess;
};
DotNetBrowser
browser.Navigation.NavigationFinished += (sender, args) =>
{// 如果导航失败,则为错误代码。var errorCode = args.ErrorCode;// 指示导航是否导致错误页面。var isErrorPage = args.IsErrorPage;
};
将 FrameCreated
替换为同名事件 FrameCreated
。您可以使用此事件缓存 IFrame
实例。但是,JavaScript 上下文和 DOM 树可能无法立即使用。使用 FrameDocumentLoadFinished
和 InjectJsHandler
来确定页面何时准备好进行交互。
WebView2
webView.CoreWebView2.FrameCreated += (sender, args) =>
{CoreWebView2Frame frame = args.Frame;
};
DotNetBrowser
browser.FrameCreated += (sender, args) =>
{IFrame frame = args.Frame;
};
将 FrameNavigationCompleted
替换为 FrameLoadFinished
和 FrameLoadFailed
的组合:
WebView2
// 当子框架触发 body.onload 或加载因错误终止时触发。
webView.CoreWebView2.FrameNavigationCompleted += (sender, args) =>
{CoreWebView2WebErrorStatus errorStatus = args.WebErrorStatus;int httpStatusCode = args.HttpStatusCode;bool isSuccess = args.IsSuccess;
};
DotNetBrowser
browser.Navigation.FrameLoadFinished += (sender, args) =>
{IFrame frame = args.Frame;string validatedUrl = args.ValidatedUrl;
};browser.Navigation.FrameLoadFailed += (sender, args) =>
{IFrame frame = args.Frame;NetError errorCode = args.ErrorCode;string validatedUrl = args.ValidatedUrl;
};
SourceChanged
事件在 DotNetBrowser 中没有等效项。 最接近的替代方案是带有条件的 NavigationStarted
事件:
WebView2
webView.CoreWebView2.SourceChanged += (sender, args) =>
{var isNewDocument = args.IsNewDocument;
};
DotNetBrowser
browser.Navigation.NavigationStarted += (sender, args) =>
{if (args.IsMainFrame){var isNewDocument = !args.IsSameDocument;}
};
访问导航指南,查看 DotNetBrowser 中导航事件的完整列表。
使用 POST 数据加载
在 WebView2 和 DotNetBrowser 中,您都可以使用 POST 请求导航到 URL:
WebView2
var postData = "username=test&password=1234";
var byteArray = Encoding.UTF8.GetBytes(postData);
var stream = new MemoryStream(byteArray);var request = webView.CoreWebView2.Environment.CreateWebResourceRequest(uri: "https://example.com",Method: "POST",postData: stream,Headers: "Content-Type: application/x-www-form-urlencoded\r\n");
webView.CoreWebView2.NavigateWithWebResourceRequest(request);
DotNetBrowser
KeyValuePair<string, string>[] formData =
{new KeyValuePair<string, string>("username", "test"),new KeyValuePair<string, string>("password", "1234")
};
LoadUrlParameters request = new LoadUrlParameters("https://example.com")
{UploadData = new FormData(formData)
};
browser.Navigation.LoadUrl(request);
发送 POST 数据时,DotNetBrowser 会自动设置 Content-Type
和 Content-Length
标头。对于多部分表单,它还将包含表单边界以及每个部分的 Content-Disposition
和 Content-Type
。
您可以覆盖默认标头,并在 HttpHeaders 参数中添加更多标头。
JavaScript
两个库都允许您执行脚本、接收结果,并允许页面脚本调用 .NET 代码。差异在于类型和连接方式。
何时开始执行 JavaScript
Chromium 完成页面加载后,需要额外时间来创建 JavaScript 上下文和 DOM 树。只有在此步骤完成后,您才能成功执行 JavaScript。
将 WebView 的两个 DOMContentLoaded
事件替换为单个 FrameDocumentLoadFinished
事件,以确保框架已准备好执行 JavaScript:
WebView2
webView.CoreWebView2.DOMContentLoaded += (sender, args) =>
{Console.WriteLine("Ready to execute JS in the main frame.");
};webView.CoreWebView2.FrameCreated += (s, e) =>
{var frame = e.Frame;frame.DOMContentLoaded += (sender, args) =>{Console.WriteLine("Ready to execute JS in an iframe.");};
};
DotNetBrowser
browser.Navigation.FrameDocumentLoadFinished += (sender, args) =>
{if (args.Frame.IsMain){Console.WriteLine("准备在主框架中执行 JS。");}else{Console.WriteLine("准备在 iframe 中执行 JS。");}
};
如果您想在页面上的任何脚本运行之前执行 JavaScript,您很可能正在使用 AddScriptToExecuteOnDocumentCreatedAsync
方法。DotNetBrowser 中的替代方案是 InjectJsHandler
:
WebView2
webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("...");
DotNetBrowser
browser.InjectJsHandler = new Handler<InjectJsParameters>(args =>
{args.Frame.ExecuteJavaScript<IJsObject>("...");
});
从 .NET 调用 JavaScript
WebView2 始终返回 JSON 字符串。undefined
和无法序列化的对象等特殊值将作为字面字符串 "null"
返回。
DotNetBrowser 将 JavaScript 值转换为相应的 .NET 类型。基本值自动映射到本地 .NET 类型,而复杂值则包装为 IJsObject
、IJsArray
或 IJsFunction
:
WebView2
// 返回字符串 "4"。
string four = await webView.CoreWebView2.ExecuteScriptAsync("2 + 2");
// 返回字符串 "null",因为 `window` 无法序列化。
string window = await webView.CoreWebView2.ExecuteScriptAsync("window");
// 您也可以异步执行相同的操作:
var result = await webView.CoreWebView2.ExecuteScriptWithResultAsync("2 + 2");
string fourAsync = scriptResult.ResultAsJson;
DotNetBrowser
// 以双精度值返回数字。
double four = await browser.MainFrame.ExecuteJavaScript<double>("2 + 2");
// 返回函数式 IJsObject 包装器。
IJsObject window = await args.Frame.ExecuteJavaScript<IJsObject>("window");
访问 JavaScript 指南了解更多详情。
从 JavaScript 调用 .NET
WebView2 提供两种通信模式:通过 window.chrome.webview.postMessage()
传递消息,以及通过注入的 COM 可见宿主对象直接调用。
DotNetBrowser 使用直接调用,并允许您将任意 .NET 对象注入 JavaScript。无需 COM。
WebView2
window.chrome.webview.postMessage({action: "hello", name: "John"});
window.chrome.webview.hostObjects.bridge.SayHello("John");
DotNetBrowser
// 您可以模拟注入对象的相同路径:
window.chrome.webview.postMessage({action: "hello", name: "John"});
window.chrome.webview.hostObjects.bridge.SayHello("John");// 或者将 .NET 对象注入到任意位置:
window.postMessage({action: "hello", name: "John"});
window.myHostObjects.SayHello("John");
如果您使用的是 postMessage()
方法,则可以在 DotNetBrowser 中模拟它,并避免重写现有的 JavaScript 代码。但您需要将 WebMessageReceived
事件处理程序替换为一个对象:
WebView2
webView.CoreWebView2.WebMessageReceived += (s, e) =>
{var jsonString= e.WebMessageAsJson;Console.WriteLine($"{jsonString}");
};
DotNetBrowser
public class Bridge
{public void postMessage(Object message){// 注意,如果底层 JS 对象不是字符串,// 则 `message` 将不是字符串。Console.WriteLine($"{message}");}
}val bridge = new Bridge();
browser.InjectJsHandler = new Handler<InjectJsParameters>(args =>
{// 创建一个与 WebView2 中名称和路径相同的 JavaScript 对象。IJsObject webview = args.Frame.ExecuteJavaScript<IJsObject>("(window.chrome.webview = {})");// 创建 `postMessage` 属性并将其赋值给 .NET 方法。webview.Properties["postMessage"] = (Action<Object>) bridge.postMessage;
});
同样,您可以用任意 .NET 对象替换注入的 COM 对象:
WebView2
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Bridge
{public void SayHello(string name){MessageBox.Show($"Hello {name}!");}
}webView.CoreWebView2.AddHostObjectToScript("bridge", new Bridge());
DotNetBrowser
public class Bridge
{public void SayHello(string name){MessageBox.Show($"Hello {name}!");}
}browser.InjectJsHandler = new Handler<InjectJsParameters>(args =>
{// 创建一个与 WebView2 中名称和路径相同的 JavaScript 对象。IJsObject webview = args.Frame.ExecuteJavaScript<IJsObject>("(window.chrome.webview = {hostObjects: {}})");IJsObject hosts = webview.Properties["hostObjects"] as IJsObject; // 创建 `postMessage` 属性并将其赋值给 .NET 方法。hosts.Properties["bridge"] = new Bridge();
});
查看JavaScript 指南了解更多关于 .NET-JavaScript 桥接的信息。
拦截流量
在 WebView2 中,流量拦截分为两步。首先,注册过滤器来隔离特定请求,然后注册处理程序来处理这些请求:
WebView2
// 仅拦截图片资源的 HTTPS 请求。
webView.CoreWebView2.AddWebResourceRequestedFilter("https://*", CoreWebView2WebResourceContext.Image);webView.CoreWebView2.WebResourceRequested += (sender, args) =>
{if (...) {// 不处理此请求。return;}// 提供您自己的响应。var response = webView.CoreWebView2.Environment.CreateWebResourceResponse(...);args.Response = response;
};
默认情况下,这些过滤器适用于标准方案:http
、https
和 file
。如果您想拦截 custom-scheme://
的请求,则需要在初始化 Engine 时注册自定义方案:
WebView2
var schemes = new List<CoreWebView2CustomSchemeRegistration>()
{new CoreWebView2CustomSchemeRegistration("custom-scheme")
};
var options = new CoreWebView2EnvironmentOptions(null, null, null, false, schemes);
var env = await CoreWebView2Environment.CreateAsync(null, null, options);
await webView.EnsureCoreWebView2Async(env);// 现在,下面这个方法也能正常工作了:
webView.CoreWebView2.AddWebResourceRequestedFilter("custom-scheme://*", ...);
在 DotNetBrowser 中,无需预先过滤:每个请求都会触发相应协议的 InterceptRequestHandler
。你只需为需要拦截的协议分别注册处理程序:
DotNetBrowser
// 创建带有不同方案的请求处理程序的 Engine。
EngineOptions options = new EngineOptions.Builder
{Schemes ={{Scheme.Create("custom-scheme"), new CustomSchemeInterceptor()},{Scheme.Create("https"), new HttpsSchemeInterceptor()}}
}.Build();
var engine = EngineFactory.Create(options);
在此处理程序中,您可以让请求通过,或提供您自己的响应:
DotNetBrowser
class CustomSchemeInterceptor : IHandler<InterceptRequestParameters, InterceptRequestResponse>
{public InterceptRequestResponse Handle(InterceptRequestParameters p){string uri = p.UrlRequest.Url;UrlRequestJob urlRequestJob = null;if (p.UrlRequest.ResourceType == ResourceType.Image){// 提供您自己的自定义响应。urlRequestJob = p.Network.CreateUrlRequestJob(p.UrlRequest,new UrlRequestJobOptions{HttpStatusCode = HttpStatusCode.OK,Headers = new List<HttpHeader>{new HttpHeader("Content-Type", "text/plain"),}});byte[] body = loadImageFromDisk(p.UrlRequest.Url);urlRequestJob.Write(body);urlRequestJob.Complete();return InterceptRequestResponse.Intercept(urlRequestJob);}// 让其他请求通过。return InterceptRequestResponse.Proceed();}
}
请求拦截会产生性能开销。如果您只需要阻止不需要的请求,请使用更轻量级的 SendUrlRequestHandler
。
有关处理自定义方案的更多信息,请参阅拦截请求指南。
DOM
WebView2 不提供原生 DOM API;要与页面内容交互,只能执行 JavaScript 并解析返回的 JSON 结果。
DotNetBrowser 提供两种选项:您可以继续使用现有的 JavaScript 片段,或切换到类型化的 DOM API,该 API 将元素作为 .NET 对象公开。
WebView2 代码的直接替换代码看起来非常相似:
WebView2
string jsCode = "document.getElementById('username').value";
string username = await webView.CoreWebView2.ExecuteScriptAsync(jsCode);
DotNetBrowser
string jsCode = "document.getElementById('username').value";
string username = await browser.MainFrame.ExecuteJavaScript<string>(jsCode);
Alternatively, you can use the DotNetBrowser DOM API:
DotNetBrowser
// 重用现有的 JavaScript 选择器。
IElement element = await frame.ExecuteJavaScript<IElement>("document.getElementById('username')");
string username = (element as IInputElement).Value;// 或者使用 C# 选择器。
IDocument document = browser.MainFrame.Document;
IInputElement inputElement = document.GetElementById("username") as IInputElement;
string username = inputElement.Value;
为什么要使用 DOM API?它带来更友好的 IntelliSense、支持编译期重构,并提供强类型的 C# 体验。更多详情请参见 DOM 指南。
JavaScript 对话框
在 WebView2 中,您可以通过单个 ScriptDialogOpening
事件处理程序来处理所有 JavaScript 对话框。而在 DotNetBrowser 中,您需要为每种对话框类型分别设置独立的处理程序来替代这一方式。
WebView2
webView.CoreWebView2.ScriptDialogOpening += (sender, args) =>
{switch (args.Kind){case CoreWebView2ScriptDialogKind.Alert:Console.WriteLine("Alert dialog called.");break;case CoreWebView2ScriptDialogKind.Confirm:Console.WriteLine("Confirm dialog called.");args.Accept();break;case CoreWebView2ScriptDialogKind.Prompt:Console.WriteLine("Prompt dialog called.");args.ResultText = "some response";args.Accept();break;case CoreWebView2ScriptDialogKind.Beforeunload:Console.WriteLine("Beforeunload dialog called.");break;}
};
DotNetBrowser
var dialogs = browser.JsDialogs;
dialogs.AlertHandler = new Handler<AlertParameters>(p =>{Console.WriteLine("Alert dialog called.");});
dialogs.ConfirmHandler =new Handler<ConfirmParameters, ConfirmResponse>(p =>{Console.WriteLine("Confirm dialog called.");return ConfirmResponse.Ok();});
dialogs.PromptHandler =new Handler<PromptParameters, PromptResponse>(p =>{Console.WriteLine("Prompt dialog called.");return PromptResponse.SubmitText("some response");});
dialogs.BeforeUnloadHandler =new Handler<BeforeUnloadParameters, BeforeUnloadResponse>(p =>{Console.WriteLine("Beforeunload dialog called.");return BeforeUnloadResponse.Leave();});
如果您未设置处理程序,DotNetBrowser 会自动处理这些对话框。在 BrowserView
内部,它会使用应用程序的 UI 库来呈现对话框。在该上下文之外,它会跳过这些对话框,就像用户按下了“取消”按钮一样。
原生对话框
原生对话框由浏览器操作触发,例如文件上传按钮、PDF 保存提示、表单重新提交警告、外部应用启动触发器、<input type="color">
颜色选择器等。
在 WebView2 中,覆盖原生对话框需要采用一些临时性的变通方法。
而在 DotNetBrowser 中,您可以通过注册相应的事件处理程序来覆盖任意原生对话框:
-
OpenDirectoryHandler
用于“打开目录”对话框。 -
OpenFileHandler
用于“打开文件”对话框。 -
OpenMultipleFilesHandler
用于“打开多个文件”对话框。 -
OpenExternalAppHandler
用于浏览器尝试打开外部应用时触发的对话框。 -
RepostFormHandler
用于“确认表单重新提交”对话框。 -
SaveAsPdfHandler
用于在通过“打印预览”对话框将页面保存为 PDF 时选择文件。 -
SaveFileHandler
用于“保存文件”对话框。 -
SelectColorHandler
用于颜色选择器。
以下示例演示如何重写 OpenFileHandler
:
DotNetBrowser
browser.Dialogs.OpenFileHandler =new Handler<OpenFileParameters, OpenFileResponse>(parameters =>{var initialDirectory = parameters.InitialDirectory;var acceptableExtensions = parameters.AcceptableExtensions;return OpenFileResponse.SelectFile(...);});
更多示例请参考对话框指南。
弹出窗口
当 JavaScript 调用 window.open 或用户点击带有 target="_blank"
的链接时,浏览器会创建一个弹出窗口。
在 WebView2 中,弹出窗口的创建通过 NewWindowRequested
事件处理程序进行控制。您可以选择阻止弹出窗口、在当前 WebView2 控件中打开它,或允许其创建新窗口。
在 DotNetBrowser 中,弹出窗口的创建由 CreatePopupHandler
管理,您可以在其中决定是否允许或隐藏弹出窗口。如果您决定创建弹出窗口,DotNetBrowser 会实例化一个新的 IBrowser
并将其传递给 OpenPopupHandler
。然后,您可以使用 BrowserView
在 UI 中显示它,也可以在无头模式下运行它。
虽然不直接支持在同一个 BrowserView
控件中显示新浏览器,但可以通过以下方式模拟实现:
WebView2
webView.CoreWebView2.NewWindowRequested += (sender, e) =>
{if (openInSameBrowser){e.NewWindow = (CoreWebView2)sender;} else{// 阻止默认弹出行为。e.Handled = true;// 创建一个新的弹出窗口。CreatePopup(e);}
};private async void CreatePopup(CoreWebView2NewWindowRequestedEventArgs popup)
{//创建并配置新窗口。Window popupWindow = new Window();...// 创建一个新的 WebView2 控件来显示新的浏览器。WebView2 popupWebView = new WebView2();popupWindow.Content = popupWebView;popupWindow.Show();CoreWebView2Environment env = webView.CoreWebView2.Environment;await popupWebView.EnsureCoreWebView2Async(env);popupWebView.CoreWebView2.Navigate(popup.Uri);
}
DotNetBrowser
browser.CreatePopupHandler =new Handler<CreatePopupParameters, CreatePopupResponse>(p =>{if (openInSameBrowser){browser.Navigation.LoadUrl(p.TargetUrl);return CreatePopupResponse.Suppress();}return CreatePopupResponse.Create();});browser.OpenPopupHandler = new Handler<OpenPopupParameters>(p =>
{Action createPopupAction = () =>{CreatePopupWindow(p.PopupBrowser, p.Rectangle);};Dispatcher.BeginInvoke(createPopupAction);
});void CreatePopupWindow(IBrowser popupBrowser, Rectangle rect)
{BrowserView popupBrowserView = new BrowserView();popupBrowserView.InitializeFrom(popupBrowser);Dispatcher.UIThread.InvokeAsync(() =>{// Create and configure the new window. Window popupWindow = new Window();window.Content = browserView;popupWindow.Show();...});
}
如果未配置处理程序,DotNetBrowser 会自动管理弹出窗口。当位于 BrowserView
中时,它将使用应用程序的 UI 库打开一个新窗口,否则会隐藏对话框。
总结
在本指南中,我们介绍了如何创建和关闭浏览器、导航页面、与 JavaScript 交互、处理对话框和弹出窗口,以及拦截网络流量。
在即将发布的第二部分将继续讲解从 WebView2 迁移至 DotNetBrowser 的进阶主题,包括:
-
代理与身份验证流程
-
Cookie 和持久化存储
-
Profiles(配置文件)
-
上下文菜单
-
下载
-
打印 API
-
DevTools 集成
-
Chrome 扩展程序