wpf 覆盖元素在webview2之上 - 优化
备注
原有提供的覆盖元素在webview2的方案性能较差(https://www.cnblogs.com/ives/p/17719809.html)
寻找后发现一个新的方案性能较高。此方案无需重写webview2相关事件而是通过样式绑定到新的组件中,可以保留原有代码只需要极少的改动即可适配。
帮助类SupportControl
using System.Windows;
using System.Windows.Controls;
namespace CraesUmfp.Component.CtrlFolder
{
public class SupportControl : UserControl
{
private readonly SupportWnd _alpha;
public SupportControl()
{
_alpha = new SupportWnd(this);
}
public static readonly DependencyProperty BackProperty = DependencyProperty.Register("Back", typeof(UIElement),
typeof(SupportControl), new PropertyMetadata(default(UIElement), BackChangedCallback));
private static void BackChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is SupportControl control))
return;
var argsNewValue = e.NewValue;
if (argsNewValue is UIElement element)
{
control.BackChange(element);
}
}
public UIElement Back
{
get => (UIElement)GetValue(BackProperty);
set => SetValue(BackProperty, value);
}
private void BackChange(UIElement value)
{
this.Content = value;
}
public static readonly DependencyProperty FrontProperty = DependencyProperty.Register("Front", typeof(UIElement),
typeof(SupportControl), new PropertyMetadata(default(UIElement), FrontChangedCallback));
private static void FrontChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is SupportControl control))
return;
var argsNewValue = e.NewValue;
if (argsNewValue is UIElement element)
{
control.FrontChange(element);
}
}
public UIElement Front
{
get => (UIElement)GetValue(FrontProperty);
set => SetValue(FrontProperty, value);
}
private void FrontChange(UIElement value)
{
_alpha.FrontContent = value;
}
}
}
帮助类
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace CraesUmfp.Component.CtrlFolder
{
internal class SupportWnd : Window
{
private Window _wndHost;
private readonly UserControl _backControl;
private UIElement _frontContent;
private readonly Point _basePoint;
internal SupportWnd(UserControl backControl) : base()
{
_basePoint = new Point();
Background = new SolidColorBrush(Color.FromArgb(0, 255, 255, 255));
AllowsTransparency = true;
ResizeMode = ResizeMode.NoResize;
ShowInTaskbar = false;
WindowStyle = WindowStyle.None;
_backControl = backControl;
_backControl.Loaded += BackgroundLoaded;
_backControl.LayoutUpdated += BackgroundLayoutUpdated;
_backControl.Unloaded += BackgroundUnloaded;
}
public UIElement FrontContent
{
get => _frontContent;
set
{
_frontContent = value;
Content = value;
}
}
private void BackgroundUnloaded(object sender, RoutedEventArgs e)
{
_wndHost.Closing -= WndHost_Closing;
_wndHost.SizeChanged -= WndHost_SizeChanged;
_wndHost.LocationChanged -= WndHost_LocationChanged;
this.Hide();
}
private static double GetSourceScaleX(PresentationSource source)
{
var compositionTarget = source?.CompositionTarget;
if (compositionTarget is null)
return 1;
var transformToDevice = compositionTarget.TransformToDevice;
return transformToDevice.M11;
}
private static double GetSourceScaleY(PresentationSource source)
{
var compositionTarget = source?.CompositionTarget;
if (compositionTarget is null)
return 1;
var transformToDevice = compositionTarget.TransformToDevice;
return transformToDevice.M22;
}
private void UpdateOwnPosition()
{
if (_wndHost == null || !_backControl.IsVisible)
{
return;
}
var locationFromScreen = _backControl.PointToScreen(_basePoint);
var source = PresentationSource.FromVisual(_wndHost);
var compositionTarget = source?.CompositionTarget;
if (compositionTarget is null)
return;
var fromDevice = compositionTarget.TransformFromDevice;
var targetPoints = fromDevice.Transform(locationFromScreen);
this.Left = targetPoints.X;
this.Top = targetPoints.Y;
}
private void UpdateOwnSize()
{
if (_wndHost == null || !_backControl.IsVisible)
{
return;
}
var source = PresentationSource.FromVisual(_wndHost);
var backActualWidth = _backControl.ActualWidth;
var backActualHeight = _backControl.ActualHeight;
var point = new Point(backActualWidth, backActualHeight);
var last = _backControl.PointToScreen(point);
var first = _backControl.PointToScreen(_basePoint);
var size = last - first;
var sourceScaleY = GetSourceScaleY(source);
this.Height = size.Y / sourceScaleY;
var sourceScaleX = GetSourceScaleX(source);
this.Width = size.X / sourceScaleX;
}
private void BackgroundLoaded(object sender, RoutedEventArgs e)
{
_wndHost = GetWindow(_backControl);
this.Owner = _wndHost;
if (_wndHost is null)
return;
_wndHost.Closing += WndHost_Closing;
_wndHost.SizeChanged += WndHost_SizeChanged;
_wndHost.LocationChanged += WndHost_LocationChanged;
try
{
this.Show();
_wndHost.Focus();
}
catch
{
this.Hide();
}
}
private void BackgroundLayoutUpdated(object sender, EventArgs e)
{
UpdateOwnPosition();
UpdateOwnSize();
}
private void WndHost_LocationChanged(object sender, EventArgs e)
{
UpdateOwnPosition();
}
private void WndHost_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateOwnPosition();
UpdateOwnSize();
}
private void WndHost_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.Close();
}
}
}
使用
<UserControl.Resources>
<wpf:WebView2 x:Key="WebViewKey"
Name="webView"
Initialized="webView_Initialized" CoreWebView2InitializationCompleted="webView_CoreWebView2InitializationCompleted"/>
<offlinemap:OfflineMapSaveDialog x:Key="StackPaneCtrlKey" />
</UserControl.Resources>
<Grid>
<ctrlFolder:SupportControl x:Name="SupportControlName"
Back="{StaticResource WebViewKey}"
Front="{StaticResource StackPaneCtrlKey}" />
</Grid>
留待后查,同时方便他人
联系我:renhanlinbsl@163.com
联系我:renhanlinbsl@163.com