diff --git a/CefSharp.Core/WebBrowserExtensionsEx.cs b/CefSharp.Core/WebBrowserExtensionsEx.cs index b88df16413..0c898f31fe 100644 --- a/CefSharp.Core/WebBrowserExtensionsEx.cs +++ b/CefSharp.Core/WebBrowserExtensionsEx.cs @@ -5,6 +5,7 @@ using CefSharp.Internals; using System; using System.IO; +using System.Threading; using System.Threading.Tasks; namespace CefSharp @@ -50,6 +51,106 @@ public static Task GetVisibleNavigationEntryAsync(this IWebBrow return tcs.Task; } + /// + /// See for details + /// + /// ChromiumWebBrowser instance (cannot be null) + /// See for details + public static async Task WaitForBrowserInitialLoadAsync(IWebBrowser chromiumWebBrowser) + { + if (chromiumWebBrowser.IsDisposed) + { + throw new ObjectDisposedException(nameof(chromiumWebBrowser)); + } + + //If the browser has already initialized then we + //should check if the page has already loaded + if (chromiumWebBrowser.IsBrowserInitialized) + { + var browser = chromiumWebBrowser.GetBrowser(); + + if (!browser.IsLoading) + { + var navEntry = await chromiumWebBrowser.GetVisibleNavigationEntryAsync().ConfigureAwait(false); + + int statusCode = navEntry?.HttpStatusCode ?? -1; + + //By default 0 is some sort of error, we map that to -1 + //so that it's clearer that something failed. + if (statusCode == 0) + { + statusCode = -1; + } + + return new LoadUrlAsyncResponse(CefErrorCode.None, statusCode); + } + } + + var tcs = new TaskCompletionSource(); + + EventHandler loadErrorHandler = null; + EventHandler loadingStateChangeHandler = null; + + loadErrorHandler = (sender, args) => + { + //Ignore Aborted + if (args.ErrorCode == CefErrorCode.Aborted) + { + return; + } + + //If LoadError was called then we'll remove both our handlers + //as we won't need to capture LoadingStateChanged, we know there + //was an error + chromiumWebBrowser.LoadError -= loadErrorHandler; + chromiumWebBrowser.LoadingStateChanged -= loadingStateChangeHandler; + + //Ensure our continuation is executed on the ThreadPool + //For the .Net Core implementation we could use + //TaskCreationOptions.RunContinuationsAsynchronously + tcs.TrySetResultAsync(new LoadUrlAsyncResponse(args.ErrorCode, -1)); + }; + + loadingStateChangeHandler = (sender, args) => + { + //Wait for IsLoading = false + if (!args.IsLoading) + { + //If LoadingStateChanged was called then we'll remove both our handlers + //as LoadError won't be called, our site has loaded with a valid HttpStatusCode + //HttpStatusCodes can still be for example 404, this is considered a successful request, + //the server responded, it just didn't have the page you were after. + chromiumWebBrowser.LoadError -= loadErrorHandler; + chromiumWebBrowser.LoadingStateChanged -= loadingStateChangeHandler; + + var host = args.Browser.GetHost(); + + var navEntry = host?.GetVisibleNavigationEntry(); + + int statusCode = navEntry?.HttpStatusCode ?? -1; + + //By default 0 is some sort of error, we map that to -1 + //so that it's clearer that something failed. + if (statusCode == 0) + { + statusCode = -1; + } + + //Ensure our continuation is executed on the ThreadPool + //For the .Net Core implementation we could use + //TaskCreationOptions.RunContinuationsAsynchronously + tcs.TrySetResultAsync(new LoadUrlAsyncResponse(CefErrorCode.None, statusCode)); + } + }; + + chromiumWebBrowser.LoadError += loadErrorHandler; + chromiumWebBrowser.LoadingStateChanged += loadingStateChangeHandler; + + var response = await tcs.Task.ConfigureAwait(false); + + return response; + } + /// /// Downloads the specified and calls /// when the download is complete. Makes a GET Request. diff --git a/CefSharp.Test/DevTools/DevToolsClientFacts.cs b/CefSharp.Test/DevTools/DevToolsClientFacts.cs index 1cce4032cc..121bfbc3d6 100644 --- a/CefSharp.Test/DevTools/DevToolsClientFacts.cs +++ b/CefSharp.Test/DevTools/DevToolsClientFacts.cs @@ -37,7 +37,7 @@ public async Task CanCaptureScreenshot() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { @@ -83,7 +83,7 @@ public async Task CanGetDevToolsProtocolVersion() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { @@ -104,7 +104,7 @@ public async Task CanEmulationCanEmulate() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { @@ -120,7 +120,7 @@ public async Task CanGetPageNavigationHistory() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { @@ -143,7 +143,7 @@ public async Task CanSetCookieForDomain(string name, string value, string domain { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { @@ -159,7 +159,7 @@ public async Task CanUseMultipleDevToolsClientInstancesPerBrowser() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { @@ -192,7 +192,7 @@ public async Task CanSetUserAgentOverride() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { @@ -309,7 +309,7 @@ public async Task ExecuteDevToolsMethodThrowsExceptionWithInvalidMethod() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { diff --git a/CefSharp.Test/JavascriptBinding/IntegrationTestFacts.cs b/CefSharp.Test/JavascriptBinding/IntegrationTestFacts.cs index 87753d95b3..c17d629d39 100644 --- a/CefSharp.Test/JavascriptBinding/IntegrationTestFacts.cs +++ b/CefSharp.Test/JavascriptBinding/IntegrationTestFacts.cs @@ -106,7 +106,7 @@ public async Task IsObjectCachedWithInvalidObjectNameReturnsFalse() { using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl)) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); //We'll execute twice using the different cased (camelcase naming and standard) var response = await browser.EvaluateScriptAsync("CefSharp.IsObjectCached('doesntexist')"); @@ -132,7 +132,7 @@ public async Task JsBindingGlobalObjectNameCustomValueExecuteIsObjectCachedSucce //To modify the settings we need to defer browser creation slightly browser.CreateBrowser(); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var result = await browser.EvaluateScriptAsync("bindingApiObject.isObjectCached('doesntexist') === false"); @@ -151,7 +151,7 @@ public async Task JsBindingGlobalApiDisabled() //To modify the settings we need to defer browser creation slightly browser.CreateBrowser(); - var loadResponse = await browser.LoadUrlAsync(); + var loadResponse = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(loadResponse.Success); @@ -177,7 +177,7 @@ public async Task JsBindingGlobalApiEnabled() //To modify the settings we need to defer browser creation slightly browser.CreateBrowser(); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var response1 = await browser.EvaluateScriptAsync("typeof window.cefSharp === 'undefined'"); var response2 = await browser.EvaluateScriptAsync("typeof window.CefSharp === 'undefined'"); @@ -197,7 +197,7 @@ public async Task JsBindingRenderProcessId(string script) { using (var browser = new ChromiumWebBrowser(CefExample.BindingApiCustomObjectNameTestUrl)) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var result = await browser.EvaluateScriptAsync(script); @@ -217,7 +217,7 @@ public async Task CanCallCefSharpBindObjectAsyncWithoutParams() { using (var browser = new ChromiumWebBrowser(CefExample.HelloWorldUrl)) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); //TODO: See if we can avoid GetAwaiter().GetResult() var evt = Assert.Raises( diff --git a/CefSharp.Test/OffScreen/OffScreenBrowserBasicFacts.cs b/CefSharp.Test/OffScreen/OffScreenBrowserBasicFacts.cs index ba9345dd5d..20f45f0029 100644 --- a/CefSharp.Test/OffScreen/OffScreenBrowserBasicFacts.cs +++ b/CefSharp.Test/OffScreen/OffScreenBrowserBasicFacts.cs @@ -48,7 +48,7 @@ public async Task CanLoadGoogle() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -66,7 +66,7 @@ public async Task CanLoadInvalidDomain() { using (var browser = new ChromiumWebBrowser("notfound.cefsharp.test")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -82,7 +82,7 @@ public async Task CanLoadExpiredBadSsl() { using (var browser = new ChromiumWebBrowser("https://expired.badssl.com/")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -141,7 +141,7 @@ public async Task CanLoadGoogleAndEvaluateScript() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -161,7 +161,7 @@ public async Task CanEvaluateScriptInParallel() { using (var browser = new ChromiumWebBrowser("www.google.com")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -195,7 +195,7 @@ public async Task CanEvaluateScriptAsyncReturnPartiallyEmptyArrays(string javasc { using (var browser = new ChromiumWebBrowser(CefExample.HelloWorldUrl)) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var result = await browser.EvaluateScriptAsync(javascript); @@ -224,7 +224,7 @@ public async Task CrossSiteNavigationJavascriptBinding() browser.JavascriptObjectRepository.Register("bound", boundObj, true); #endif - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -236,7 +236,7 @@ public async Task CrossSiteNavigationJavascriptBinding() boundObj.MethodCalled = false; browser.Load("https://www.google.com"); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); browser.GetMainFrame().ExecuteJavaScriptAsync(script); await Task.Delay(2000); Assert.True(boundObj.MethodCalled); @@ -268,7 +268,7 @@ public async Task JavascriptBindingMultipleObjects() #endif }; - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); browser.GetMainFrame().ExecuteJavaScriptAsync(script); await Task.Delay(2000); @@ -286,7 +286,7 @@ public async Task CanEvaluateScriptAsyncWithEncodedStringArguments() { using (var browser = new ChromiumWebBrowser("http://www.google.com")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -319,7 +319,7 @@ public async Task CanEvaluateScriptAsPromiseAsyncJavascriptBindingApiGlobalObjec browser.JavascriptObjectRepository.Settings.JavascriptBindingApiGlobalObjectName = rootObjName; browser.CreateBrowser(); - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -345,7 +345,7 @@ public async Task CanEvaluateScriptAsPromiseAsync(string script, bool success, s { using (var browser = new ChromiumWebBrowser("http://www.google.com")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -377,7 +377,7 @@ public async Task CanEvaluateScriptAsPromiseAsyncReturnObject(string script, boo { using (var browser = new ChromiumWebBrowser("http://www.google.com")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -406,7 +406,7 @@ public async Task CanMakeFrameUrlRequest() { using (var browser = new ChromiumWebBrowser("https://code.jquery.com/jquery-3.4.1.min.js")) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -444,7 +444,7 @@ public async Task CanDownloadUrlForFrame(string url) { using (var browser = new ChromiumWebBrowser(url)) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -490,7 +490,7 @@ public async Task CanDownloadFileToFolderWithoutAskingUser(string url) } }); - await chromiumWebBrowser.LoadUrlAsync(); + await chromiumWebBrowser.WaitForBrowserInitialLoadAsync(); chromiumWebBrowser.StartDownload(url); @@ -551,7 +551,7 @@ public async Task CanExecuteJavascriptInMainFrameAfterNavigatingToDifferentOrigi { using (var browser = new ChromiumWebBrowser(firstUrl)) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -575,7 +575,7 @@ public async Task CanLoadRequestWithPostData(string url) //To use LoadRequest we must first load a web page using (var browser = new ChromiumWebBrowser(new HtmlString("Testing"))) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -620,7 +620,7 @@ public async Task CanLoadHttpWebsiteUsingProxy() using (var browser = new ChromiumWebBrowser("http://cefsharp.github.io/", requestContext: requestContext)) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -656,7 +656,7 @@ public async Task CanLoadHttpWebsiteUsingSetProxyAsync() using (var browser = new ChromiumWebBrowser("http://cefsharp.github.io/", requestContext: requestContext)) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -708,7 +708,7 @@ await Cef.UIThreadTaskFactory.StartNew(delegate using (var browser = new ChromiumWebBrowser("http://cefsharp.github.io/", requestContext: requestContext)) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -720,6 +720,28 @@ await Cef.UIThreadTaskFactory.StartNew(delegate } } + [Fact] + public async Task CanWaitForBrowserInitialLoadAfterLoad() + { + using (var browser = new ChromiumWebBrowser("http://www.google.com")) + { + var response = await browser.WaitForBrowserInitialLoadAsync(); + + var mainFrame = browser.GetMainFrame(); + Assert.True(mainFrame.IsValid); + Assert.Contains("www.google.com", mainFrame.Url); + Assert.Equal(CefErrorCode.None, response.ErrorCode); + Assert.Equal(200, response.HttpStatusCode); + + output.WriteLine("Url {0}", mainFrame.Url); + + response = await browser.WaitForBrowserInitialLoadAsync(); + + Assert.Equal(CefErrorCode.None, response.ErrorCode); + Assert.Equal(200, response.HttpStatusCode); + } + } + #if DEBUG [Fact] public async Task CanLoadMultipleBrowserInstancesSequentially() @@ -728,7 +750,7 @@ public async Task CanLoadMultipleBrowserInstancesSequentially() { using (var browser = new ChromiumWebBrowser(new HtmlString("Testing"))) { - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); diff --git a/CefSharp.Test/PostMessage/IntegrationTestFacts.cs b/CefSharp.Test/PostMessage/IntegrationTestFacts.cs index 840984700f..7c38fb4bc8 100644 --- a/CefSharp.Test/PostMessage/IntegrationTestFacts.cs +++ b/CefSharp.Test/PostMessage/IntegrationTestFacts.cs @@ -51,7 +51,7 @@ public async Task JavascriptCustomEvent(string jsEventObject, string eventToRais //Page.AddScriptToEvaluateOnNewDocument (via DevTools) using (var browser = new ChromiumWebBrowser(new HtmlString("Initial Load"))) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); using (var devToolsClient = browser.GetDevToolsClient()) { diff --git a/CefSharp.Test/WinForms/WinFormsBrowserBasicFacts.cs b/CefSharp.Test/WinForms/WinFormsBrowserBasicFacts.cs index 0296e0b534..b67ed3e3e2 100644 --- a/CefSharp.Test/WinForms/WinFormsBrowserBasicFacts.cs +++ b/CefSharp.Test/WinForms/WinFormsBrowserBasicFacts.cs @@ -30,7 +30,7 @@ public async Task CanLoadGoogle() browser.Size = new System.Drawing.Size(1024, 768); browser.CreateControl(); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -52,7 +52,7 @@ public async Task CanSetBrowserSettingsDisableImageLoadingViaObjectFactory() browser.Size = new System.Drawing.Size(1024, 768); browser.CreateControl(); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -75,7 +75,7 @@ public async Task CanSetBrowserSettingsDisableImageLoading() browser.Size = new System.Drawing.Size(1024, 768); browser.CreateControl(); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -97,7 +97,7 @@ public async Task CanSetRequestContextViaRequestContextBuilder() browser.Size = new System.Drawing.Size(1024, 768); browser.CreateControl(); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -117,7 +117,7 @@ public async Task CanSetRequestContext() browser.Size = new System.Drawing.Size(1024, 768); browser.CreateControl(); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); diff --git a/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs b/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs index 82909b0de2..7affb3066f 100644 --- a/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs +++ b/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs @@ -28,7 +28,7 @@ public async Task CanLoadGoogle() { using (var browser = new ChromiumWebBrowser(null, "www.google.com", new Size(1024, 786))) { - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -63,7 +63,7 @@ public async Task CanCallLoadUrlImmediately() browser.Load("www.google.com"); browser.CreateBrowser(null, new Size(1024, 786)); - var response = await browser.LoadUrlAsync(); + var response = await browser.WaitForBrowserInitialLoadAsync(); Assert.True(response.Success); @@ -83,7 +83,7 @@ public async Task CanSetRequestContext() browser.RequestContext = new RequestContext(); browser.CreateBrowser(null, new Size(1024, 786)); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); @@ -102,7 +102,7 @@ public async Task CanSetRequestContextViaBuilder() browser.CreateBrowser(null, new Size(1024, 786)); - await browser.LoadUrlAsync(); + await browser.WaitForBrowserInitialLoadAsync(); var mainFrame = browser.GetMainFrame(); Assert.True(mainFrame.IsValid); diff --git a/CefSharp/IWebBrowser.cs b/CefSharp/IWebBrowser.cs index 3ac4b1aa81..105ba8e42a 100644 --- a/CefSharp/IWebBrowser.cs +++ b/CefSharp/IWebBrowser.cs @@ -111,6 +111,15 @@ public interface IWebBrowser : IDisposable /// Task LoadUrlAsync(string url = null, SynchronizationContext ctx = null); + /// + /// Wait for the Browser to finish Loading the initial web page + /// + /// + /// A that can be awaited which returns the HttpStatusCode and . + /// A HttpStatusCode equal to 200 and is considered a success. + /// + Task WaitForBrowserInitialLoadAsync(); + /// /// The javascript object repository, one repository per ChromiumWebBrowser instance. /// diff --git a/CefSharp/Internals/Partial/ChromiumWebBrowser.Partial.cs b/CefSharp/Internals/Partial/ChromiumWebBrowser.Partial.cs index 0bd3692738..99ad0c5a7a 100644 --- a/CefSharp/Internals/Partial/ChromiumWebBrowser.Partial.cs +++ b/CefSharp/Internals/Partial/ChromiumWebBrowser.Partial.cs @@ -327,14 +327,19 @@ public void LoadUrl(string url) } /// - public Task LoadUrlAsync(string url = null, SynchronizationContext ctx = null) + public Task LoadUrlAsync(string url, SynchronizationContext ctx = null) { //LoadUrlAsync is actually a static method so that CefSharp.Wpf.HwndHost can reuse the code - //It's not actually an extension method so we can have it included as part of the - //IWebBrowser interface return CefSharp.WebBrowserExtensions.LoadUrlAsync(this, url, ctx); } + /// + public Task WaitForBrowserInitialLoadAsync() + { + //WaitForBrowserLoadAsync is actually a static method so that CefSharp.Wpf.HwndHost can reuse the code + return CefSharp.WebBrowserExtensionsEx.WaitForBrowserInitialLoadAsync(this); + } + partial void OnAfterBrowserCreated(IBrowser browser); ///