From d74215a1f912ee6f0604fe4474f498a328dde697 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 26 Jun 2017 13:41:23 +1000 Subject: [PATCH] WPF Example - update MenuHandler to implement custom menu, execute command based on CefMenuCommand enum rather than trying to use IRunContextMenuCallback which isn't working (upstream issue) This is a workaround for #1767 You can use the default CEF menu it does however require you to integrate CEF into your main message loop see #1795 --- CefSharp.Wpf.Example/Handlers/MenuHandler.cs | 204 ++++++++++++++----- 1 file changed, 153 insertions(+), 51 deletions(-) diff --git a/CefSharp.Wpf.Example/Handlers/MenuHandler.cs b/CefSharp.Wpf.Example/Handlers/MenuHandler.cs index 3bdfb61707..8a14f32e0c 100644 --- a/CefSharp.Wpf.Example/Handlers/MenuHandler.cs +++ b/CefSharp.Wpf.Example/Handlers/MenuHandler.cs @@ -3,6 +3,7 @@ // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; +using System.Linq; using System.Collections.Generic; using System.Windows.Controls; using System.Windows; @@ -48,71 +49,172 @@ bool IContextMenuHandler.OnContextMenuCommand(IWebBrowser browserControl, IBrows void IContextMenuHandler.OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame) { - //var chromiumWebBrowser = (ChromiumWebBrowser)browserControl; + var chromiumWebBrowser = (ChromiumWebBrowser)browserControl; - //chromiumWebBrowser.Dispatcher.Invoke(() => - //{ - // chromiumWebBrowser.ContextMenu = null; - //}); + chromiumWebBrowser.Dispatcher.Invoke(() => + { + chromiumWebBrowser.ContextMenu = null; + }); } bool IContextMenuHandler.RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback) { - return false; + //NOTE: Return false to use the build in Context menu - in WPF this requires you integrate into your existing message loop, read the General Usage Guide for more details + //return false; + + var chromiumWebBrowser = (ChromiumWebBrowser)browserControl; - //var chromiumWebBrowser = (ChromiumWebBrowser)browserControl; - - ////IMenuModel is only valid in the context of this method, so need to read the values before invoking on the UI thread - //var menuItems = GetMenuItems(model); - - //chromiumWebBrowser.Dispatcher.Invoke(() => - //{ - // var menu = new ContextMenu - // { - // IsOpen = true - // }; - - // RoutedEventHandler handler = null; - - // handler = (s, e) => - // { - // menu.Closed -= handler; - - // //If the callback has been disposed then it's already been executed - // //so don't call Cancel - // if(!callback.IsDisposed) - // { - // callback.Cancel(); - // } - // }; - - // menu.Closed += handler; - - // foreach (var item in menuItems) - // { - // menu.Items.Add(new MenuItem - // { - // Header = item.Item1, - // Command = new RelayCommand(() => { callback.Continue(item.Item2, CefEventFlags.None); }) - // }); - // } - // chromiumWebBrowser.ContextMenu = menu; - //}); - - //return true; + //IMenuModel is only valid in the context of this method, so need to read the values before invoking on the UI thread + var menuItems = GetMenuItems(model).ToList(); + + chromiumWebBrowser.Dispatcher.Invoke(() => + { + var menu = new ContextMenu + { + IsOpen = true + }; + + RoutedEventHandler handler = null; + + handler = (s, e) => + { + menu.Closed -= handler; + + //If the callback has been disposed then it's already been executed + //so don't call Cancel + if (!callback.IsDisposed) + { + callback.Cancel(); + } + }; + + menu.Closed += handler; + + foreach (var item in menuItems) + { + if(item.Item2 == CefMenuCommand.NotFound && string.IsNullOrWhiteSpace(item.Item1)) + { + menu.Items.Add(new Separator()); + continue; + } + + menu.Items.Add(new MenuItem + { + Header = item.Item1.Replace("&", "_"), + IsEnabled = item.Item3, + Command = new RelayCommand(() => + { + //BUG: CEF currently not executing callbacks correctly so we manually map the commands below + //the following line worked in previous versions, it doesn't now, so custom EXAMPLE below + //callback.Continue(item.Item2, CefEventFlags.None); + + //NOTE: Note all menu item options below have been tested, you can work out the rest + switch (item.Item2) + { + case CefMenuCommand.Back: + { + browser.GoBack(); + break; + } + case CefMenuCommand.Forward: + { + browser.GoForward(); + break; + } + case CefMenuCommand.Cut: + { + browser.FocusedFrame.Cut(); + break; + } + case CefMenuCommand.Copy: + { + browser.FocusedFrame.Copy(); + break; + } + case CefMenuCommand.Paste: + { + browser.FocusedFrame.Paste(); + break; + } + case CefMenuCommand.Print: + { + browser.GetHost().Print(); + break; + } + case CefMenuCommand.ViewSource: + { + browser.FocusedFrame.ViewSource(); + break; + } + case CefMenuCommand.Undo: + { + browser.FocusedFrame.Undo(); + break; + } + case CefMenuCommand.StopLoad: + { + browser.StopLoad(); + break; + } + case CefMenuCommand.SelectAll: + { + browser.FocusedFrame.SelectAll(); + break; + } + case CefMenuCommand.Redo: + { + browser.FocusedFrame.Redo(); + break; + } + case CefMenuCommand.Find: + { + browser.GetHost().Find(0, parameters.SelectionText, true, false, false); + break; + } + case CefMenuCommand.AddToDictionary: + { + browser.GetHost().AddWordToDictionary(parameters.MisspelledWord); + break; + } + case CefMenuCommand.Reload: + { + browser.Reload(); + break; + } + case CefMenuCommand.ReloadNoCache: + { + browser.Reload(ignoreCache: true); + break; + } + case (CefMenuCommand)26501: + { + browser.GetHost().ShowDevTools(); + break; + } + case (CefMenuCommand)26502: + { + browser.GetHost().CloseDevTools(); + break; + } + } + }) + }); + } + chromiumWebBrowser.ContextMenu = menu; + }); + + return true; } - private static IEnumerable> GetMenuItems(IMenuModel model) + private static IEnumerable> GetMenuItems(IMenuModel model) { - var list = new List>(); for(var i = 0; i < model.Count; i++) { var header = model.GetLabelAt(i); var commandId = model.GetCommandIdAt(i); - list.Add(new Tuple(header, commandId)); + var isEnabled = model.IsEnabledAt(i); + yield return new Tuple(header, commandId, isEnabled); } - - return list; } } }