// Copyright © 2021 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.ComponentModel; using System.Drawing; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace CefSharp.WinForms.Host { /// /// Chromium Browser Host Control, used for hosting Popups in WinForms /// /// [Docking(DockingBehavior.AutoDock), ToolboxBitmap(typeof(ChromiumWebBrowser)), Designer(typeof(ChromiumWebBrowserDesigner))] public class ChromiumHostControl : ChromiumHostControlBase, IWinFormsChromiumWebBrowser { /// /// Get access to the core instance. /// Maybe null if the underlying CEF Browser has not yet been /// created or if this control has been disposed. Check /// before accessing. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(null)] public IBrowser BrowserCore { get; internal set; } /// /// Event handler that will get called when the resource load for a navigation fails or is canceled. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang.. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// public event EventHandler LoadError; /// /// Event handler that will get called when the browser begins loading a frame. Multiple frames may be loading at the same /// time. Sub-frames may start or continue loading after the main frame load has ended. This method may not be called for a /// particular frame if the load request for that frame fails. For notification of overall browser load status use /// OnLoadingStateChange instead. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang.. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// /// Whilst this may seem like a logical place to execute js, it's called before the DOM has been loaded, implement /// as it's called when the underlying V8Context is created /// public event EventHandler FrameLoadStart; /// /// Event handler that will get called when the browser is done loading a frame. Multiple frames may be loading at the same /// time. Sub-frames may start or continue loading after the main frame load has ended. This method will always be called /// for all frames irrespective of whether the request completes successfully. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang.. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// public event EventHandler FrameLoadEnd; /// /// Event handler that will get called when the Loading state has changed. /// This event will be fired twice. Once when loading is initiated either programmatically or /// by user action, and once when loading is terminated due to completion, cancellation of failure. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang.. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// public event EventHandler LoadingStateChanged; /// /// Event handler for receiving Javascript console messages being sent from web pages. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang.. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// (The exception to this is when you're running with settings.MultiThreadedMessageLoop = false, then they'll be the same thread). /// public event EventHandler ConsoleMessage; /// /// Event handler for changes to the status message. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// (The exception to this is when you're running with settings.MultiThreadedMessageLoop = false, then they'll be the same thread). /// public event EventHandler StatusMessage; /// /// Occurs when the browser address changed. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang.. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// public event EventHandler AddressChanged; /// /// Occurs when the browser title changed. /// It's important to note this event is fired on a CEF UI thread, which by default is not the same as your application UI /// thread. It is unwise to block on this thread for any length of time as your browser will become unresponsive and/or hang.. /// To access UI elements you'll need to Invoke/Dispatch onto the UI Thread. /// public event EventHandler TitleChanged; /// /// A flag that indicates whether the control is currently loading one or more web pages (true) or not (false). /// /// true if this instance is loading; otherwise, false. /// In the WPF control, this property is implemented as a Dependency Property and fully supports data /// binding. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(false)] public bool IsLoading { get; private set; } /// /// The address (URL) which the browser control is currently displaying. /// Will automatically be updated as the user navigates to another page (e.g. by clicking on a link). /// /// The address. /// In the WPF control, this property is implemented as a Dependency Property and fully supports data /// binding. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(null)] public string Address { get; private set; } /// /// A flag that indicates whether the state of the control currently supports the GoForward action (true) or not (false). /// /// true if this instance can go forward; otherwise, false. /// In the WPF control, this property is implemented as a Dependency Property and fully supports data /// binding. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(false)] public bool CanGoForward { get; private set; } /// /// A flag that indicates whether the state of the control current supports the GoBack action (true) or not (false). /// /// true if this instance can go back; otherwise, false. /// In the WPF control, this property is implemented as a Dependency Property and fully supports data /// binding. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(false)] public bool CanGoBack { get; private set; } /// /// A flag that indicates whether the WebBrowser is initialized (true) or not (false). /// /// true if this instance is browser initialized; otherwise, false. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(false)] public bool IsBrowserInitialized { get { return BrowserCore != null; } } /// /// Handles the event. /// /// The instance containing the event data. internal void OnFrameLoadStart(FrameLoadStartEventArgs args) { FrameLoadStart?.Invoke(this, args); } /// /// Handles the event. /// /// The instance containing the event data. internal void OnFrameLoadEnd(FrameLoadEndEventArgs args) { FrameLoadEnd?.Invoke(this, args); } /// /// Handles the event. /// /// The instance containing the event data. internal void OnConsoleMessage(ConsoleMessageEventArgs args) { ConsoleMessage?.Invoke(this, args); } /// /// Handles the event. /// /// The instance containing the event data. internal void OnStatusMessage(StatusMessageEventArgs args) { StatusMessage?.Invoke(this, args); } /// /// Handles the event. /// /// The instance containing the event data. internal void OnLoadError(LoadErrorEventArgs args) { LoadError?.Invoke(this, args); } /// /// Sets the loading state change. /// /// The instance containing the event data. internal void OnLoadingStateChange(LoadingStateChangedEventArgs args) { CanGoBack = args.CanGoBack; CanGoForward = args.CanGoForward; IsLoading = args.IsLoading; LoadingStateChanged?.Invoke(this, args); } /// /// Sets the title. /// /// The instance containing the event data. internal void OnTitleChanged(TitleChangedEventArgs args) { TitleChanged?.Invoke(this, args); } /// /// Sets the address. /// /// The instance containing the event data. internal void OnAddressChanged(AddressChangedEventArgs args) { Address = args.Address; AddressChanged?.Invoke(this, args); } /// /// Loads the specified in the Main Frame. /// /// The URL to be loaded. public void LoadUrl(string url) { if (IsDisposed) { return; } var browser = BrowserCore; if (browser == null || browser.IsDisposed) { return; } using (var frame = browser.MainFrame) { frame.LoadUrl(url); } } /// public Task LoadUrlAsync(string url) { //LoadUrlAsync is actually a static method so that CefSharp.Wpf.HwndHost can reuse the code return CefSharp.WebBrowserExtensions.LoadUrlAsync(this, url); } /// public Task WaitForNavigationAsync(TimeSpan? timeout = null, CancellationToken cancellationToken = default) { //WaitForNavigationAsync is actually a static method so that CefSharp.Wpf.HwndHost can reuse the code return CefSharp.WebBrowserExtensions.WaitForNavigationAsync(this, timeout, cancellationToken); } /// /// Returns the main (top-level) frame for the browser window. /// /// the main frame public IFrame GetMainFrame() { var browser = BrowserCore; if(browser == null) { throw new Exception(CefSharp.WebBrowserExtensions.BrowserNullExceptionString); } return browser.MainFrame; } /// protected override void Dispose(bool disposing) { if (disposing) { var browserCore = BrowserCore; AddressChanged = null; ConsoleMessage = null; FrameLoadEnd = null; FrameLoadStart = null; LoadError = null; LoadingStateChanged = null; StatusMessage = null; TitleChanged = null; BrowserCore = null; if (browserCore?.IsDisposed == false) { //Close the underlying CEF Browser browserCore?.GetHost()?.CloseBrowser(true); } } base.Dispose(disposing); } /// /// Gets the associated with /// a specific instance. /// /// browser /// returns the assocaited or null if Disposed or no host found. public static ChromiumHostControl FromBrowser(IBrowser browser) { return FromBrowser(browser); } } }