当前位置: 首页 > news >正文

从 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 树可能无法立即使用。使用 FrameDocumentLoadFinishedInjectJsHandler 来确定页面何时准备好进行交互。

WebView2

webView.CoreWebView2.FrameCreated += (sender, args) =>
{CoreWebView2Frame frame = args.Frame;
};

DotNetBrowser

browser.FrameCreated += (sender, args) =>
{IFrame frame = args.Frame;
};

FrameNavigationCompleted 替换为 FrameLoadFinishedFrameLoadFailed 的组合:

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-TypeContent-Length 标头。对于多部分表单,它还将包含表单边界以及每个部分的 Content-DispositionContent-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 类型,而复杂值则包装为 IJsObjectIJsArrayIJsFunction

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;
};

默认情况下,这些过滤器适用于标准方案:httphttpsfile。如果您想拦截 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 扩展程序

http://www.dtcms.com/a/326603.html

相关文章:

  • android 换肤框架详解2-LayoutInflater源码解析
  • 《零基础入门AI:深度学习基础核心概念解析(从激活函数到反向传播)》
  • 大模型提示词工程实践:提示词工程实践-引导大模型完成任务
  • 直播美颜SDK架构设计指南:美白滤镜的高效实现与跨平台适配
  • MySQL 基本语法
  • 【网络基础】深入理解 TCP/IP 协议体系
  • 秒懂边缘云|1分钟了解边缘安全加速 ESA
  • GCC C++实现Matlab矩阵计算和数学函数功能
  • 乡土诗性的多重奏鸣——儿歌《生我养我的小村庄》文学赏析
  • C5.3:发射极偏置和LED驱动电路
  • 26考研|西安电子科技大学优势学科、25考研复试线及就业质量分析报告
  • 力扣热题100-----322.零钱兑换
  • 事务的特性
  • 下一代防火墙组网方案
  • IoT/透过oc_lwm2m/boudica150 源码中的AT指令序列,分析NB-IoT接入华为云物联网平台IoTDA的工作机制
  • visual studio 2015 使用番茄助手(Visual Assist)给函数自动添加注释模板
  • WSL / Linux安装MySQL(以及注意事项)
  • 嵌入式学习的第四十八天-中断+OCP原则
  • Photoshop图层混合模式:实现图像元素透明度渐变过渡的终极指南
  • Effective C++ 条款36: 绝不重新定义继承而来的非虚函数
  • 数据结构:树与二叉树
  • ARM基础概念 day51
  • easyExcel嵌套子集合导出Excel
  • 2025第十六届蓝桥杯大赛青少组省赛C++真题(初级组和中级组)
  • MCU的设计原理
  • SNMP入门教程:Windows下编译
  • Linux811 YUM;SHELL:if else fi,for
  • 进程线程切换的区别
  • 【k近邻】 K-Nearest Neighbors算法k值的选择
  • 第4节 大模型推理内存与计算优化