{"id":2687,"date":"2022-08-30T15:26:56","date_gmt":"2022-08-30T15:26:56","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/02\/06\/wpf-webbrowser-refresh-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:26:56","modified_gmt":"2022-08-30T15:26:56","slug":"wpf-webbrowser-refresh-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/wpf-webbrowser-refresh-collection-of-common-programming-errors\/","title":{"rendered":"Wpf WebBrowser Refresh-Collection of common programming errors"},"content":{"rendered":"<p>You can handle a refresh and differentiate it from navigation. With a little exercise, it can be done by handling DOM <code>document.onreadystatechange<\/code> and <code>window.onunload<\/code> events, as well as the underlying WebBrowser ActiveX control&#8217;s <code>NavigateComplete2<\/code> and <code>DownloadBegin<\/code> events.<\/p>\n<p><code>NavigateComplete2<\/code> doesn&#8217;t get fired for the top <code>WebBrowser<\/code> object when the page is being refreshed, but it does when navigating. <code>DownloadBegin<\/code> always gets fired, for any download, navigation or refresh activity, possibly multiple times. <code>window.onunload<\/code> gets fired before navigation or refresh, and <code>document.onreadystatechange<\/code> gets fired during navigation or refresh. The rest is the matter of tracking the state transitions. Here is a working example (which still may contain bugs).<\/p>\n<p><strong>C#:<\/strong><\/p>\n<pre><code>using Microsoft.Win32;\nusing System;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace WpfWebBrowser\n{\n    public partial class MainWindow : Window\n    {\n        bool navigating = false;\n        bool loading = false;\n        bool loaded = false;\n\n        public MainWindow()\n        {\n            SetBrowserFeatureControl();\n            InitializeComponent();\n\n            this.Loaded += (s, e) =&gt;\n            {\n                var axWebBrowser = (SHDocVw.WebBrowser)GetActiveXInstance(this.webBrowser);\n\n                axWebBrowser.DownloadBegin += delegate\n                {\n                    HandleDownloadActivity();\n                };\n\n                axWebBrowser.NavigateComplete2 += delegate(object pDisp, ref object URL)\n                {\n                    \/\/ top frame?\n                    if (Object.ReferenceEquals(axWebBrowser, pDisp))\n                    {\n                        this.navigating = true;\n                        HandleDownloadActivity();\n                    }\n                };\n\n                this.webBrowser.Navigate(\"http:\/\/example.com\");\n            };\n        }\n\n        \/\/ handler for document.readyState == \"complete\"\n        void DomDocumetCompleteHandler(dynamic domDocument)\n        {\n            dynamic domWindow = domDocument.parentWindow;\n\n            domWindow.attachEvent(\"onunload\", new DomEventHandler(delegate\n            {\n                this.loaded = false;\n                this.loading = false;\n            }));\n\n            var navigated = this.navigating;\n\n            this.navigating = false;\n            this.loaded = true;\n            this.loading = false;\n\n            MessageBox.Show(navigated ? \"Navigated\" : \"Refreshed\");\n        }\n\n        void HandleDownloadActivity()\n        {\n            dynamic domDocument = this.webBrowser.Document;\n            if (domDocument == null)\n                return;\n\n            if (loading || loaded)\n                return;\n\n            this.loading = true;\n\n            if (domDocument.readyState == \"complete\")\n            {\n                DomDocumetCompleteHandler(domDocument);\n            }\n            else\n            {\n                DomEventHandler handler = null;\n                handler = new DomEventHandler(delegate\n                {\n                    if (domDocument.readyState == \"complete\")\n                    {\n                        domDocument.detachEvent(\"onreadystatechange\", handler);\n                        DomDocumetCompleteHandler(domDocument);\n                    }\n                });\n                domDocument.attachEvent(\"onreadystatechange\", handler);\n            }\n        }\n\n        \/\/\/ \n        \/\/\/ Get the underlying WebBrowser ActiveX object;\n        \/\/\/ this code depends on SHDocVw.dll COM interop assembly,\n        \/\/\/ generate SHDocVw.dll: \"tlbimp.exe ieframe.dll\",\n        \/\/\/ and add as a reference to the project\n        \/\/\/ \n        static object GetActiveXInstance(WebBrowser wb)\n        {\n            return wb.GetType().InvokeMember(\"ActiveXInstance\",\n                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,\n                null, wb, new object[] { }) as SHDocVw.WebBrowser;\n        }\n\n        \/\/\/ \n        \/\/\/ EventHandler - adaptor to call C# back from JavaScript or DOM event handlers\n        \/\/\/ \n        [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]\n        public class DomEventHandler\n        {\n            [ComVisible(false)]\n            public delegate void Callback(ref object result, object[] args);\n\n            [ComVisible(false)]\n            private Callback _callback;\n\n            [DispId(0)]\n            public object Method(params object[] args)\n            {\n                var result = Type.Missing; \/\/ Type.Missing is \"undefined\" in JavaScript\n                _callback(ref result, args);\n                return result;\n            }\n\n            public DomEventHandler(Callback callback)\n            {\n                _callback = callback;\n            }\n        }\n\n        \/\/\/ \n        \/\/\/ WebBrowser version control\n        \/\/\/ http:\/\/msdn.microsoft.com\/en-us\/library\/ee330730(v=vs.85).aspx#browser_emulation\n        \/\/\/ \n        void SetBrowserFeatureControl()\n        {\n            \/\/ http:\/\/msdn.microsoft.com\/en-us\/library\/ee330720(v=vs.85).aspx\n\n            \/\/ FeatureControl settings are per-process\n            var fileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);\n\n            \/\/ make the control is not running inside Visual Studio Designer\n            if (String.Compare(fileName, \"devenv.exe\", true) == 0 || String.Compare(fileName, \"XDesProc.exe\", true) == 0)\n                return;\n\n            \/\/ Webpages containing standards-based !DOCTYPE directives are displayed in IE9\/IE10 Standards mode.\n            SetBrowserFeatureControlKey(\"FEATURE_BROWSER_EMULATION\", fileName, 9000);\n        }\n\n        void SetBrowserFeatureControlKey(string feature, string appName, uint value)\n        {\n            using (var key = Registry.CurrentUser.CreateSubKey(\n                String.Concat(@\"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\\", feature),\n                RegistryKeyPermissionCheck.ReadWriteSubTree))\n            {\n                key.SetValue(appName, (UInt32)value, RegistryValueKind.DWord);\n            }\n        }\n\n    }\n}\n<\/code><\/pre>\n<p><strong>XAML:<\/strong><\/p>\n<pre><code>\n        \n\n<\/code><\/pre>\n<p id=\"rop\"><small>Originally posted 2014-02-06 03:57:08. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>You can handle a refresh and differentiate it from navigation. With a little exercise, it can be done by handling DOM document.onreadystatechange and window.onunload events, as well as the underlying WebBrowser ActiveX control&#8217;s NavigateComplete2 and DownloadBegin events. NavigateComplete2 doesn&#8217;t get fired for the top WebBrowser object when the page is being refreshed, but it does [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2687","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/2687","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=2687"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/2687\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=2687"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=2687"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=2687"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}