public BrowserTabUserControl(ChromiumHostControl chromiumHostControl)
        {
            InitializeComponent();

            Browser = chromiumHostControl;

            browserPanel.Controls.Add(chromiumHostControl);

            chromiumHostControl.LoadingStateChanged         += OnBrowserLoadingStateChanged;
            chromiumHostControl.ConsoleMessage              += OnBrowserConsoleMessage;
            chromiumHostControl.TitleChanged                += OnBrowserTitleChanged;
            chromiumHostControl.AddressChanged              += OnBrowserAddressChanged;
            chromiumHostControl.StatusMessage               += OnBrowserStatusMessage;
            chromiumHostControl.IsBrowserInitializedChanged += OnIsBrowserInitializedChanged;
            chromiumHostControl.LoadError += OnLoadError;
        }
        public BrowserTabUserControl(Action <string, int?> openNewTab, string url, bool multiThreadedMessageLoopEnabled)
        {
            InitializeComponent();

            var browser = new ChromiumWebBrowser(url)
            {
                Dock = DockStyle.Fill
            };

            browserPanel.Controls.Add(browser);

            Browser = browser;

            browser.MenuHandler     = new MenuHandler();
            browser.RequestHandler  = new WinFormsRequestHandler(openNewTab);
            browser.JsDialogHandler = new JsDialogHandler();
            browser.DownloadHandler = new DownloadHandler();
            browser.AudioHandler    = new CefSharp.Handler.AudioHandler();
            browser.FrameHandler    = new CefSharp.Handler.FrameHandler();

            if (multiThreadedMessageLoopEnabled)
            {
                browser.KeyboardHandler = new KeyboardHandler();
            }

            //The CefSharp.WinForms.Handler.LifeSpanHandler implementation
            //allows for Popups to be hosted in Controls/Tabs
            //This example also demonstrates docking DevTools in a SplitPanel
            browser.LifeSpanHandler = CefSharp.WinForms.Handler.LifeSpanHandler
                                      .Create()
                                      .OnBeforePopupCreated((chromiumWebBrowser, b, frame, targetUrl, targetFrameName, targetDisposition, userGesture, browserSettings) =>
            {
                //Can cancel opening popup based on Url if required.
                if (targetUrl?.StartsWith(CefExample.BaseUrl + "/cancelme.html") == true)
                {
                    return(PopupCreation.Cancel);
                }

                return(PopupCreation.Continue);
            })
                                      .OnPopupCreated((ctrl, targetUrl) =>
            {
                //Don't try using ctrl.FindForm() here as
                //the control hasn't been attached to a parent yet.
                if (FindForm() is BrowserForm owner)
                {
                    owner.AddTab(ctrl, targetUrl);
                }
            })
                                      .OnPopupDestroyed((ctrl, popupBrowser) =>
            {
                //If we docked  DevTools (hosted it ourselves rather than the default popup)
                //Used when the BrowserTabUserControl.ShowDevToolsDocked method is called
                if (popupBrowser.MainFrame.Url.Equals("devtools://devtools/devtools_app.html"))
                {
                    //Dispose of the parent control we used to host DevTools, this will release the DevTools window handle
                    //and the ILifeSpanHandler.OnBeforeClose() will be call after.
                    ctrl.Dispose();
                }
                else
                {
                    //If browser is disposed or the handle has been released then we don't
                    //need to remove the tab in this example. The user likely used the
                    // File -> Close Tab menu option which also calls BrowserForm.RemoveTab
                    if (!ctrl.IsDisposed && ctrl.IsHandleCreated)
                    {
                        if (ctrl.FindForm() is BrowserForm owner)
                        {
                            owner.RemoveTab(ctrl);
                        }

                        ctrl.Dispose();
                    }
                }
            })
                                      .OnPopupBrowserCreated((ctrl, popupBrowser) =>
            {
                //The host control maybe null if the popup was hosted in a native Window e.g. Devtools by default
                if (ctrl == null)
                {
                    return;
                }

                //You can access all the core browser functionality via IBrowser
                //frames, browwser host, etc.
                var isPopup = popupBrowser.IsPopup;
            })
                                      .Build();

            browser.LoadingStateChanged         += OnBrowserLoadingStateChanged;
            browser.ConsoleMessage              += OnBrowserConsoleMessage;
            browser.TitleChanged                += OnBrowserTitleChanged;
            browser.AddressChanged              += OnBrowserAddressChanged;
            browser.StatusMessage               += OnBrowserStatusMessage;
            browser.IsBrowserInitializedChanged += OnIsBrowserInitializedChanged;
            browser.LoadError += OnLoadError;

#if NETCOREAPP
            browser.JavascriptObjectRepository.Register("boundAsync", new AsyncBoundObject(), options: BindingOptions.DefaultBinder);
#else
            browser.JavascriptObjectRepository.Register("bound", new BoundObject(), isAsync: false, options: BindingOptions.DefaultBinder);
            browser.JavascriptObjectRepository.Register("boundAsync", new AsyncBoundObject(), isAsync: true, options: BindingOptions.DefaultBinder);
#endif

            //If you call CefSharp.BindObjectAsync in javascript and pass in the name of an object which is not yet
            //bound, then ResolveObject will be called, you can then register it
            browser.JavascriptObjectRepository.ResolveObject += (sender, e) =>
            {
                var repo = e.ObjectRepository;
                if (e.ObjectName == "boundAsync2")
                {
#if NETCOREAPP
                    repo.Register("boundAsync2", new AsyncBoundObject(), options: BindingOptions.DefaultBinder);
#else
                    repo.Register("boundAsync2", new AsyncBoundObject(), isAsync: true, options: BindingOptions.DefaultBinder);
#endif
                }
            };

            browser.RenderProcessMessageHandler = new RenderProcessMessageHandler();
            browser.DisplayHandler = new WinFormsDisplayHandler();
            //browser.MouseDown += OnBrowserMouseClick;
            this.multiThreadedMessageLoopEnabled = multiThreadedMessageLoopEnabled;

            var eventObject = new ScriptedMethodsBoundObject();
            eventObject.EventArrived += OnJavascriptEventArrived;
            // Use the default of camelCaseJavascriptNames
            // .Net methods starting with a capitol will be translated to starting with a lower case letter when called from js
#if !NETCOREAPP
            browser.JavascriptObjectRepository.Register("boundEvent", eventObject, isAsync: false, options: BindingOptions.DefaultBinder);
#endif

            CefExample.RegisterTestResources(browser);

            var version = string.Format("Chromium: {0}, CEF: {1}, CefSharp: {2}", Cef.ChromiumVersion, Cef.CefVersion, Cef.CefSharpVersion);
            //Set label directly, don't use DisplayOutput as call would be a NOOP (no valid handle yet).
            outputLabel.Text = version;
        }