最近有小伙伴需要在不规则窗体上放置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控件。
详细描述可以参考以下两个链接:
WebBrowser control on transparent WPF window | Microsoft Learn
Technology Regions Overview - WPF .NET Framework | Microsoft Learn
这里提供三个解决办法
1、将WebBrowser控件替换为CefSharp/WebView2等控件
这种方法最简单,几乎不用修改什么代码,缺点是老版本系统可能不兼容。
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上的一个老哥,链接如下:
- 首先我们新建一个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 }
- 然后我们新建一个自定义控件
CustomWebBrowser.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.Navigation;
14 using System.Windows.Shapes;
15
16 namespace WebBrowserDemo.Controls
17 {
18 public class CustomWebBrowser : Control
19 {
20
21 private WebBrowserEx _WebBrowserOverlayWindow;
22 public static readonly DependencyProperty TargetElementProperty = DependencyProperty.Register("TargetElement", typeof(FrameworkElement), typeof(CustomWebBrowser), new PropertyMetadata(TargetElementPropertyChanged));
23 public FrameworkElement TargetElement
24 {
25 get
26 {
27 return GetValue(TargetElementProperty) as FrameworkElement;
28 }
29 set
30 {
31 SetValue(TargetElementProperty, value);
32 }
33 }
34
35 public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(CustomWebBrowser), new PropertyMetadata(SourcePropertyChanged));
36 public string Source
37 {
38 get
39 {
40 return GetValue(SourceProperty) as string;
41 }
42 set
43 {
44 SetValue(SourceProperty, value);
45 }
46 }
47
48 private static void SourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
49 {
50 var transparentWebBrowser = sender as CustomWebBrowser;
51 if (transparentWebBrowser != null)
52 {
53 transparentWebBrowser._WebBrowserOverlayWindow.Source = args.NewValue as string;
54 }
55 }
56
57 private static void TargetElementPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
58 {
59 var transparentWebBrowser = sender as CustomWebBrowser;
60 if (transparentWebBrowser != null)
61 {
62 transparentWebBrowser._WebBrowserOverlayWindow.TargetElement = args.NewValue as FrameworkElement;
63 }
64 }
65
66 public CustomWebBrowser()
67 {
68 _WebBrowserOverlayWindow = new WebBrowserEx();
69 }
70
71 static CustomWebBrowser()
72 {
73 DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomWebBrowser), new FrameworkPropertyMetadata(typeof(CustomWebBrowser)));
74 }
75 }
76 }
- 自定义控件样式如下
1 <Style TargetType="{x:Type local:CustomWebBrowser}">
2 <Setter Property="Template">
3 <Setter.Value>
4 <ControlTemplate TargetType="{x:Type local:CustomWebBrowser}">
5 <Border Background="{TemplateBinding Background}"
6 BorderBrush="{TemplateBinding BorderBrush}"
7 BorderThickness="{TemplateBinding BorderThickness}">
8 </Border>
9 </ControlTemplate>
10 </Setter.Value>
11 </Setter>
12 </Style>
- 使用时将WebBrowser控件换成CustomWebBrowser即可。