CEFSharp was contacted directly and told me to post this here. So here goes:
I was curious as I made a clone of the solution CEF gives here: https://github.com/cefsharp/CefSharp. I am seeing all invocation of the context menu is done in code behind with implementing the 'IContextMenuHandler'. Is there any way to invoke the Context Menu directly in the XAML like:
<cefSharp:ChromiumWebBrowser x:Name="browser" Address="http://www.google.com">
<FrameworkElement.ContextMenu>
<ContextMenu >
<MenuItem Header="Run It" Command="{Binding CommandRun}" / >
</ContextMenu >
</FrameworkElement.ContextMenu>
</cefSharp:ChromiumWebBrowser>
?
I was curious as in the code example it is all commented out in this class of xaml:
CefSharp.Wpf.Example/Views/BrowserTabView.xaml
lines 437-467 show this <!--<FrameworkElement.ContextMenu> <ContextMenu> <MenuItem Header="Back" Command="{Binding WebBrowser.BackCommand}" /> <MenuItem Header="Forward" Command="{Binding WebBrowser.ForwardCommand}" /> <Separator /> <MenuItem Header="Print ..." Command="{Binding WebBrowser.PrintCommand}" /> <Separator /> <MenuItem Header="Zoom In" Command="{Binding WebBrowser.ZoomInCommand}" /> <MenuItem Header="Zoom Out" Command="{Binding WebBrowser.ZoomOutCommand}" /> <MenuItem Header="Zoom Reset" Command="{Binding WebBrowser.ZoomResetCommand}" /> <Separator /> <MenuItem Header="Show DevTools" Command="{Binding ShowDevToolsCommand}" /> <MenuItem Header="Close DevTools" Command="{Binding CloseDevToolsCommand}" /> <Separator /> <MenuItem Header="View Source" Command="{Binding WebBrowser.ViewSourceCommand}" /> <MenuItem Header="Cut" Command="{Binding WebBrowser.CutCommand}"/> <MenuItem Header="Copy" Command="{Binding WebBrowser.CopyCommand}"/> <MenuItem Header="Paste" Command="{Binding WebBrowser.PasteCommand}"/> </ContextMenu> </FrameworkElement.ContextMenu>-->
I may have missed a section that shows how to implement it. Please let me know if any knows how you can implement your ChromiumWebBrowser in WPF with all the code directly in the XAML following traditional MVVM Bindings to ICommand arguments to be executed in the ViewModel that is bound to the View that holds the ChromiumWebBrowser.
What I have done thus far is create a class that implements IContextMenuHandler like so:
public class BrowserContextMenuHandler : IContextMenuHandler
{
private Action<IMenuModel> _menu;
private Func<CefMenuCommand, bool> _menuCommands;
public BrowserContextMenuHandler(Action<IMenuModel> menu, Func<CefMenuCommand, bool> menuCommands)
{
_menu = menu;
_menuCommands = menuCommands;
}
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model) =>
_menu(model);
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags) => _menuCommands(commandId);
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
var chromiumWebBrowser = (ChromiumWebBrowser)browserControl;
chromiumWebBrowser.Dispatcher.Invoke(() =>
{
chromiumWebBrowser.ContextMenu = null;
});
}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback) => false;
}
Then to get it to work I would do something like:
XAML:
<cefSharp:ChromiumWebBrowser Grid.Row="1" x:Name="browser" Address="http://www.google.com">
Code Behind constructor:
private MainWindowViewModel _vm;
public MainWindow()
{
InitializeComponent();
_vm = new MainWindowViewModel();
DataContext = _vm;
browser.MenuHandler = new BrowserContextMenuHandler(menu =>
{
menu.Clear();
menu.AddItem((CefMenuCommand)26501, "Run Test for VM");
menu.AddSeparator();
menu.AddItem((CefMenuCommand)26502, "Hello");
},
commandId =>
{
if (commandId == (CefMenuCommand)26501)
_vm.CommandRun.Execute(null);
if (commandId == (CefMenuCommand)26502)
MessageBox.Show("Hello there");
return true;
});
}
And then I can invoke VM commands with a delayed action till menu items are clicked. This does all work and feel free to play with my Repo: https://github.com/djangojazz/CefSharpChromiumWebBrowser. However this is kind of messy and I was hoping I could just do this in xaml directly. Does anyone know? I was thinking I could at least Add a 'CefSharp.WebBrowser' property to my VM and potentially invoke all of the Context Menu directly there(have not tried that yet as of writing this). That could put more of the burden on the VM.
Thanks