diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index f5edd04c4b..961e6e7a24 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -513,12 +513,24 @@ public Task ScreenshotAsync(bool ignoreExistingScreenshot = false, Popup /// public void Load(string url) { - Address = url; + if (IsDisposed) + { + return; + } - //Destroy the frame wrapper when we're done - using (var frame = this.GetMainFrame()) + //There's a small window here between CreateBrowser + //and OnAfterBrowserCreated where the Address prop + //will be updated, though LoadUrl won't be called. + if (IsBrowserInitialized) + { + using (var frame = this.GetMainFrame()) + { + frame.LoadUrl(url); + } + } + else { - frame.LoadUrl(url); + Address = url; } } diff --git a/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs b/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs index cecaa99ea3..82909b0de2 100644 --- a/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs +++ b/CefSharp.Test/Wpf/WpfBrowserBasicFacts.cs @@ -38,6 +38,43 @@ public async Task CanLoadGoogle() } } + [WpfFact] + public async Task CanCallLoadUrlAsyncImmediately() + { + using (var browser = new ChromiumWebBrowser(null, string.Empty, new Size(1024, 786))) + { + var response = await browser.LoadUrlAsync("www.google.com"); + + Assert.True(response.Success); + + var mainFrame = browser.GetMainFrame(); + Assert.True(mainFrame.IsValid); + Assert.Contains("www.google", mainFrame.Url); + + output.WriteLine("Url {0}", mainFrame.Url); + } + } + + [WpfFact] + public async Task CanCallLoadUrlImmediately() + { + using (var browser = new ChromiumWebBrowser()) + { + browser.Load("www.google.com"); + browser.CreateBrowser(null, new Size(1024, 786)); + + var response = await browser.LoadUrlAsync(); + + Assert.True(response.Success); + + var mainFrame = browser.GetMainFrame(); + Assert.True(mainFrame.IsValid); + Assert.Contains("www.google", mainFrame.Url); + + output.WriteLine("Url {0}", mainFrame.Url); + } + } + [WpfFact] public async Task CanSetRequestContext() { diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 3b9b8fe787..960a438fe6 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -449,6 +449,14 @@ private void InternalDispose(bool disposing) /// public void Load(string url) { + if (IsDisposed) + { + return; + } + + //There's a small window here between CreateBrowser + //and OnAfterBrowserCreated where the Address prop + //will be updated, though LoadUrl won't be called. if (IsBrowserInitialized) { using (var frame = this.GetMainFrame()) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index f7259ab501..50d27368a0 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -89,7 +89,7 @@ public partial class ChromiumWebBrowser : Control, IRenderWebBrowser, IWpfWebBro /// /// Initial address /// - private readonly string initialAddress; + private string initialAddress; /// /// Has the underlying Cef Browser been created (slightly different to initialized in that /// the browser is initialized in an async fashion) @@ -1794,8 +1794,9 @@ protected virtual bool CreateOffscreenBrowser(Size size) if (!webBrowserInternal.HasParent) { var windowInfo = CreateOffscreenBrowserWindowInfo(source == null ? IntPtr.Zero : source.Handle); - //Pass null in for Address and rely on Load being called in OnAfterBrowserCreated - //Workaround for issue https://github.com/cefsharp/CefSharp/issues/2300 + //If initialAddress is set then we use that value, later in OnAfterBrowserCreated then we will + //call Load(url) if initial address was empty. + //Issue https://github.com/cefsharp/CefSharp/issues/2300 managedCefBrowserAdapter.CreateBrowser(windowInfo, browserSettings, requestContext, address: initialAddress); //Dispose of BrowserSettings if we created it, if user created then they're responsible @@ -2417,21 +2418,41 @@ protected override AutomationPeer OnCreateAutomationPeer() /// public void Load(string url) { - if (!InternalIsBrowserInitialized()) + if(IsDisposed) { - throw new Exception("The browser has not been initialized. Load can only be called " + - "after the underlying CEF browser is initialized (CefLifeSpanHandler::OnAfterCreated)."); + return; } - // Added null check -> binding-triggered changes of Address will lead to a nullref after Dispose has been called - // or before OnApplyTemplate has been called - if (browser != null) + //If the browser is already initialized then we can call LoadUrl directly + if (InternalIsBrowserInitialized()) { - using (var frame = browser.MainFrame) + // Added null check -> binding-triggered changes of Address will lead to a nullref after Dispose has been called + // or before OnApplyTemplate has been called + if (browser != null) { - frame.LoadUrl(url); + using (var frame = browser.MainFrame) + { + frame.LoadUrl(url); + } } } + //If CreateBrowser was called and InternalIsBrowserInitialized() == false then we need to set the Address + //property so in OnAfterBrowserCreated the Url is loaded. If initialAddress was + //set then the Url set here will be ignored. If we called Load(url) then historically + //an aborted error would be raised as per https://github.com/cefsharp/CefSharp/issues/2300 + //So we ignore the call for now. + else if (browserCreated) + { + UiThreadRunAsync(() => + { + Address = url; + }); + } + //Before browser created, set the intialAddress + else + { + initialAddress = url; + } } /// diff --git a/CefSharp/IWebBrowser.cs b/CefSharp/IWebBrowser.cs index 77d7d67bd6..3ac4b1aa81 100644 --- a/CefSharp/IWebBrowser.cs +++ b/CefSharp/IWebBrowser.cs @@ -82,6 +82,7 @@ public interface IWebBrowser : IDisposable /// /// Loads the specified in the Main Frame. + /// If is true then the method call will be ignored. /// Same as calling /// /// The URL to be loaded.