首先先看一下效果圖:
本實現是基於WPF,VS版本2008 SP1。
先說一下在Winform中的實現方法:很簡單通過設置窗體的opacity來實現,或者還可以設置TransparentKey來實現某種顏色透明。但是在WPF中則如何實現呢?
通過設置窗體的opacity,那麼得到結果就是webbrowser整體消失了。因為這裡面涉及到WPF中“空域”的問題,相關的文章如下:
http://blogs.msdn.com/changov/archive/2009/01/19/webbrowser-control-on-transparent-wpf-window.aspx
由此看來通過直接設置透明度的方法是不行了,那麼回到原來的問題,“將浏覽器窗體背景成透明”,其實這裡的透明只是一個視覺上的感覺,就是浏覽器中網頁的背景和整個窗體的背景想融合就可以。看到這裡,各位看官可能已經想到了,將浏覽器中頁面的背景繪制成被浏覽器控件所覆蓋出的背景就可以了。確實,我的實現也是依照這種思路走的。
這裡主要用到了兩個技術:
l Mshtml操作網頁中元素,通過給body標簽添加行為來實現背景的繪制。
[ComVisible(true), Guid("0015EC28-C85F-49a8-9B1A-DC91E6345274"),
ClassInterface(ClassInterfaceType.AutoDispatch)]
public class MyGadgetBodyBehavior : IElementBehavior, IHTMLPainter
{
public delegate void SizeChangedEventHandler(SizeChangedEventArgs e);
public event SizeChangedEventHandler onSizeChangedEvent;
private AppScreenSnapHelper snapHelper;
下面是繪制部分的代碼
public void Draw(RECT rcBounds, RECT rcUpdates, int lDrawFlags, IntPtr hdc, IntPtr pvDrawObject)
{
Graphics g = Graphics.FromHdc(hdc);
Bitmap buffer = new Bitmap(width, height);
Graphics gBuffer = Graphics.FromImage(buffer);
AppScreenSnapHelper.Image image = snapHelper.GetScreenSnap();
gBuffer.DrawImage(image.Bitmap, 0, 0);
image.Dispose();
string imageSrc = ((IHTMLElement2)body).currentStyle.backgroundImage;
if (!string.IsNullOrEmpty(imageSrc))
{
Match match = Regex.Match(imageSrc, @"url(""file:///(?<path>.*)"")");
if (match.Success)
{
imageSrc = match.Groups["path"].Value;
using (Bitmap bitmap = new Bitmap(imageSrc))
{
object obj = ((IHTMLElement2)body).currentStyle.marginLeft;
gBuffer.DrawImage(bitmap, new Rectangle(0, 0, width, height));
}
}
}
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);
buffer.Dispose();
gBuffer.Dispose();
g.Dispose();
}
l RenderTargetBitmap類用來給應用程序截圖:
internal Image GetScreenSnap(bool isForceRefresh)
{
if (CheckPositionAndSize() && !isForceRefresh)
{
return screenImage;
}
control.Visibility = Visibility.Hidden;
RenderTargetBitmap bitmap = new RenderTargetBitmap((int)parentWindow.Width,
(int)parentWindow.Width, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(parentWindow);
BitmapSource bitmapSource = bitmap.CloneCurrentValue();
Bitmap newBitmap = ConvertSourceImageToBitmap(bitmapSource);
newBitmap = ClipBitmap(newBitmap, new System.Drawing.Rectangle((int)oldPoint.X, (int)oldPoint.Y,
((int)control.Width == 0 ? 1 : (int)control.Width), ((int)control.Height) == 0 ? 1 : (int)control.Height));
control.Visibility = Visibility.Visible;
screenImage = new Image(newBitmap, imagePtr);
return screenImage;
}
在截圖的時候這裡使用了一個技巧就是,先將控件隱藏,然後截圖,最後恢復控件的顯示。
最後說一下本實現的一些缺陷:
如果將應用程序的背景設置為透明,則浏覽器的背景將呈現白色,因為本實現使用的是應用程序的背景來進行截圖,如果應用程序背景被透明,則截圖得到的也是一張透明的圖片,繪制到頁面上後並不能達到透明的效果。如果想在這種情況下實現透明,可以考慮對桌面背景進行截圖。
如果網頁過大出現滾動條,那麼網頁中未呈現的部分並不能透明,因為截圖只能作用於已經顯示的部分。所以本實現用於顯示本地控制好大小的html頁面有比較好的效果。
本文配套源碼