C # - Захват CTRL-колеса мыши в элементе управления WebBrowser

Я разрабатываю приложение Windows Forms на C # со встроенным элементом управления WebBrowser для «фиктивного» (т. Е. Отключения контекстных меню, кнопки возврата, свободной навигации и т. Д.) Доступа к стороннему веб-приложению.

Прямо сейчас я пытаюсь добавить функцию масштабирования в свой собственный браузер. У меня работают комбинации клавиш (CTRL + и CTRL - сделайте правильные вызовы OLE для базового объекта ActiveX WebBrowser), но среди других неприятных вещей о WebBrowser, с которыми мне пришлось иметь дело, я не могу понять узнаем, как захватить CTRL-колесо мыши для имитации функции масштабирования, как это делает IE. Я везде искал решение этой проблемы, но безрезультатно.

Чтобы попытаться понять это, я создал пустую форму с элементом управления WebBrowser и обнаружил следующее:

  1. CTRL-MouseWheel всегда запускает событие MouseWheel, когда родительская форма имеет фокус и курсор мыши находится над верхней частью окна (например, над заголовком приложения), или когда курсор мыши находится над элементом управления WebBrowser, когда это происходит. не имеет фокуса, хотя родительская форма имеет фокус.
  2. CTRL-MouseWheel никогда не запускает событие MouseWheel, когда курсор мыши находится над элементом управления WebBrowser и WebBrowser находится в фокусе, и, похоже, нет никакого эффекта.
  3. Using the mouse wheel without CTRL scrolls the window contents of WebBrowser but does not fire the MouseWheel event until the vertical scroll bar has fully reached either the top or the bottom.
  4. Intercepting the Message for WM_MOUSEWHEEL by overriding WndProc and DefWndProc both for a sample class inherited from WebBrowser and for the parent form applies only for the above conditions (with wParam properly denoting MK_CONTROL).
  5. Событие PreviewKeyDown срабатывает при нажатии CTRL, как и ожидалось, но по-прежнему ничего не делает в унисон с колесом мыши.

Итак, я предполагаю, что Message обрабатывается ниже родительской формы и уровня управляемого контроля и не всплывает туда, где я могу его перехватить или даже обработать. Есть ли способ сделать это или какой-либо другой способ имитировать увеличение и уменьшение масштаба с помощью CTRL-MouseWheel?

Спасибо за чтение!


person lhial    schedule 19.10.2010    source источник
comment
Привет, у меня точно такая же проблема. Удалось ли вам это решить, и если да, не могли бы вы поделиться решением? Большое спасибо за уделенное время, Ник   -  person MoonKnight    schedule 21.02.2011


Ответы (5)


Сначала приведите WebBrowser.Document.DomDocument к правому интерфейсу в пространстве имен mshtml, например 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
} 

Теперь, если вам нужно знать дельту колеса (количество прокрутки), вы захотите передать объект событий еще одному интерфейсу.

bool docEvents_onmousewheel(mshtml.IHTMLEventObj pEvtObj)
{
    var wheelEventObj = (mshtml.IHTMLEventObj4)pEvtObj;
    var delta = wheelEventObj.wheelDelta;
    [...]
}
person TCC    schedule 09.10.2013
comment
надежно работает для меня ... я в Windows 7 с IE 9 и IE 10 ... .NET 4 - person TCC; 15.01.2014
comment
pEvtObj.returnValue = false; // это отменяет событие .. это было обязательным условием для правильной работы. Спасибо. - person MuhammadHani; 16.01.2014

Возможно, использование SetWindowsHookEx для поиска этих событий может сработать для вас. Это то, что я использовал для получения событий колеса прокрутки поверх элемента ActiveX MapPoint.

Имейте в виду, что в Windows 7 есть некоторые особенности, которые могут потребовать некоторой доработки. Для получения дополнительных сведений выполните поиск SetWindowsHookEx в Windows 7 на форумах MSDN.

person jpierson    schedule 04.01.2011


Это код, который я использовал для отключения ctrl + shift:
Вам нужно изменить поведение WndProc в самом глубоком элементе управления "Internet Explorer_Server",
Сделайте это после того, как ваш веб-браузер будет готов:

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);
        }
    }

Вы можете найти больше сообщений о WM_MOUSEWHEEL в MSDN.
Я нахожу это в MSDN. Но я забыл ссылку, как только найду, добавлю ее сюда.

person dasons    schedule 13.11.2013
comment
social.msdn.microsoft.com/Forums/zh-CN/ - person dasons; 13.11.2013

Я не мог заставить ни один из них работать надежно, поэтому после некоторых (разочаровывающих) экспериментов я придумал производную от ответа, опубликованного 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;
    } 
person JGU    schedule 06.05.2014