繁体   English   中英

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

[英]How to use 'Back' & 'Forward' navigation button events in WPF WebBrowser?

WPF 中的WebBrowser控件继承自UIElement ,但我们无法在UIElement事件中注册事件处理程序。 为什么? WPF WebBrowser Mouse Events not working as expected ,它得到了回答,但我仍然无法理解。

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

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

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,
    }

更简单的方式....

这适用于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");
}

您可以使用低级别的鼠标钩子并检查是否单击了xbutton1或xbutton2
这里

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

WebBrowser控件实际上只是Trident COM对象的瘦包装器。 它不像其他内置控件那样“纯WPF”......因此很多普通的东西都无法使用它。 要回答您的问题,您可以获得的最接近的是进入导航事件。 这不会告诉你用户是试图前进还是后退或其他地方,但它会给你URL并有机会设置e.Cancel = true来停止导航(通常接着调用Navigate(url)用户在其他地方)。

TL; 博士

安装我的 nuget 包Lette.Wpf.AppCommandsGitHub 上的源代码)并将其添加到您的主窗口:

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

每当按下“后退”按钮(无论是哪个)时,都会调用BackCommand

解释

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

  1. 连接一个WndProc
  2. 侦听WM_APPCOMMAND消息。
  3. lparam ,进行一些处理并找到实际的APPCOMMAND_*值。
  4. 如果它是所需的值(例如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 进行掩码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM