最近有小伙伴需要在不规则窗体上放置WebBrowser控件,因为设置了WindowStyle="None" 和 AllowsTransparency="True"。
导致WebBrowser控件不显示。
界面如下所示:
1 <Window x:Class="WebBrowserDemo.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WebBrowserDemo" 7 mc:Ignorable="d" 8 Height="979" Width="1259" 9 WindowStyle="None" ResizeMode="NoResize" Background="Transparent" AllowsTransparency="True" 10 MouseLeftButtonDown="Window_MouseLeftButtonDown" Loaded="Window_Loaded"> 11 <Canvas> 12 <Image Source="background.png" Stretch="Fill" Width="1259" Height="979" /> 13 <WebBrowser x:Name="webBrowser" Width="521" Height="635" Canvas.Left="58" Canvas.Top="198" Address="https://www.baidu.com" HorizontalAlignment="Left" VerticalAlignment="Center"></cef:ChromiumWebBrowser> 14 </Canvas> 15 </Window>
预期效果如下:
但实际浏览器并不会显示出来。
导致这个问题的原因是因为空域(airspace)问题,因为WebBrowser并不是一个原生的WPF控件,而是一个Win32控件。
详细描述可以参考以下两个链接:
https://learn.microsoft.com/en-us/archive/blogs/changov/webbrowser-control-on-transparent-wpf-window
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/technology-regions-overview?view=netframeworkdesktop-4.8&redirectedfrom=MSDN
这里提供三个解决办法
1、将WebBrowser替换为CefSharp/WebView2等原生WPF控件
这种方法最简单,几乎不用修改什么代码,缺点是老版本系统可能不兼容。
2、使用WindowsChrome
1 <WindowChrome.WindowChrome> 2 <WindowChrome GlassFrameThickness="-1"/> 3 </WindowChrome.WindowChrome>
需要配合 ResizeMode="CanMinimize" Background="Transparent" WindowStyle="None" 使用
完整界面代码如下:
1 <Window x:Class="WebBrowserDemo.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WebBrowserDemo" 7 mc:Ignorable="d" 8 ResizeMode="CanMinimize" Background="Transparent" WindowStyle="None" Height="979" Width="1259"> 9 <WindowChrome.WindowChrome> 10 <WindowChrome GlassFrameThickness="-1"/> 11 </WindowChrome.WindowChrome> 12 <Canvas> 13 <Canvas.Background> 14 <ImageBrush ImageSource="background.png" Stretch="Uniform"></ImageBrush> 15 </Canvas.Background> 16 <WebBrowser x:Name="webBrowser" Width="527" Height="501" Canvas.Left="54" Canvas.Top="249" Source="https://bing.com" HorizontalAlignment="Center" VerticalAlignment="Top"></WebBrowser> 17 </Canvas> 18 </Window>
3、将WebBrowser封装到一个独立的窗口,变成独立控件
这个方法来自stackoverflow上的一个老哥,链接如下:
https://stackoverflow.com/questions/23529824/how-do-i-work-around-the-activex-webbrowser-flaw-in-a-wpf-window-that-allowstran
首先我们新建一个Window
WebBrowserEx.xaml
1 <Window x:Class="WebBrowserDemo.Controls.WebBrowserEx" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WebBrowserDemo.Controls" 7 xmlns:winForms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" 8 WindowStyle="None" 9 ShowInTaskbar="False" 10 ResizeMode="NoResize" Width="761" Height="444"> 11 <WindowsFormsHost x:Name="wfh"> 12 <winForms:WebBrowser x:Name="wfBrowser" /> 13 </WindowsFormsHost> 14 </Window>
后台代码如下:
WebBrowserEx.xaml.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents; 10 using System.Windows.Input; 11 using System.Windows.Media; 12 using System.Windows.Media.Imaging; 13 using System.Windows.Shapes; 14 15 namespace WebBrowserDemo.Controls 16 { 17 public partial class WebBrowserEx : Window 18 { 19 public WebBrowserEx() 20 { 21 InitializeComponent(); 22 } 23 24 public static readonly DependencyProperty TargetElementProperty = DependencyProperty.Register("TargetElement", typeof(FrameworkElement), typeof(WebBrowserEx), new PropertyMetadata(TargetElementPropertyChanged)); 25 public FrameworkElement TargetElement 26 { 27 get 28 { 29 return GetValue(TargetElementProperty) as FrameworkElement; 30 } 31 set 32 { 33 SetValue(TargetElementProperty, value); 34 } 35 } 36 37 38 public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(WebBrowserEx), new PropertyMetadata(SourcePropertyChanged)); 39 public string Source 40 { 41 get 42 { 43 return GetValue(SourceProperty) as string; 44 } 45 set 46 { 47 SetValue(SourceProperty, value); 48 } 49 } 50 private static void SourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) 51 { 52 var webBrowserOverlayWindow = sender as WebBrowserEx; 53 54 if (webBrowserOverlayWindow != null) 55 { 56 webBrowserOverlayWindow.wfBrowser.Navigate(args.NewValue as string); 57 } 58 } 59 60 private static void TargetElementPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) 61 { 62 var oldTargetElement = args.OldValue as FrameworkElement; 63 var webBrowserOverlayWindow = sender as WebBrowserEx; 64 var mainWindow = Window.GetWindow(webBrowserOverlayWindow.TargetElement); 65 66 if (webBrowserOverlayWindow != null && mainWindow != null) 67 { 68 webBrowserOverlayWindow.Owner = mainWindow; 69 webBrowserOverlayWindow.Owner.LocationChanged += webBrowserOverlayWindow.PositionAndResize; 70 webBrowserOverlayWindow.TargetElement.LayoutUpdated += webBrowserOverlayWindow.PositionAndResize; 71 72 if (oldTargetElement != null) 73 oldTargetElement.LayoutUpdated -= webBrowserOverlayWindow.PositionAndResize; 74 75 webBrowserOverlayWindow.PositionAndResize(sender, new EventArgs()); 76 77 if (webBrowserOverlayWindow.TargetElement.IsVisible && webBrowserOverlayWindow.Owner.IsVisible) 78 { 79 webBrowserOverlayWindow.Show(); 80 } 81 82 webBrowserOverlayWindow.TargetElement.IsVisibleChanged += (x, y) => 83 { 84 if (webBrowserOverlayWindow.TargetElement.IsVisible && webBrowserOverlayWindow.Owner.IsVisible) 85 { 86 webBrowserOverlayWindow.Show(); 87 } 88 else 89 { 90 webBrowserOverlayWindow.Hide(); 91 } 92 }; 93 } 94 } 95 96 protected override void OnClosed(EventArgs e) 97 { 98 base.OnClosed(e); 99 100 Owner.LocationChanged -= PositionAndResize; 101 if (TargetElement != null) 102 { 103 TargetElement.LayoutUpdated -= PositionAndResize; 104 } 105 } 106 107 private void PositionAndResize(object sender, EventArgs e) 108 { 109 if (TargetElement != null && TargetElement.IsVisible) 110 { 111 var point = TargetElement.PointToScreen(new Point()); 112 Left = point.X + 396; //这里可以控制位置 113 Top = point.Y + 326; //point是左上角0,0的位置 114 115 //Height = TargetElement.ActualHeight; //这里可以控制宽高 116 //Width = TargetElement.ActualWidth; 117 } 118 } 119 120 } 121 }