WPF .NET中BeforeNavigate2未被触发的解决方法

5
我需要使用System.Windows.Controls.WebBrowser控件发送每个请求时都带有标头。使用C#和.Net,由于一个被描述在这里的错误,BeforeNavigate2事件不能被触发,而这个事件能够帮助我实现按引用参数调用,而在错误报告中描述的BeforeNavigate事件并不能帮助我,因为它的参数是只读的。 这里的解决方案难以或者不可能使用,因为我有很多对Controls Web Browser的引用需要解决,而这会导致在项目中遍历现有的接口和其他库。
就像描述中的解决方案一样,拥有一个可以外部设置的固定字符串就足够了,但我需要一个使用Controls Web Browser设置标头的解决方案。有没有一种解决方案可以满足我的要求,而不使用Forms?

Frame怎么样? - dovid
即使我使用一个框架,仍然需要在C#.net中使用WebBrowser控件,而BeforeNavigate2事件仍然不会触发,我仍然无法设置头文件。我不确定使用框架如何有所帮助。 - Andreas
请查看http://wpfbrowsersample.codeplex.com/,使用“Navigating”事件。我认为它在每次预加载时都会触发。 - dovid
我无法让浏览器工作,因为我既没有Visual Studio 11也没有.Net 4.5的访问权限(被困在10和.Net 4中)。此外,我已经查看了“导航”事件,因为那是我可以订阅并触发的事件,但我没有看到任何可能使用该事件编辑请求的当前标头的可能性。 - Andreas
1个回答

5
这里有另一种方法,它使用低级COM连接点容器接口直接附加到底层的DWebBrowserEvents2源接口。从这里获取完整的项目源代码。我没有VS2010,所以这是一个VS2012项目,但它针对.NET 4.0。如果你准备好尝试它,编译后的应用程序包含在Debug文件夹中。以下是相关的代码。这是一个快速的概念验证,可能仍然存在错误:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;

namespace WpfWebBrowserEvents
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += (s, e) =>
            {
                var sink = new WebBrowserEventSink();
                sink.Connect(this.webBrowser);

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

    /// <summary>
    /// Handling WebBrowser ActiveX events directly
    /// by Noseratio - https://dev59.com/RXrZa4cB1Zd3GeqP6b8V
    /// </summary>

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(SHDocVw.DWebBrowserEvents2))]
    public class WebBrowserEventSink : SHDocVw.DWebBrowserEvents2
    {
        System.Runtime.InteropServices.ComTypes.IConnectionPoint _sinkCP = null;
        int _sinkCookie = int.MaxValue;

        public void Connect(System.Windows.Controls.WebBrowser webBrowser)
        {
            if (_sinkCookie != int.MaxValue)
                throw new InvalidOperationException();

            var activeXInstance = webBrowser.GetType().InvokeMember("ActiveXInstance",
                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                null, webBrowser, new object[] { }) as SHDocVw.WebBrowser;

            var cpc = (System.Runtime.InteropServices.ComTypes.IConnectionPointContainer)activeXInstance;
            var guid = typeof(SHDocVw.DWebBrowserEvents2).GUID;
            System.Runtime.InteropServices.ComTypes.IConnectionPoint _sinkCP;
            cpc.FindConnectionPoint(ref guid, out _sinkCP);
            _sinkCP.Advise(this, out _sinkCookie);
        }

        public void Disconnect()
        {
            if (_sinkCookie == int.MaxValue)
                throw new InvalidOperationException();
            _sinkCP.Unadvise(_sinkCookie);
            _sinkCookie = int.MaxValue;
            _sinkCP = null;
        }

        #region SHDocVw.DWebBrowserEvents2

        public void StatusTextChange(string Text)
        {
        }

        public void ProgressChange(int Progress, int ProgressMax)
        {
        }

        public void CommandStateChange(int Command, bool Enable)
        {
        }

        public void DownloadBegin()
        {
        }

        public void DownloadComplete()
        {
        }

        public void TitleChange(string Text)
        {
        }

        public void PropertyChange(string szProperty)
        {
        }

        public void BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
        {
            MessageBox.Show("BeforeNavigate2: " + URL.ToString());
        }

        public void NewWindow2(ref object ppDisp, ref bool Cancel)
        {
        }

        public void NavigateComplete2(object pDisp, ref object URL)
        {
        }

        public void DocumentComplete(object pDisp, ref object URL)
        {
        }

        public void OnQuit()
        {
        }

        public void OnVisible(bool Visible)
        {
        }

        public void OnToolBar(bool ToolBar)
        {
        }

        public void OnMenuBar(bool MenuBar)
        {
        }

        public void OnStatusBar(bool StatusBar)
        {
        }

        public void OnFullScreen(bool FullScreen)
        {
        }

        public void OnTheaterMode(bool TheaterMode)
        {
        }

        public void WindowSetResizable(bool Resizable)
        {
        }

        public void WindowSetLeft(int Left)
        {
        }

        public void WindowSetTop(int Top)
        {
        }

        public void WindowSetWidth(int Width)
        {
        }

        public void WindowSetHeight(int Height)
        {
        }

        public void WindowClosing(bool IsChildWindow, ref bool Cancel)
        {
        }

        public void ClientToHostWindow(ref int CX, ref int CY)
        {
        }

        public void SetSecureLockIcon(int SecureLockIcon)
        {
        }

        public void FileDownload(bool ActiveDocument, ref bool Cancel)
        {
        }

        public void NavigateError(object pDisp, ref object URL, ref object Frame, ref object StatusCode, ref bool Cancel)
        {
        }

        public void PrintTemplateInstantiation(object pDisp)
        {
        }

        public void PrintTemplateTeardown(object pDisp)
        {
        }

        public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone)
        {
        }

        public void PrivacyImpactedStateChange(bool bImpacted)
        {
        }

        public void NewWindow3(ref object ppDisp, ref bool Cancel, uint dwFlags, string bstrUrlContext, string bstrUrl)
        {
        }

        public void SetPhishingFilterStatus(int PhishingFilterStatus)
        {
        }

        public void WindowStateChanged(uint dwWindowStateFlags, uint dwValidFlagsMask)
        {
        }

        public void NewProcess(int lCauseFlag, object pWB2, ref bool Cancel)
        {
        }

        public void ThirdPartyUrlBlocked(ref object URL, uint dwCount)
        {
        }

        public void RedirectXDomainBlocked(object pDisp, ref object StartURL, ref object RedirectURL, ref object Frame, ref object StatusCode)
        {
        }

        public void BeforeScriptExecute(object pDispWindow)
        {
        }

        public void WebWorkerStarted(uint dwUniqueID, string bstrWorkerLabel)
        {
        }

        public void WebWorkerFinsihed(uint dwUniqueID)
        {
        }

        #endregion
    }

}

1
乍一看,我觉得我可能已经尝试过类似的东西了。我会尝试并回复,但我不知道能否在周末之前完成。只是写这个告诉你我已经读过了。 - Andreas
显然,标题似乎是只读的,即使它们是按引用传递的参数。当我在“导航”中设置一个标题时,它会被发送出去。在BeforeNavigate2更改标题似乎不会更改要发送的标题。有取消请求并再次使用正确的标题进行导航的选项,但我想避免这种情况。有什么想法吗? - Andreas
1
@Andreas,因此,尽管通过ref传递了Headers参数,但在分配时被忽略了?如果是这样,我只能想到两种可能的选择,两者都相当复杂:1)实现一个进程内代理服务器并配置WebBrowser使用它(使用UrlMkSetSessionOption)。2)实现一个进程内可插拔协议处理程序来拦截和修改HTTP流量。 - noseratio - open to work
感谢那些回复... 对于选项1),我们已经使用了一个系统范围的代理,我无法更改(也不应该/不能在IE级别上更改)。对于选项2),请纠正我,但由于我们还使用https流量,拦截和更改它将是...“困难的”。此外,我向我的老板提出了选项2),但被否决了。我尝试了“取消导航并重新添加标头”的方法,但这导致了意想不到的后果,破坏了整个系统,我还没有完全分析它。 - Andreas
1
这太棒了。真的帮了我很多! - psulek
1
干得好。成功地实现了在顶级导航中可靠地启用/禁用加载进度动画的功能。 - bgx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接