WPF中Webbrowser控件使用HwndHost所以webbrowser會在所有控件的前方。所以webbrowser會覆蓋所有同級的控件。
現在通過使用Win32API 可以避免這個情況。
最主要的就是這幾個Win32API:
[DllImport("user32.dll")] public static extern bool SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool redraw); [DllImport("gdi32.dll")] public static extern IntPtr CreateRectRgn(int Left, int Top, int RectRightBottom_X, int RectRightBottom_Y); [DllImport("gdi32.dll")] public static extern int CombineRgn(IntPtr hrgnDst, IntPtr hrgnSrc1, IntPtr hrgnSrc2, int iMode);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr objectHandle);
適當說一下:
setwindowrgn就是設置有效繪圖區域。
createrectrgn是創建矩形
combinergn這個就是融合兩個矩形,可以並集,交集以及Src1中不包括Src2的部分,最終結果會在hrgnDst中。
總的來說就是利用webbrowser的父級控件的sizechanged事件來不斷的設置有效繪圖區域。
我就直接上代碼了,
Win32API類
[DllImport("user32.dll")] public static extern bool SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool redraw); /// <summary> /// 創建一個矩形,本來四個參數均為x1 y1 x2 y2 意思為左上角X1,Y1坐標,右下角X2,Y2坐標,但是為了方便WPF使用我則是改了 /// left意味矩形和左邊的距離 /// top意味着矩形和頂邊距離 /// rectrightbottom_x意味着矩形右下角的X坐標 /// rectrightbottom_y意味着矩形右下角的Y坐標 /// </summary> /// <param name="Left"></param> /// <param name="Top"></param> /// <param name="RectRightBottom_X"></param> /// <param name="RectRightBottom_Y"></param> /// <returns></returns> [DllImport("gdi32.dll")] public static extern IntPtr CreateRectRgn(int Left, int Top, int RectRightBottom_X, int RectRightBottom_Y);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr objectHandle);
[DllImport("gdi32.dll")] public static extern int CombineRgn(IntPtr hrgnDst, IntPtr hrgnSrc1, IntPtr hrgnSrc2, int iMode); //合並選項: //RGN_AND = 1; //RGN_OR = 2; //RGN_XOR = 3; //RGN_DIFF = 4; //RGN_COPY = 5; {復制第一個區域}
附加屬性類:
class ATCH { public static readonly DependencyProperty PanelProperty = DependencyProperty.RegisterAttached("Panel", typeof(Panel), typeof(ATCH), new PropertyMetadata(null)); public static void SetPanel(DependencyObject d, Panel value) => d.SetValue(PanelProperty, value); public static Panel GetPanel(DependencyObject d) => (Panel)d.GetValue(PanelProperty); public static readonly DependencyProperty NameProperty = DependencyProperty.RegisterAttached("Name", typeof(FrameworkElement), typeof(ATCH), new PropertyMetadata(null, new PropertyChangedCallback(OnNamePropertyChanged))); public static void SetName(DependencyObject d, FrameworkElement value) => d.SetValue(NameProperty, value); public static FrameworkElement GetName(DependencyObject d) => (FrameworkElement)d.GetValue(NameProperty); private static void OnNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var b = d.GetValue(PanelProperty); if (b is null||! (b is Panel)||e.NewValue is null) return; var panel = b as Panel; var web = d as WebBrowser; var ui = e.NewValue as FrameworkElement; SetRect(panel, web, ui); panel.SizeChanged += (sender, args) => { SetRect(panel, web, ui); }; } private static IntPtr C1; private static void SetRect(Panel panel, WebBrowser web, FrameworkElement ui) { IntPtr handle = web.Handle; Win32API.DeleteObject(C1); Win32API.SetWindowRgn(handle, IntPtr.Zero, true); Rect PanelRect = new Rect(new Size(panel.ActualWidth, panel.ActualHeight)); C1 = Win32API.CreateRectRgn((int)0, (int)0, (int)PanelRect.BottomRight.X, (int)PanelRect.BottomRight.Y); Rect UIRect = new Rect(new Size(ui.ActualWidth, ui.ActualHeight)); var D1 = (int)ui.TransformToAncestor(panel).Transform(new Point(0, 0)).X; var D2 = (int)ui.TransformToAncestor(panel).Transform(new Point(0, 0)).Y; var D3 = (int)(D1 + UIRect.Width); var D4 = (int)(D2 + UIRect.Height); var C2 = Win32API.CreateRectRgn(D1, D2, D3, D4); Win32API.CombineRgn(C1, C1, C2, 4); Win32API.SetWindowRgn(handle, C1, true); } }
xaml代碼
<Grid> <WebBrowser Source="http://www.baidu.com" local:ATCH.Panel="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=Grid}}" local:ATCH.Name="{Binding ElementName=btn}"/> <Button x:Name="btn" Height="50" Width="100" Content="覆蓋測試" /> </Grid>
截圖1:
截圖2: