2

WebBrowserプロジェクトでコントロールを使用しています。

そして、ユーザーが右クリックを押した場合に気付きました->更新

Navigating

LoadCompleted

呼び出されません。

もう1つの奇妙なことは、更新を押してWebブラウザの別のリンクをクリックしてLoadCompletedも呼び出されないことです。

これは、最初にページをナビゲートする方法です:

nrowser.Navigate(MYPAGE);

何が問題になる可能性がありますか?

で修正できますJavaScriptか?

4

2 に答える 2

3

更新を処理して、ナビゲーションと区別することができます。少し練習すれば、DOMdocument.onreadystatechangewindow.onunloadイベント、および基になる WebBrowser ActiveX コントロールNavigateComplete2とイベントを処理することで実行できDownloadBeginます。

NavigateComplete2WebBrowserページが更新されているときは 最上位オブジェクトに対して起動されませんが、ナビゲートするときは起動されます。DownloadBeginダウンロード、ナビゲーション、または更新アクティビティに対して、おそらく複数回、常に起動されます。window.onunloadナビゲーションまたは更新の前に発生し、ナビゲーションまたはdocument.onreadystatechange更新中に発生します。残りは、状態遷移を追跡する問題です。これは実際の例です (まだバグが含まれている可能性があります)。

C#:

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;

namespace WpfWebBrowser
{
    public partial class MainWindow : Window
    {
        bool navigating = false;
        bool loading = false;
        bool loaded = false;

        public MainWindow()
        {
            SetBrowserFeatureControl();
            InitializeComponent();

            this.Loaded += (s, e) =>
            {
                var axWebBrowser = (SHDocVw.WebBrowser)GetActiveXInstance(this.webBrowser);

                axWebBrowser.DownloadBegin += delegate
                {
                    HandleDownloadActivity();
                };

                axWebBrowser.NavigateComplete2 += delegate(object pDisp, ref object URL)
                {
                    // top frame?
                    if (Object.ReferenceEquals(axWebBrowser, pDisp))
                    {
                        this.navigating = true;
                        HandleDownloadActivity();
                    }
                };

                this.webBrowser.Navigate("http://example.com");
            };
        }

        // handler for document.readyState == "complete"
        void DomDocumetCompleteHandler(dynamic domDocument)
        {
            dynamic domWindow = domDocument.parentWindow;

            domWindow.attachEvent("onunload", new DomEventHandler(delegate
            {
                this.loaded = false;
                this.loading = false;
            }));

            var navigated = this.navigating;

            this.navigating = false;
            this.loaded = true;
            this.loading = false;

            MessageBox.Show(navigated ? "Navigated" : "Refreshed");
        }

        void HandleDownloadActivity()
        {
            dynamic domDocument = this.webBrowser.Document;
            if (domDocument == null)
                return;

            if (loading || loaded)
                return;

            this.loading = true;

            if (domDocument.readyState == "complete")
            {
                DomDocumetCompleteHandler(domDocument);
            }
            else
            {
                DomEventHandler handler = null;
                handler = new DomEventHandler(delegate
                {
                    if (domDocument.readyState == "complete")
                    {
                        domDocument.detachEvent("onreadystatechange", handler);
                        DomDocumetCompleteHandler(domDocument);
                    }
                });
                domDocument.attachEvent("onreadystatechange", handler);
            }
        }

        /// <summary>
        /// Get the underlying WebBrowser ActiveX object;
        /// this code depends on SHDocVw.dll COM interop assembly,
        /// generate SHDocVw.dll: "tlbimp.exe ieframe.dll",
        /// and add as a reference to the project
        /// </summary>
        static object GetActiveXInstance(WebBrowser wb)
        {
            return wb.GetType().InvokeMember("ActiveXInstance",
                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                null, wb, new object[] { }) as SHDocVw.WebBrowser;
        }

        /// <summary>
        /// EventHandler - adaptor to call C# back from JavaScript or DOM event handlers
        /// </summary>
        [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]
        public class DomEventHandler
        {
            [ComVisible(false)]
            public delegate void Callback(ref object result, object[] args);

            [ComVisible(false)]
            private Callback _callback;

            [DispId(0)]
            public object Method(params object[] args)
            {
                var result = Type.Missing; // Type.Missing is "undefined" in JavaScript
                _callback(ref result, args);
                return result;
            }

            public DomEventHandler(Callback callback)
            {
                _callback = callback;
            }
        }

        /// <summary>
        /// WebBrowser version control
        /// http://msdn.microsoft.com/en-us/library/ee330730(v=vs.85).aspx#browser_emulation
        /// </summary>
        void SetBrowserFeatureControl()
        {
            // http://msdn.microsoft.com/en-us/library/ee330720(v=vs.85).aspx

            // FeatureControl settings are per-process
            var fileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);

            // make the control is not running inside Visual Studio Designer
            if (String.Compare(fileName, "devenv.exe", true) == 0 || String.Compare(fileName, "XDesProc.exe", true) == 0)
                return;

            // Webpages containing standards-based !DOCTYPE directives are displayed in IE9/IE10 Standards mode.
            SetBrowserFeatureControlKey("FEATURE_BROWSER_EMULATION", fileName, 9000);
        }

        void SetBrowserFeatureControlKey(string feature, string appName, uint value)
        {
            using (var key = Registry.CurrentUser.CreateSubKey(
                String.Concat(@"Software\Microsoft\Internet Explorer\Main\FeatureControl\", feature),
                RegistryKeyPermissionCheck.ReadWriteSubTree))
            {
                key.SetValue(appName, (UInt32)value, RegistryValueKind.DWord);
            }
        }

    }
}

XAML:

<Window x:Class="WpfWebBrowser.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Width="800" Height="600">
        <WebBrowser Name="webBrowser"/>
</Window>
于 2013-10-15T12:04:09.777 に答える
0

Noseratio に感謝します。あなたが行ったことを、Web ブラウザーを渡してイベントを処理できるオブジェクトにラップしました。

public class WebBrowserHook
{
    private bool _isNavigating = false;
    private bool _isLoading = false;
    private bool _isLoaded = false;
    private WebBrowser _webBrowser = null;

    public WebBrowserHook(WebBrowser webBrowser)
    {
        _webBrowser = webBrowser;

        _webBrowser.Loaded += (s, e) =>
        {
            try
            {
                var axWebBrowser = (SHDocVw.WebBrowser)GetActiveXInstance(this._webBrowser);

                axWebBrowser.DownloadBegin += delegate
                {
                    HandleDownloadActivity();
                };

                axWebBrowser.NavigateComplete2 += delegate(object pDisp, ref object URL)
                {
                    // top frame?
                    if (Object.ReferenceEquals(axWebBrowser, pDisp))
                    {
                        this._isNavigating = true;
                        HandleDownloadActivity();
                    }
                };
            }
            catch (Exception ex)
            {
                AppLog.LogException(ex);
            }

        };

    }

    public event EventHandler Navigated;
    public event EventHandler Refreshed;

    public WebBrowser Browser
    {
        get{return _webBrowser;}
    }

    // handler for document.readyState == "complete"
    private void DomDocumentCompleteHandler(mshtml.HTMLDocument domDocument)
    {
        try
        {
            mshtml.HTMLWindow2 domWindow = (mshtml.HTMLWindow2)domDocument.parentWindow;

            domWindow.attachEvent("onunload", new DomEventHandler(delegate
            {
                this._isLoaded = false;
                this._isLoading = false;
            }));

            var navigated = this._isNavigating;

            this._isNavigating = false;
            this._isLoaded = true;
            this._isLoading = false;

            if (navigated)
            {
                if (Navigated != null)
                    Navigated(this, new EventArgs());
            }
            else
            {
                if (Refreshed != null)
                    Refreshed(this, new EventArgs());
            }
        }
        catch (Exception ex)
        {
            AppLog.LogException(ex);
        }
    }

    private void HandleDownloadActivity()
    {
        try
        {
            mshtml.HTMLDocument domDocument = (mshtml.HTMLDocument)this._webBrowser.Document;
            if (domDocument == null)
                return;

            if (_isLoading || _isLoaded)
                return;

            this._isLoading = true;

            if (domDocument.readyState == "complete")
            {
                DomDocumentCompleteHandler(domDocument);
            }
            else
            {
                DomEventHandler handler = null;
                handler = new DomEventHandler(delegate
                {
                    if (domDocument.readyState == "complete")
                    {
                        domDocument.detachEvent("onreadystatechange", handler);
                        DomDocumentCompleteHandler(domDocument);
                    }
                });
                domDocument.attachEvent("onreadystatechange", handler);
            }
        }
        catch (Exception ex)
        {
            AppLog.LogException(ex);
        }
    }

    /// <summary>
    /// Get the underlying WebBrowser ActiveX object;
    /// this code depends on SHDocVw.dll COM interop assembly,
    /// generate SHDocVw.dll: "tlbimp.exe ieframe.dll",
    /// and add as a reference to the project
    /// </summary>
    private static object GetActiveXInstance(WebBrowser wb)
    {
        return wb.GetType().InvokeMember("ActiveXInstance",
            BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
            null, wb, new object[] { }) as SHDocVw.WebBrowser;
    }

    /// <summary>
    /// EventHandler - adaptor to call C# back from JavaScript or DOM event handlers
    /// </summary>
    [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]
    public class DomEventHandler
    {
        [ComVisible(false)]
        public delegate void Callback(ref object result, object[] args);

        [ComVisible(false)]
        private Callback _callback;

        [DispId(0)]
        public object Method(params object[] args)
        {
            var result = Type.Missing; // Type.Missing is "undefined" in JavaScript
            _callback(ref result, args);
            return result;
        }

        public DomEventHandler(Callback callback)
        {
            _callback = callback;
        }
    }
}
于 2013-11-20T19:02:06.153 に答える