From afd1fd9a6a4ac125c06540e506decb692535dbd3 Mon Sep 17 00:00:00 2001 From: amaitland <307872+amaitland@users.noreply.github.com> Date: Sat, 16 Nov 2024 11:15:09 +1000 Subject: [PATCH 01/12] HwndHost - Initial import --- CefSharp.Wpf.HwndHost.Example/App.config | 6 + CefSharp.Wpf.HwndHost.Example/App.xaml | 11 + CefSharp.Wpf.HwndHost.Example/App.xaml.cs | 62 + CefSharp.Wpf.HwndHost.Example/AssemblyInfo.cs | 14 + .../Behaviours/HoverLinkBehaviour.cs | 34 + .../TextBoxBindingUpdateOnEnterBehaviour.cs | 28 + .../CefSharp.Wpf.HwndHost.Example.csproj | 40 + .../Converter/EnvironmentConverter.cs | 19 + .../Converter/TitleConverter.cs | 19 + .../Handlers/DisplayHandler.cs | 53 + CefSharp.Wpf.HwndHost.Example/MainWindow.xaml | 86 + .../MainWindow.xaml.cs | 26 + .../TabbedMainWindow.xaml | 13 + .../TabbedMainWindow.xaml.cs | 41 + CefSharp.Wpf.HwndHost.Example/app.manifest | 77 + .../crash_reporter.cfg | 12 + CefSharp.Wpf/HwndHost/CefSettings.cs | 26 + CefSharp.Wpf/HwndHost/ChromiumWebBrowser.cs | 1967 +++++++++++++++++ CefSharp.Wpf/HwndHost/FocusHandler.cs | 84 + ...egratedMessageLoopBrowserProcessHandler.cs | 131 ++ CefSharp.Wpf/HwndHost/IWpfWebBrowser.cs | 143 ++ .../HwndHost/Internals/DelegateCommand.cs | 68 + .../Internals/NoCloseLifespanHandler.cs | 26 + 23 files changed, 2986 insertions(+) create mode 100644 CefSharp.Wpf.HwndHost.Example/App.config create mode 100644 CefSharp.Wpf.HwndHost.Example/App.xaml create mode 100644 CefSharp.Wpf.HwndHost.Example/App.xaml.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/AssemblyInfo.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/Behaviours/HoverLinkBehaviour.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/Behaviours/TextBoxBindingUpdateOnEnterBehaviour.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/CefSharp.Wpf.HwndHost.Example.csproj create mode 100644 CefSharp.Wpf.HwndHost.Example/Converter/EnvironmentConverter.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/Converter/TitleConverter.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/Handlers/DisplayHandler.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/MainWindow.xaml create mode 100644 CefSharp.Wpf.HwndHost.Example/MainWindow.xaml.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/TabbedMainWindow.xaml create mode 100644 CefSharp.Wpf.HwndHost.Example/TabbedMainWindow.xaml.cs create mode 100644 CefSharp.Wpf.HwndHost.Example/app.manifest create mode 100644 CefSharp.Wpf.HwndHost.Example/crash_reporter.cfg create mode 100644 CefSharp.Wpf/HwndHost/CefSettings.cs create mode 100644 CefSharp.Wpf/HwndHost/ChromiumWebBrowser.cs create mode 100644 CefSharp.Wpf/HwndHost/FocusHandler.cs create mode 100644 CefSharp.Wpf/HwndHost/Handler/IntegratedMessageLoopBrowserProcessHandler.cs create mode 100644 CefSharp.Wpf/HwndHost/IWpfWebBrowser.cs create mode 100644 CefSharp.Wpf/HwndHost/Internals/DelegateCommand.cs create mode 100644 CefSharp.Wpf/HwndHost/Internals/NoCloseLifespanHandler.cs diff --git a/CefSharp.Wpf.HwndHost.Example/App.config b/CefSharp.Wpf.HwndHost.Example/App.config new file mode 100644 index 0000000000..1e8988739d --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/CefSharp.Wpf.HwndHost.Example/App.xaml b/CefSharp.Wpf.HwndHost.Example/App.xaml new file mode 100644 index 0000000000..4f5c756edb --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/App.xaml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/CefSharp.Wpf.HwndHost.Example/App.xaml.cs b/CefSharp.Wpf.HwndHost.Example/App.xaml.cs new file mode 100644 index 0000000000..75ba9e1c93 --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/App.xaml.cs @@ -0,0 +1,62 @@ +// Copyright © 2019 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System; +using System.IO; +using System.Windows; +using CefSharp.Wpf.HwndHost.Handler; + +namespace CefSharp.Wpf.HwndHost.Example +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public App() + { +#if !NETCOREAPP3_1 + CefRuntime.SubscribeAnyCpuAssemblyResolver(); +#endif + } + + protected override void OnStartup(StartupEventArgs e) + { + var settings = new CefSettings() + { + //By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data + CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache") + }; + + //Example of setting a command line argument + //Enables WebRTC + // - CEF Doesn't currently support permissions on a per browser basis see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access + // - CEF Doesn't currently support displaying a UI for media access permissions + // + //NOTE: WebRTC Device Id's aren't persisted as they are in Chrome see https://bitbucket.org/chromiumembedded/cef/issues/2064/persist-webrtc-deviceids-across-restart + settings.CefCommandLineArgs.Add("enable-media-stream"); + //https://peter.sh/experiments/chromium-command-line-switches/#use-fake-ui-for-media-stream + settings.CefCommandLineArgs.Add("use-fake-ui-for-media-stream"); + //For screen sharing add (see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access#comment-58677180) + settings.CefCommandLineArgs.Add("enable-usermedia-screen-capturing"); + + //See https://github.com/cefsharp/CefSharp/wiki/General-Usage#multithreadedmessageloop + //The default is true + const bool multiThreadedMessageLoop = true; + + IBrowserProcessHandler browserProcessHandler = null; + + if(!multiThreadedMessageLoop) + { + settings.MultiThreadedMessageLoop = false; + browserProcessHandler = new IntegratedMessageLoopBrowserProcessHandler(Dispatcher); + } + + // Make sure you set performDependencyCheck false + Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: browserProcessHandler); + + base.OnStartup(e); + } + } +} diff --git a/CefSharp.Wpf.HwndHost.Example/AssemblyInfo.cs b/CefSharp.Wpf.HwndHost.Example/AssemblyInfo.cs new file mode 100644 index 0000000000..ed33db9bfa --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/AssemblyInfo.cs @@ -0,0 +1,14 @@ +// Copyright © 2019 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/CefSharp.Wpf.HwndHost.Example/Behaviours/HoverLinkBehaviour.cs b/CefSharp.Wpf.HwndHost.Example/Behaviours/HoverLinkBehaviour.cs new file mode 100644 index 0000000000..1fc77b3656 --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/Behaviours/HoverLinkBehaviour.cs @@ -0,0 +1,34 @@ +using System.Windows; +using System; +using Microsoft.Xaml.Behaviors; + +namespace CefSharp.Wpf.HwndHost.Example.Behaviours +{ + public class HoverLinkBehaviour : Behavior + { + // Using a DependencyProperty as the backing store for HoverLink. This enables animation, styling, binding, etc... + public static readonly DependencyProperty HoverLinkProperty = DependencyProperty.Register("HoverLink", typeof(string), typeof(HoverLinkBehaviour), new PropertyMetadata(string.Empty)); + + public string HoverLink + { + get { return (string)GetValue(HoverLinkProperty); } + set { SetValue(HoverLinkProperty, value); } + } + + protected override void OnAttached() + { + AssociatedObject.StatusMessage += OnStatusMessageChanged; + } + + protected override void OnDetaching() + { + AssociatedObject.StatusMessage -= OnStatusMessageChanged; + } + + private void OnStatusMessageChanged(object sender, StatusMessageEventArgs e) + { + var chromiumWebBrowser = sender as ChromiumWebBrowser; + chromiumWebBrowser.Dispatcher.BeginInvoke((Action)(() => HoverLink = e.Value)); + } + } +} diff --git a/CefSharp.Wpf.HwndHost.Example/Behaviours/TextBoxBindingUpdateOnEnterBehaviour.cs b/CefSharp.Wpf.HwndHost.Example/Behaviours/TextBoxBindingUpdateOnEnterBehaviour.cs new file mode 100644 index 0000000000..24ad3b4e7a --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/Behaviours/TextBoxBindingUpdateOnEnterBehaviour.cs @@ -0,0 +1,28 @@ +using System.Windows.Controls; +using System.Windows.Input; +using Microsoft.Xaml.Behaviors; + +namespace CefSharp.Wpf.HwndHost.Example.Behaviours +{ + public class TextBoxBindingUpdateOnEnterBehaviour : Behavior + { + protected override void OnAttached() + { + AssociatedObject.KeyDown += OnTextBoxKeyDown; + } + + protected override void OnDetaching() + { + AssociatedObject.KeyDown -= OnTextBoxKeyDown; + } + + private void OnTextBoxKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + var txtBox = sender as TextBox; + txtBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); + } + } + } +} diff --git a/CefSharp.Wpf.HwndHost.Example/CefSharp.Wpf.HwndHost.Example.csproj b/CefSharp.Wpf.HwndHost.Example/CefSharp.Wpf.HwndHost.Example.csproj new file mode 100644 index 0000000000..b9079bd985 --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/CefSharp.Wpf.HwndHost.Example.csproj @@ -0,0 +1,40 @@ + + + WinExe + true + netcoreapp3.1;net462 + CefSharp.Wpf.HwndHost.Example + true + CefSharp.Wpf.HwndHost.Example.App + AnyCPU + app.manifest + 9.0 + + + + win-x64 + false + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + PreserveNewest + + + + + + + diff --git a/CefSharp.Wpf.HwndHost.Example/Converter/EnvironmentConverter.cs b/CefSharp.Wpf.HwndHost.Example/Converter/EnvironmentConverter.cs new file mode 100644 index 0000000000..a5564df204 --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/Converter/EnvironmentConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace CefSharp.Wpf.HwndHost.Example.Converter +{ + public class EnvironmentConverter : IValueConverter + { + object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return Environment.Is64BitProcess ? "x64" : "x86"; + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return Binding.DoNothing; + } + } +} diff --git a/CefSharp.Wpf.HwndHost.Example/Converter/TitleConverter.cs b/CefSharp.Wpf.HwndHost.Example/Converter/TitleConverter.cs new file mode 100644 index 0000000000..60333176e4 --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/Converter/TitleConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace CefSharp.Wpf.HwndHost.Example.Converter +{ + public class TitleConverter : IValueConverter + { + object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return "CefSharp.MinimalExample.Wpf.HwndHost - " + (value ?? "No Title Specified"); + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return Binding.DoNothing; + } + } +} diff --git a/CefSharp.Wpf.HwndHost.Example/Handlers/DisplayHandler.cs b/CefSharp.Wpf.HwndHost.Example/Handlers/DisplayHandler.cs new file mode 100644 index 0000000000..48b8f6c812 --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/Handlers/DisplayHandler.cs @@ -0,0 +1,53 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace CefSharp.Wpf.HwndHost.Example.Handlers +{ + public class DisplayHandler : CefSharp.Handler.DisplayHandler + { + private Border parent; + private Window fullScreenWindow; + + protected override void OnFullscreenModeChange(IWebBrowser chromiumWebBrowser, IBrowser browser, bool fullscreen) + { + var webBrowser = (ChromiumWebBrowser)chromiumWebBrowser; + + _ = webBrowser.Dispatcher.InvokeAsync(() => + { + if (fullscreen) + { + //In this example the parent is a Border, if your parent is a different type + //of control then update this code accordingly. + parent = (Border)VisualTreeHelper.GetParent(webBrowser); + + //NOTE: If the ChromiumWebBrowser instance doesn't have a direct reference to + //the DataContext in this case the BrowserTabViewModel then your bindings won't + //be updated/might cause issues like the browser reloads the Url when exiting + //fullscreen. + parent.Child = null; + + fullScreenWindow = new Window + { + WindowStyle = WindowStyle.None, + WindowState = WindowState.Maximized, + Content = webBrowser + }; + fullScreenWindow.Loaded += (_,_) => webBrowser.Focus(); + + fullScreenWindow.ShowDialog(); + } + else + { + fullScreenWindow.Content = null; + + parent.Child = webBrowser; + + fullScreenWindow.Close(); + fullScreenWindow = null; + parent = null; + } + }); + } + } +} diff --git a/CefSharp.Wpf.HwndHost.Example/MainWindow.xaml b/CefSharp.Wpf.HwndHost.Example/MainWindow.xaml new file mode 100644 index 0000000000..4bc266f3a3 --- /dev/null +++ b/CefSharp.Wpf.HwndHost.Example/MainWindow.xaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + +