如何在 WPF WebBrowser 中使用“后退”和“前进”导航按钮事件?

Posted

技术标签:

【中文标题】如何在 WPF WebBrowser 中使用“后退”和“前进”导航按钮事件?【英文标题】:How to use 'Back' & 'Forward' navigation button events in WPF WebBrowser? 【发布时间】:2011-09-16 07:42:21 【问题描述】:

WPF 中的WebBrowser 控件继承自UIElement,但我们无法在UIElement 事件中注册事件处理程序。为什么? WPF WebBrowser Mouse Events not working as expected有回答,但还是看不懂。

无论如何,将处理程序连接到WebBrowser 的文档提供的事件可以捕获大多数鼠标事件,但不能使用“后退”和“前进”导航按钮事件。由于Internet Explorer可以做到这一点,我认为这是可能的。有没有办法解决这个问题?

更新: 在这个问题中,'Back' & 'Forward' navigation buttonsmean XButton1 和 XButton2 在 5 键鼠标系统中。

UPDATE2:我用 Navid Rahmani 的回答解决了这个问题。我认为有人会需要这个答案,所以我附上主要部分。如果发现任何问题或更合理的解决方案,请告诉我。

    //This code assumes the `WebBrowser` field named _webBrowser is already initiated.
    //For the detail out of this code, please refer to the Navid Rahmani's answer.

    private bool _isMouseOver;
    private htmlDocumentEvents2_Event _docEvent;    

    public ctor()
    
        _webBrowser.LoadCompleted += _webBrowser_LoadCompleted;
    

    private void _webBrowser_LoadCompleted(object sender, NavigationEventArgs e)
    
        if (_docEvent != null)
        
            _docEvent.onmouseover -= _docEvent_onmouseover;
            _docEvent.onmouseout -= _docEvent_onmouseout;
        
        if (_webBrowser.Document != null)
        
            _docEvent = (HTMLDocumentEvents2_Event)_webBrowser.Document;
            _docEvent.onmouseover += _docEvent_onmouseover;
            _docEvent.onmouseout += _docEvent_onmouseout;
        
    

    void _docEvent_onmouseout(IHTMLEventObj pEvtObj)
    
        _isMouseOver = false;
    

    void _docEvent_onmouseover(IHTMLEventObj pEvtObj)
    
        _isMouseOver = true;
    


    private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    
        if (_isMouseOver)
        
            if (nCode >= 0 && (MouseMessages)wParam == MouseMessages.XBUTTON)
            
                var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct));
                if (hookStruct.mouseData == 0x10000)
                
                    //do something when XButto1 clicked
                
                else if (hookStruct.mouseData == 0x20000)
                
                    //do something when XButto2 clicked
                
            
        
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    


    private enum MouseMessages
    
        //WM_LBUTTONDOWN = 0x00A1,
        //WM_LBUTTONUP = 0x0202,
        //WM_MOUSEMOVE = 0x0200,
        //WM_MOUSEWHEEL = 0x020A,
        //WM_RBUTTONDOWN = 0x0204,
        //WM_RBUTTONUP = 0x0205,
        XBUTTON = 0x020B,
    

【问题讨论】:

没问题。这是通过您的努力解决的。 【参考方案1】:

WebBrowser 控件实际上只是 Trident COM 对象的薄包装器。它不像其他内置控件那样是“纯 WPF”……所以很多正常的东西都不能用它。要回答您的问题,您可以获得的最接近的方法是连接到 Navigating 事件。这不会告诉您用户是在尝试前进还是后退或其他地方,但它会给您 URL 和设置 e.Cancel = true 以停止导航的机会(通常随后调用 Navigate(url) 进行其他地方的用户)。

【讨论】:

首先,感谢您的回答。但是,无论方向如何,我都无法使用鼠标XButton click 为WebBrowser 的导航事件注册事件句柄。【参考方案2】:

您可以使用鼠标的低级挂钩并检查xbutton1或xbutton2是否被点击 看here

WM_XBUTTONDOWN 的值看http://msdn.microsoft.com/en-us/library/ms646245(VS.85).aspx

【讨论】:

我试过作为你的答案,但WM_LBUTTONDOWNevent 很酷,XBUTTONevent 不是。我试过0x0001 and 0x0020作为MouseMessages enum的值XBUTTONevent。我做错了什么? 你检查高位文本了吗?看看这个链接msdn.microsoft.com/en-us/library/ms997498.aspx 不,你应该检查0x020C 和按钮检查高位字参数0x00010x0002 感谢您的评论。我实现了鼠标导航事件的使用,0x020B 作为MouseMessages enum0x10000 用于左侧XBUTTON0x20000 用于右侧XBUTTON 作为hookStruct.mouseData。但是,如果在窗口中的任何位置触发事件,则会处理鼠标导航事件。 您可以检查鼠标是否在文档上。【参考方案3】:

更简单的方法....

这适用于 WPF 和 .net 4.5

private void Window_MouseDown(object sender, MouseButtonEventArgs e)

if (e.ChangedButton.Equals(MouseButton.XButton1)) MessageBox.Show(@"back");
if (e.ChangedButton.Equals(MouseButton.XButton2)) MessageBox.Show(@"forward");

【讨论】:

MouseDown 和 PreviewMouseDown 被 WebBrowser 控件吞噬,所以它对我不起作用。【参考方案4】:

TL;DR

安装我的 nuget 包 Lette.Wpf.AppCommands (source on GitHub) 并将其添加到您的主窗口:

<l:Window.AppCommandBindings>
    <AppCommandBinding AppCommand="BrowserBackward" Command="Binding BackCommand" />
</l:Window.AppCommandBindings>

只要按下“返回”按钮(无论是哪个),都会调用BackCommand

说明

XButton1XButton2 可能默认映射到 BackForward 导航,但情况可能并非总是如此。这些按钮可以重新映射到其他功能,有些鼠标有五个以上的按钮。那么,您实际上是如何收听Backwards navigation 消息的呢?

    联系WndProc。 收听WM_APPCOMMAND 消息。 在lparam 中,做一些位旋转并找到实际的APPCOMMAND_* 值。 如果它是所需的值(例如APPCOMMAND_BROWSER_BACKWARD),请执行您的操作。

例子:

var hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(mainWindow).Handle);
hwndSource.AddHook(WndProc);

// ...

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)

    if (msg == WM_APPCOMMAND)
    
        var appCommand = BitTwiddling(lparam);

        if (appCommand == APPCOMMAND_BROWSER_BACKWARD)
        
            // do your thing
        
    
    return IntPtr.Zero;

mainWindow 是对主窗口的引用(Window 类型)。

BitTwiddling 基本上是:将IntPtr 转换为int,右移16 位,然后用0x7FFF 屏蔽。

【讨论】:

以上是关于如何在 WPF WebBrowser 中使用“后退”和“前进”导航按钮事件?的主要内容,如果未能解决你的问题,请参考以下文章

WPF:如何在弹出窗口中自动调整 WebBrowser 的大小?

在 WPF 中使用 WebBrowser 关闭窗口后音频继续播放

WPF WebBrowser - 如何缩放内容?

使用 WPF WebBrowser 控件时如何抑制脚本错误?

wpf下如何去除webbrowser的滚动条

WPF中WebBrowser 如何在页面加载的时候注入js脚本