基於 WPF、VS2008 SP1 實現。
WinForms 只需設 Opacity 或 TransparencyKey。WPF 中設 Window.Opacity 會導致 WebBrowser 整體消失——這是 「空域」問題:WPF 像素與 Win32 HWND 像素無法正確混合。
參考:MSDN Blog
真正透明難實現,但可做到視覺融合:將網頁背景繪製為被 WebBrowser 覆蓋區域的「應用程式背景截圖」,欺騙眼睛以為透明。
實作 IElementBehavior、IHTMLPainter 掛載至 <body>,在 Draw() 中繪製背景:
[ComVisible(true), Guid("0015EC28-C85F-49a8-9B1A-DC91E6345274"), ClassInterface(ClassInterfaceType.AutoDispatch)]
public class MyGadgetBodyBehavior : IElementBehavior, IHTMLPainter
{
public void Draw(RECT rcBounds, RECT rcUpdates, int lDrawFlags, IntPtr hdc, IntPtr pvDrawObject)
{
using (var g = Graphics.FromHdc(hdc))
using (var buffer = new Bitmap(width, height))
using (var gBuffer = Graphics.FromImage(buffer))
{
// 1. 截取應用程式背景
var image = snapHelper.GetScreenSnap();
gBuffer.DrawImage(image.Bitmap, 0, 0);
image.Dispose();
// 2. 處理 CSS background-image
string imageSrc = ((IHTMLElement2)body).currentStyle.backgroundImage;
if (!string.IsNullOrEmpty(imageSrc))
{
var match = Regex.Match(imageSrc, @"url(""file:///(?.*)"")");
if (match.Success)
{
imageSrc = match.Groups["path"].Value;
using (var bitmap = new Bitmap(imageSrc))
gBuffer.DrawImage(bitmap, new Rectangle(0, 0, width, height));
}
}
// 3. 只繪製更新區域
g.DrawImage(buffer, rcUpdates.left, rcUpdates.top,
new Rectangle(rcUpdates.left - rcBounds.left, rcUpdates.top - rcBounds.top,
rcUpdates.right - rcUpdates.left, rcUpdates.bottom - rcUpdates.top),
GraphicsUnit.Pixel);
}
}
}
internal Image GetScreenSnap(bool isForceRefresh)
{
if (CheckPositionAndSize() && !isForceRefresh) return screenImage;
control.Visibility = Visibility.Hidden; // 隱藏 WebBrowser
var bitmap = new RenderTargetBitmap((int)parentWindow.Width, (int)parentWindow.Height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(parentWindow); // 截取整個視窗
var bitmapSource = bitmap.CloneCurrentValue();
var newBitmap = ConvertSourceImageToBitmap(bitmapSource);
newBitmap = ClipBitmap(newBitmap, new System.Drawing.Rectangle((int)oldPoint.X, (int)oldPoint.Y,
(int)control.Width, (int)control.Height));
control.Visibility = Visibility.Visible; // 恢復顯示
screenImage = new Image(newBitmap, imagePtr);
return screenImage;
}
技巧:截圖前隱藏 WebBrowser,否則會截到自身內容。
本文附配套源碼。