diff --git a/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs b/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs index ba8e1e6263bb..c34d8ceaa5bb 100644 --- a/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs +++ b/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs @@ -5,7 +5,7 @@ using WebView2Control = Microsoft.Web.WebView2.WinForms.WebView2; #elif WEBVIEW2_WPF using Microsoft.Web.WebView2.Core; -using WebView2Control = Microsoft.Web.WebView2.Wpf.WebView2CompositionControl; +using WebView2Control = Microsoft.Web.WebView2.Wpf.IWebView2; #elif WINDOWS && WEBVIEW2_MAUI using Microsoft.Web.WebView2.Core; using WebView2Control = Microsoft.UI.Xaml.Controls.WebView2; diff --git a/src/BlazorWebView/src/SharedSource/WebView2WebViewManager.cs b/src/BlazorWebView/src/SharedSource/WebView2WebViewManager.cs index 132f746c02b3..f0087a9e3e68 100644 --- a/src/BlazorWebView/src/SharedSource/WebView2WebViewManager.cs +++ b/src/BlazorWebView/src/SharedSource/WebView2WebViewManager.cs @@ -28,7 +28,7 @@ using Microsoft.AspNetCore.Components.WebView.Wpf; using Microsoft.Extensions.DependencyInjection; using Microsoft.Web.WebView2.Core; -using WebView2Control = Microsoft.Web.WebView2.Wpf.WebView2CompositionControl; +using WebView2Control = Microsoft.Web.WebView2.Wpf.IWebView2; using System.Reflection; #elif WEBVIEW2_MAUI using Microsoft.AspNetCore.Components.WebView.Maui; diff --git a/src/BlazorWebView/src/Wpf/BlazorWebView.cs b/src/BlazorWebView/src/Wpf/BlazorWebView.cs index e811f1dee101..bd9cafb318a1 100644 --- a/src/BlazorWebView/src/Wpf/BlazorWebView.cs +++ b/src/BlazorWebView/src/Wpf/BlazorWebView.cs @@ -16,7 +16,9 @@ using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using WebView2Control = Microsoft.Web.WebView2.Wpf.WebView2CompositionControl; +using IWebView2 = Microsoft.Web.WebView2.Wpf.IWebView2; +using WebView2CompositionControl = Microsoft.Web.WebView2.Wpf.WebView2CompositionControl; +using WebView2Control = Microsoft.Web.WebView2.Wpf.WebView2; namespace Microsoft.AspNetCore.Components.WebView.Wpf { @@ -85,10 +87,19 @@ public class BlazorWebView : Control, IAsyncDisposable propertyType: typeof(EventHandler), ownerType: typeof(BlazorWebView)); + /// + /// The backing store for the property. + /// + public static readonly DependencyProperty UseCompositionControlProperty = DependencyProperty.Register( + name: nameof(UseCompositionControl), + propertyType: typeof(bool), + ownerType: typeof(BlazorWebView), + typeMetadata: new PropertyMetadata(true, OnUseCompositionControlPropertyChanged)); + #endregion private const string WebViewTemplateChildName = "WebView"; - private WebView2Control? _webview; + private IWebView2? _webview; private WebView2WebViewManager? _webviewManager; private bool _isDisposed; @@ -113,23 +124,24 @@ public BlazorWebView() SetValue(RootComponentsProperty, new RootComponentsCollection()); RootComponents.CollectionChanged += HandleRootComponentsCollectionChanged; - Template = new ControlTemplate - { - VisualTree = new FrameworkElementFactory(typeof(WebView2Control), WebViewTemplateChildName) - }; + // Default to the composition control; OnUseCompositionControlPropertyChanged will + // update this if UseCompositionControl is set to false before the control is initialized. + Template = CreateWebViewTemplate(useComposition: UseCompositionControl); ApplyTabNavigation(IsTabStop); } /// - /// Returns the inner used by this control. + /// Returns the inner used by this control. + /// When is (the default), this is a + /// ; otherwise it is a . /// /// /// Directly using some functionality of the inner web view can cause unexpected results because its behavior /// is controlled by the that is hosting it. /// [Browsable(false)] - public WebView2Control WebView => _webview!; + public IWebView2 WebView => _webview!; /// /// Path to the host page within the application's static files. For example, wwwroot\index.html. @@ -195,6 +207,23 @@ public IServiceProvider Services set => SetValue(ServicesProperty, value); } + /// + /// Gets or sets a value indicating whether to use the composition-based , + /// which resolves WPF airspace issues at the cost of additional rendering overhead, or the standard + /// for better performance in scenarios where airspace layering is not required. + /// Defaults to . + /// + /// + /// This property must be set before the control is initialized (e.g., in XAML or before adding the control to + /// the visual tree). Changing it after the underlying WebView2 has been created will throw an + /// . + /// + public bool UseCompositionControl + { + get => (bool)GetValue(UseCompositionControlProperty); + set => SetValue(UseCompositionControlProperty, value); + } + private static void OnServicesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((BlazorWebView)d).OnServicesPropertyChanged(e); private void OnServicesPropertyChanged(DependencyPropertyChangedEventArgs e) => StartWebViewCoreIfPossible(); @@ -203,6 +232,28 @@ public IServiceProvider Services private void OnHostPagePropertyChanged(DependencyPropertyChangedEventArgs e) => StartWebViewCoreIfPossible(); + private static void OnUseCompositionControlPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((BlazorWebView)d).OnUseCompositionControlPropertyChanged(e); + + private void OnUseCompositionControlPropertyChanged(DependencyPropertyChangedEventArgs e) + { + if (_webview != null) + { + throw new InvalidOperationException( + $"The {nameof(UseCompositionControl)} property cannot be changed after the underlying WebView has been created."); + } + + Template = CreateWebViewTemplate(useComposition: (bool)e.NewValue); + } + + private static ControlTemplate CreateWebViewTemplate(bool useComposition) + { + var controlType = useComposition ? typeof(WebView2CompositionControl) : typeof(WebView2Control); + return new ControlTemplate + { + VisualTree = new FrameworkElementFactory(controlType, WebViewTemplateChildName) + }; + } + private static void OnIsTabStopPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((BlazorWebView)d).OnIsTabStopPropertyChanged(e); private void OnIsTabStopPropertyChanged(DependencyPropertyChangedEventArgs e) => ApplyTabNavigation((bool)e.NewValue); @@ -228,7 +279,11 @@ public override void OnApplyTemplate() if (_webview == null) { - _webview = (WebView2Control)GetTemplateChild(WebViewTemplateChildName); + if (GetTemplateChild(WebViewTemplateChildName) is not IWebView2 webView) + { + throw new InvalidOperationException($"Template child '{WebViewTemplateChildName}' was not found or does not implement {nameof(IWebView2)}. Ensure the control template contains a WebView2 or WebView2CompositionControl element named '{WebViewTemplateChildName}'."); + } + _webview = webView; StartWebViewCoreIfPossible(); } } @@ -392,7 +447,7 @@ await _webviewManager.DisposeAsync() _webviewManager = null; } - _webview?.Dispose(); + (_webview as IDisposable)?.Dispose(); _webview = null; } diff --git a/src/BlazorWebView/src/Wpf/PublicAPI.Unshipped.txt b/src/BlazorWebView/src/Wpf/PublicAPI.Unshipped.txt index 7dc5c58110bf..e2e393ae5c9e 100644 --- a/src/BlazorWebView/src/Wpf/PublicAPI.Unshipped.txt +++ b/src/BlazorWebView/src/Wpf/PublicAPI.Unshipped.txt @@ -1 +1,8 @@ #nullable enable +*REMOVED*~Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializedEventArgs.WebView.get -> Microsoft.Web.WebView2.Wpf.WebView2CompositionControl +*REMOVED*Microsoft.AspNetCore.Components.WebView.Wpf.BlazorWebView.WebView.get -> Microsoft.Web.WebView2.Wpf.WebView2CompositionControl! +~Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializedEventArgs.WebView.get -> Microsoft.Web.WebView2.Wpf.IWebView2 +Microsoft.AspNetCore.Components.WebView.Wpf.BlazorWebView.UseCompositionControl.get -> bool +Microsoft.AspNetCore.Components.WebView.Wpf.BlazorWebView.UseCompositionControl.set -> void +Microsoft.AspNetCore.Components.WebView.Wpf.BlazorWebView.WebView.get -> Microsoft.Web.WebView2.Wpf.IWebView2! +static readonly Microsoft.AspNetCore.Components.WebView.Wpf.BlazorWebView.UseCompositionControlProperty -> System.Windows.DependencyProperty! \ No newline at end of file