[英]C# - Capturing CTRL-Mouse wheel in WebBrowser control
我正在用C#開發帶有嵌入式WebBrowser
控件的Windows Forms應用程序,以“虛擬”(例如,禁用上下文菜單,后退按鈕,自由導航等)對第三方Web應用程序的訪問。
現在,我正在嘗試將縮放功能添加到自定義瀏覽器中。 我有鍵盤組合為此工作(CTRL +和CTRL-對基礎ActiveX WebBrowser對象進行正確的OLE調用),但是在不得不處理的有關WebBrowser
的其他令人沮喪的事情中,我似乎無法弄清楚像IE一樣,如何捕獲CTRL-鼠標滾輪來模擬縮放功能。 我到處都在尋找解決方案,但無濟於事。
為了找出答案,我創建了一個僅包含WebBrowser控件的空表單,並發現了以下內容:
WebBrowser
控件上時,CTRL-MouseWheel始終會觸發MouseWheel
事件即使父窗體具有焦點,也似乎沒有焦點。 WebBrowser
控件上並且WebBrowser
擁有焦點時,CTRL-MouseWheel永遠不會觸發MouseWheel
事件。 WebBrowser
的窗口內容,但在垂直滾動條完全到達頂部或底部之前,不會觸發MouseWheel
事件。 WndProc
和DefWndProc
來攔截從WebBrowser
繼承的示例類和父窗體的WM_MOUSEWHEEL
Message
僅適用於上述條件( wParam
正確表示MK_CONTROL
)。 PreviewKeyDown
事件,但仍然無法與鼠標滾輪保持一致。 因此,我猜該Message
正在父窗體和托管控件級別以下進行處理,並且不會冒到我可以攔截甚至處理它的地方。 有沒有辦法做到這一點,或者有其他方法可以使用CTRL-MouseWheel模擬放大和縮小?
謝謝閱讀!
首先將WebBrowser.Document.DomDocument
投射到mshtml命名空間中的正確接口,例如mshtml.HTMLDocumentEvents2_Event
,然后可以處理(並取消)鼠標滾輪事件。 我不確定,但是我認為您隨時需要在文檔更改時連接事件處理程序,因此我在WebBrowser.DocumentCompleted
事件上進行操作。 我也不確定是否需要釋放任何COM對象。
這實在令人沮喪,以至於我開始工作並停止關心……
這里是至少一個解釋基礎的文檔: 如何在Visual C#.NET應用程序中處理文檔事件
對於您的特定情況,只需根據是否按下CTRL
鍵有條件地壓縮onmousewheel
事件。
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;
[...]
}
這是我用來禁用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找到了這個。 但是我忘了鏈接,一旦找到,將在此處添加。
我無法使所有這些可靠地工作,因此在進行一些(令人沮喪的)實驗之后,我想出了TCC發布的答案的派生詞。 我的Web瀏覽器控件托管在用戶控件中。 主要區別在於我為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;
}
也許使用SetWindowsHookEx查找這些事件可能對您有用。 這就是我用來在ActiveX MapPoint控件上獲取滾輪事件的功能。
請注意,Windows 7上對此有一些怪異之處,可能需要進行一些修改。 有關更多詳細信息,請在MSDN論壇上的Windows 7上搜索SetWindowsHookEx。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.