3

我正在用 C# 开发一个 Windows 窗体应用程序,它带有一个嵌入式WebBrowser控件来“防伪”(即禁用上下文菜单、后退按钮、自由导航等)访问第三方 Web 应用程序。

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

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

  1. CTRL-MouseWheel 总是MouseWheel在父窗体具有焦点并且鼠标光标悬停在窗口顶部(例如,在应用程序的标题上),或者当鼠标光标悬停在WebBrowser控件上而不出现时触发事件即使父窗体有焦点也有焦点。
  2. MouseWheel当鼠标光标悬停在WebBrowser控件上并具有焦点时, CTRL-MouseWheel 从不触发事件WebBrowser,并且似乎没有效果。
  3. 在没有 CTRL 的情况下使用鼠标滚轮滚动窗口内容,WebBrowser但不会触发MouseWheel事件,直到垂直滚动条完全到达顶部或底部。
  4. 为继承自父表单的示例类和为继承自父表单的示例类拦截Messagefor仅适用于上述条件(正确表示)。WM_MOUSEWHEELWndProcDefWndProcWebBrowserwParamMK_CONTROL
  5. 正如预期的那样,当按下 CTRL 时会触发该PreviewKeyDown事件,但仍然不会与鼠标滚轮一致。

所以我猜Message它正在父表单和托管控制级别以下处理,并且不会冒泡到我可以拦截甚至处理它的地方。有没有办法做到这一点,或者其他方式来模拟使用 CTRL-MouseWheel 放大和缩小?

谢谢阅读!

4

5 回答 5

5

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

这令人沮丧,以至于我让它工作并停止关心......

这里至少有一个文档解释了基础知识:如何在 Visual C# .NET 应用程序中处理文档事件

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(滚动量),您需要将事件对象转换为另一个接口。

bool docEvents_onmousewheel(mshtml.IHTMLEventObj pEvtObj)
{
    var wheelEventObj = (mshtml.IHTMLEventObj4)pEvtObj;
    var delta = wheelEventObj.wheelDelta;
    [...]
}
于 2013-10-09T20:00:07.677 回答
0

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

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

于 2011-01-04T18:07:37.083 回答
0

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

  • OLECMDID_GETZOOMRANGE
  • OLECMDID_OPTICAL_GETZOOMRANGE
  • OLECMDID_OPTICAL_ZOOM
  • OLECMDID_ZOOM

它们由 Internet Explorer 发送。请参阅MSDN 上的备注

于 2012-02-12T02:37:29.423 回答
0

我无法让这些中的任何一个可靠地工作,所以经过一些(令人沮丧的)实验后,我想出了 TCC 发布的答案的派生词。我的网络浏览器控件托管在用户控件中。主要区别是我为 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;
    } 
于 2014-05-06T22:03:17.720 回答
0

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

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 找到这个。但是我忘记了链接,一旦找到,将在此处附加。

于 2013-11-13T14:52:32.170 回答