using System.Windows.Controls; using System.Windows.Threading; using Microsoft.Extensions.DependencyInjection; using Microsoft.Web.WebView2.Core; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.WebView; public sealed partial class DUI3ControlWebView : UserControl, IBrowserScriptExecutor, IDisposable { private readonly IServiceProvider _serviceProvider; public DUI3ControlWebView(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; InitializeComponent(); Browser.CoreWebView2InitializationCompleted += (sender, args) => _serviceProvider .GetRequiredService() .CatchUnhandled(() => OnInitialized(sender, args)); } public bool IsBrowserInitialized => Browser.IsInitialized; public object BrowserElement => Browser; // { // if (!Browser.IsInitialized) // { // throw new InvalidOperationException("Failed to execute script, Webview2 is not initialized yet."); // } // // var t = Browser.Dispatcher.Invoke( // async () => // { // var res = await Browser.ExecuteScriptAsync(script).ConfigureAwait(true); // await Task.Delay(100).ConfigureAwait(true); // return res; // }, // DispatcherPriority.Background // ); // // _ = t.IsCompleted; // bool isAlreadyMainThread = Browser.Dispatcher.CheckAccess(); // if (isAlreadyMainThread) // { // Browser.ExecuteScriptAsync(script); // } // else // { // Browser.Dispatcher.Invoke( // () => // { // return Browser.ExecuteScriptAsync(script); // }, // DispatcherPriority.Background // ); // } // } public async Task ExecuteScriptAsyncMethod(string script, CancellationToken cancellationToken) { if (!Browser.IsInitialized) { throw new InvalidOperationException("Failed to execute script, Webview2 is not initialized yet."); } var callbackTask = await Browser .Dispatcher.InvokeAsync( async () => await Browser.ExecuteScriptAsync(script).ConfigureAwait(false), DispatcherPriority.Background, cancellationToken ) .Task.ConfigureAwait(false); _ = await callbackTask.ConfigureAwait(false); } private void OnInitialized(object? sender, CoreWebView2InitializationCompletedEventArgs e) { if (!e.IsSuccess) { throw new InvalidOperationException("Webview Failed to initialize", e.InitializationException); } // We use Lazy here to delay creating the binding until after the Browser is fully initialized. // Otherwise the Browser cannot respond to any requests to ExecuteScriptAsyncMethod foreach (var binding in _serviceProvider.GetRequiredService>()) { SetupBinding(binding); } } /// /// This must be called on the Main thread /// private void SetupBinding(IBinding binding) { binding.Parent.AssociateWithBinding(binding); Browser.CoreWebView2.AddHostObjectToScript(binding.Name, binding.Parent); } public void ShowDevTools() => Browser.CoreWebView2.OpenDevToolsWindow(); //https://github.com/MicrosoftEdge/WebView2Feedback/issues/2161 public void Dispose() => Browser.Dispatcher.Invoke(() => Browser.Dispose(), DispatcherPriority.Send); }