C# - 在WebBrowser控件中捕获CTRL-鼠标滚轮

时间:2010-10-19 18:55:44

标签: c# forms browser mousewheel ctrl

我正在用C#开发一个Windows窗体应用程序,其中嵌入了WebBrowser控件以“虚拟证明”(即禁用上下文菜单,后退按钮,自由导航等)访问第三方Web应用。

现在我正在尝试将缩放功能添加到我的自定义浏览器中。我有键盘组合工作(CTRL +和CTRL - 对底层ActiveX WebBrowser对象进行正确的OLE调用),但在其他令人沮丧的事情WebBrowser我必须处理,我可以'似乎弄清楚如何捕捉CTRL鼠标滚轮来模拟像IE一样的缩放功能。我到处寻找解决方案,但无济于事。

为了弄清楚,我创建了一个只有WebBrowser控件的空表单,并找到了以下内容:

  1. 当父窗体具有焦点并且鼠标光标悬停在窗口顶部(例如,在应用程序的标题上)或鼠标光标悬停时,CTRL-MouseWheel始终触发MouseWheel事件在WebBrowser控件上,即使父窗体具有焦点,它似乎没有焦点。
  2. 当鼠标光标悬停在MouseWheel控件上且WebBrowser具有焦点时,CTRL-MouseWheel永远不会触发WebBrowser事件,并且似乎没有效果。
  3. 使用不带CTRL的鼠标滚轮滚动WebBrowser的窗口内容,但不会触发MouseWheel事件,直到垂直滚动条完全到达顶部或底部。
  4. 通过覆盖MessageWM_MOUSEWHEEL两者来截取WndProc的{​​{1}},以获取从DefWndProc继承的样本类和父表单仅适用于上述条件(WebBrowser正确表示wParam)。
  5. 按下CTRL时MK_CONTROL事件会按预期触发,但仍然与鼠标滚轮无关。
  6. 所以我想PreviewKeyDown正在父窗体和托管控制级别下面进行处理,并且没有冒泡到我可以截取甚至处理它的位置。有没有办法做到这一点,或者使用CTRL-MouseWheel模拟放大和缩小的其他方法?

    感谢阅读!

5 个答案:

答案 0 :(得分:4)

首先将WebBrowser.Document.DomDocument强制转换为mshtml命名空间中的右侧接口,如mshtml.HTMLDocumentEvents2_Event,然后您可以处理(和取消)mousewheel事件。我不确定,但我认为您需要在文档更改时随时连接事件处理程序,因此我在WebBrowser.DocumentCompleted事件上执行此操作。我也不确定你是否需要释放任何COM对象。

这令人沮丧,我让它开始工作并停止了关怀......

以下是至少一份解释基础知识的文件:How to handle document events in a Visual C# .NET application

对于您的具体情况,只需根据是否按下onmousewheel键,有条件地压缩CTRL事件。

private void webBrowser_DocumentCompleted(object sender,
                                         WebBrowserDocumentCompletedEventArgs e)
{
    if (webBrowser.Url.ToString() == "about:blank")
        return;
    var docEvents = (mshtml.HTMLDocumentEvents2_Event)webBrowser.Document.DomDocument;
    docEvents.onmousewheel -= docEvents_onmousewheel; //may not be necessary?
    docEvents.onmousewheel += docEvents_onmousewheel;
}

bool docEvents_onmousewheel(mshtml.IHTMLEventObj pEvtObj)
{
    if (pEvtObj.ctrlKey)
    {
        pEvtObj.cancelBubble = true; //not sure what this does really
        pEvtObj.returnValue = false;  //this cancels the event
        return false; //not sure what this does really
    }
    else
        return true; //again not sure what this does
} 

现在,如果您需要知道Wheel Delta(滚动量),您需要将events对象转换为另一个界面。

bool docEvents_onmousewheel(mshtml.IHTMLEventObj pEvtObj)
{
    var wheelEventObj = (mshtml.IHTMLEventObj4)pEvtObj;
    var delta = wheelEventObj.wheelDelta;
    [...]
}

答案 1 :(得分:0)

使用SetWindowsHookEx查找这些事件可能对您有用。这就是我用来在ActiveX MapPoint控件上获取滚轮事件的方法。

请注意,在Windows 7上存在一些可能需要一些修改的怪癖。有关详细信息,请在MSDN论坛上搜索Windows 7上的SetWindowsHookEx。

答案 2 :(得分:0)

要解决此问题,您必须侦听并处理这些消息:

  • OLECMDID_GETZOOMRANGE
  • OLECMDID_OPTICAL_GETZOOMRANGE
  • OLECMDID_OPTICAL_ZOOM
  • OLECMDID_ZOOM

他们是由Internet Explorer调度的。请参阅remarks on MSDN

答案 3 :(得分:0)

这是我用来禁用ctrl + shift的代码:
你需要在最深的控件“Internet Explorer_Server”中更改WndProc的行为,
在您的Web浏览器准备就绪后执行此操作:

IntPtr wbHandle = Win32.FindWindowEx(this.wbMain.Handle, IntPtr.Zero, "Shell Embedding", String.Empty);
wbHandle = Win32.FindWindowEx(wbHandle, IntPtr.Zero, "Shell DocObject View", String.Empty);
wbHandle = Win32.FindWindowEx(wbHandle, IntPtr.Zero, "Internet Explorer_Server", String.Empty);
WbInternal wb = new WbInternal(wbHandle);

class WbInternal : NativeWindow
    {
        public WbInternal(IntPtr handle)
        {
            this.AssignHandle(handle);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_MOUSEWHEEL)


            {
                if (((int)m.WParam & 0x00FF) == MK_SHIFT)
                {
                    return;
                }
            }
            base.WndProc(ref m);
        }
    }

您可以从MSDN找到有关WM_MOUSEWHEEL的更多消息 我在MSDN上找到了这个。但是我忘记了链接,一旦发现,就会把它添加到这里。

答案 4 :(得分:0)

我无法使这些中的任何一个可靠地工作,所以经过一些(令人沮丧的)实验后,我想出了TCC发布的答案的衍生物。我的webbrowser控件托管在usercontrol中。主要区别是我使用HTMLDocumentEvents2_Event的类级变量,所以我可以成功取消订阅,并将mshtml.IHTMLEventObj pEvtObj.Returnvalue设置为true ..现在似乎运行良好..

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        _wbData = (WebBrowser)FindElement("DataBrowser");
        _horzScroll = (ScrollBar)FindElement("HorizontalScroll");
        _vertScroll = (ScrollBar)FindElement("VerticalScroll");

        _wbData.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(OnLoadCompleted);

        _horzScroll.Scroll += new ScrollEventHandler(OnHorizontalScroll);
        _vertScroll.Scroll += new ScrollEventHandler(OnVerticalScroll);
        LoadDefault();
        EnableSoundEffects(SoundEffects);
    }

    private void OnHorizontalScroll(object sender, ScrollEventArgs e)
    {
       // _wbData.Handle
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;
        _horzPosition = (int)e.NewValue;

        if (htmlDoc != null && htmlDoc.body != null)
            htmlDoc.parentWindow.scroll(_horzPosition, _vertPosition);
    }

    private void OnVerticalScroll(object sender, ScrollEventArgs e)
    {
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;
        _vertPosition = (int)e.NewValue;

        if (htmlDoc != null && htmlDoc.body != null)
            htmlDoc.parentWindow.scroll(_horzPosition, _vertPosition);
    }

    private void OnLoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
    {
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;

        if (htmlDoc != null && htmlDoc.body != null)
        {
            mshtml.IHTMLElement2 body = (mshtml.IHTMLElement2)htmlDoc.body;

                _horzScroll.Visibility = Visibility.Collapsed;

            if (body.scrollHeight > _wbData.ActualHeight)
                _vertScroll.Visibility = Visibility.Visible;
            else
                _vertScroll.Visibility = Visibility.Collapsed;

            _vertScroll.ViewportSize = _wbData.ActualHeight;
            _vertScroll.Maximum = body.scrollHeight - (_wbData.ActualHeight - 8);

            _eventHelper = (HTMLDocumentEvents2_Event)_wbData.Document;
            _eventHelper.onmousewheel -= OnMouseWheel;
            _eventHelper.onmousewheel += new HTMLDocumentEvents2_onmousewheelEventHandler(OnMouseWheel);
        }
    }

    private bool OnMouseWheel(mshtml.IHTMLEventObj pEvtObj)
    {
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;
        var wheelEventObj = (mshtml.IHTMLEventObj4)pEvtObj;
        var delta = wheelEventObj.wheelDelta;

        if (htmlDoc != null && htmlDoc.body != null && wheelEventObj != null)
        {
            _vertPosition += (int)wheelEventObj.wheelDelta;
            htmlDoc.parentWindow.scroll(_horzPosition, _vertPosition);
        }

        pEvtObj.returnValue = true;
        return true;
    }