Hi I need to create a custom context menu for a web browser control in wpf. Here is my xaml code which is not working:
The XAML as follows:
<!--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>
Code as follows:
using mshtml;
private mshtml.HTMLDocumentEvents2_Event documentEvents;
in constructor or xaml set your LoadComplete event:
webBrowser.LoadCompleted += webBrowser_LoadCompleted;
then in that method create your new webbrowser document object and view the available properties and create new events as follows:
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
}
No, It's not possible to make this work.
WebBrowser control is a very thin wrapper around native WebBrowser ActiveX component, which is a part of Internet Explorer subsystem. It is hosted in it's own window host (WPF window and WebBrowser have different HWNDs), so WPF knows only about focus entering and leaving WebBrowser, but has no knowledge of any keyboard/mouse events. Also, there is so called 'airspace problem': WPF-rendered and native regions of screen area cannot overlap.
Therefore you cannot use WPF ContextMenu with WebBrowser, because:
Also, I don't think there is easy way to emulate ContextMenu with html/js in browser's content - as I recall, ActiveX component uses IE5 (quirk) rendering mode, and it is not possible to change that without changing registry files.
You can try to use ActiveX API with WebBrowser.Document object to disable native context menu and draw another one yourself through WinAPI, which is not an easy task.
So, I would recommend to look for other, pure-WPF browser controls or HTML renderers, such as awesomium
I've taken the solution provided by @MartinHoly and i've encountered the problem: to context menu can be popped up only once (if you right-click on the scrollbar, for example, or select a custom menu item - next time you right-click the WebBrowser brings the standard IE menu). I have made the following workaround: The 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>
The code behind:
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;
}
}
}
Hi You have to add reference to Microsoft HTML Object Library and than...
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;
}
}
}