[英]Custom context menu for WPF WebBrowser Control
您好,我需要為 wpf 中的 web 瀏覽器控件創建一個自定義上下文菜單。這是我的 xaml 代碼,它不起作用:
<WebBrowser x:Name="EmailBox" ap:BrowserBehavior.HtmlString="{Binding Message, Mode=OneWay}">
<WebBrowser.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy" Command="ApplicationCommands.Copy"/>
<MenuItem Header="Copy to Customer Reference ID"
Command="{Binding CopyID}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}},
Path=PlacementTarget.Selection.Text}">
<MenuItem.Icon>
<Image Source="{StaticResource CopyImageSource}" Width="16" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Copy to Comments"
Command="{Binding CopyToCommentsCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}},
Path=PlacementTarget.Selection.Text}">
<MenuItem.Icon>
<Image Source="{StaticResource NoteCopyI}" Width="16" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</WebBrowser.ContextMenu>
</WebBrowser>
我從其他地方復制了上下文菜單代碼。 這適用於其他控件,但不適用於網絡瀏覽器控件。 有可能使這項工作嗎?
嗨,您必須添加對Microsoft HTML對象庫的引用,然后...
XAML
<Window x:Class="WPFCustomContextMenuInWebBrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFCustomContextMenuInWebBrowser"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ContextMenu x:Key="MnuCustom" StaysOpen="True">
<MenuItem Header="Custom 1"></MenuItem>
<MenuItem Header="Custom 1"></MenuItem>
<MenuItem Header="Custom 3"></MenuItem>
</ContextMenu>
</Window.Resources>
<Grid>
<WebBrowser x:Name="Wb"></WebBrowser>
</Grid>
</Window>
C#
using System.Windows.Controls;
using MSHTML;
namespace WPFCustomContextMenuInWebBrowser {
public partial class MainWindow {
private HTMLDocumentEvents2_Event _docEvent;
public MainWindow() {
InitializeComponent();
Wb.Navigate("http://google.com");
Wb.LoadCompleted += delegate {
if (_docEvent != null) {
_docEvent.oncontextmenu -= _docEvent_oncontextmenu;
}
if (Wb.Document != null) {
_docEvent = (HTMLDocumentEvents2_Event)Wb.Document;
_docEvent.oncontextmenu += _docEvent_oncontextmenu;
}
};
}
bool _docEvent_oncontextmenu(IHTMLEventObj pEvtObj) {
WbShowContextMenu();
return false;
}
public void WbShowContextMenu() {
ContextMenu cm = FindResource("MnuCustom") as ContextMenu;
if (cm == null) return;
cm.PlacementTarget = Wb;
cm.IsOpen = true;
}
}
}
不,這是不可能的。
WebBrowser控件是本機WebBrowser ActiveX組件的非常薄的包裝,該組件是Internet Explorer子系統的一部分。 它托管在其自己的窗口主機中(WPF窗口和WebBrowser具有不同的HWND),因此WPF僅了解焦點進入和離開WebBrowser的知識,但不了解任何鍵盤/鼠標事件。 此外,還有一個所謂的“空域問題”:WPF渲染的屏幕區域和本機區域不能重疊。
因此,不能將WPF ContextMenu與WebBrowser一起使用,因為:
另外,我認為沒有簡單的方法可以在瀏覽器的內容中使用html / js來模擬ContextMenu-我記得,ActiveX組件使用IE5(古怪的)渲染模式,並且不更改注冊表文件就無法更改它。
您可以嘗試將ActiveX API與WebBrowser.Document對象一起使用以禁用本機上下文菜單,並通過WinAPI自己繪制另一個菜單,這並非易事。
因此,我建議您尋找其他純WPF瀏覽器控件或HTML渲染器,例如awesomium
XAML如下:
<!--WebBrowser to Display Chat Messages-->
<WebBrowser Name="webBrowser"
Source="http://stakoverflow.com"
Navigated="webBrowser_Navigated"
Navigating="webBrowser_Navigating"
LoadCompleted="webBrowser_LoadCompleted">
<WebBrowser.ContextMenu>
<ContextMenu x:Name="wbContextMenu" >
<MenuItem x:Name="menuItem1" Header="Test Item" Click="menuItem1_Click" />
</ContextMenu>
</WebBrowser.ContextMenu
</WebBrowser>
代碼如下:
using mshtml;
private mshtml.HTMLDocumentEvents2_Event documentEvents;
在構造函數或xaml中設置您的LoadComplete事件:
webBrowser.LoadCompleted += webBrowser_LoadCompleted;
然后在該方法中創建新的Webbrowser文檔對象,並查看可用屬性並創建新事件,如下所示:
private void webBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
documentEvents = (HTMLDocumentEvents2_Event)webBrowserChat.Document; // this will access the events properties as needed
documentEvents.oncontextmenu += webBrowserChat_ContextMenuOpening;
}
private bool webBrowserChat_ContextMenuOpening(IHTMLEventObj pEvtObj)
{
wbContextMenu.PlacementTarget = pEvtObj as ContextMenu; // Creates target spot where contextmenu will appear
wbContextMenu.IsOpen = true; // Opens contextmneu
return false; // ContextMenu wont open
// return true; ContextMenu will open
// Here you can create your custom contextmenu or whatever you want
}
我采用了@MartinHoly提供的解決方案,但遇到了問題:上下文菜單只能彈出一次(例如,如果右鍵單擊滾動條,或者選擇自定義菜單項-下次您右鍵單擊WebBrowser,將顯示標准IE菜單)。 我做了以下解決方法:xaml:
<Window x:Class="WPFCustomContextMenuInWebBrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFCustomContextMenuInWebBrowser"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ContextMenu x:Key="MnuCustom" StaysOpen="True">
<MenuItem Header="Custom 1"></MenuItem>
<MenuItem Header="Custom 2"></MenuItem>
<MenuItem Header="Custom 3"></MenuItem>
</ContextMenu>
</Window.Resources>
<Grid>
<WebBrowser x:Name="Browser"></WebBrowser>
</Grid>
后面的代碼:
using System.Windows.Controls;
using MSHTML;
namespace WPFCustomContextMenuInWebBrowser {
public partial class MainWindow {
public MainWindow()
{
InitializeComponent();
Browser.LoadCompleted += BrowserOnLoadCompleted;
}
void BrowserOnLoadCompleted(object sender, NavigationEventArgs navigationEventArgs)
{
var mshtmlDoc = Browser.Document as HTMLDocument;
if (mshtmlDoc == null) return;
var doc2event = mshtmlDoc as HTMLDocumentEvents2_Event;
if (doc2event != null)
{
doc2event.onfocusin += FocusInContextMenu;
}
}
bool OpenContextMenu(IHTMLEventObj pEvtObj)
{
WbShowContextMenu(pEvtObj as ContextMenu);
return false;
}
void FocusInContextMenu(IHTMLEventObj pevtobj)
{
var mshtmlDoc = Browser.Document as HTMLDocument;
var doc2event = mshtmlDoc as HTMLDocumentEvents2_Event;
if (doc2event != null)
{
doc2event.oncontextmenu -= OpenContextMenu;
doc2event.onfocusin -= FocusInContextMenu;
doc2event.oncontextmenu += OpenContextMenu;
doc2event.onfocusin += FocusInContextMenu;
}
}
public void WbShowContextMenu()
{
ContextMenu cm = FindResource("MnuCustom") as ContextMenu;
if (cm == null) return;
cm.PlacementTarget = Browser;
cm.IsOpen = true;
}
}
}
我有一個間接實現,它涉及在 C# 和 javascript 中互相調用。
xaml:
<WebBrowser x:Name="webbrowser">
<WebBrowser.ContextMenu>
<ContextMenu>
<MenuItem Header="item1"/>
</ContextMenu>
</WebBrowser.ContextMenu>
</WebBrowser>
c#:
using System.Runtime.InteropServices;
public MainWindow()
{
InitializeComponent();
//webbrowser.Navigate(new Uri("https://www.google.com"));
webbrowser.ObjectForScripting = new ScriptManager(this);
webbrowser.LoadCompleted += Webbrowser_LoadCompleted;
}
private void Webbrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
//call C# method and disable the default contextmenu here.
webbrowser.InvokeScript("eval", new object[] { "document.oncontextmenu = function() { window.external.ShowContextMenu(); return false; };" });
}
[ComVisible(true)]
public class ScriptManager
{
private MainWindow mainWindow;
public ScriptManager(MainWindow MainWindow)
{
mainWindow = MainWindow;
}
public void ShowContextMenu()
{
mainWindow.webbrowser.ContextMenu.IsOpen = true;
}
}
但是當頁面加載時它仍然有一個本機上下文菜單,因為 LoadCompleted 事件尚未觸發。
所以如果html頁面是自己寫的,可以直接在html的腳本部分添加這行,不需要LoadCompleted事件:
document.oncontextmenu = function() { window.external.ShowContextMenu(); return false; };
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.