概述
最近在Winform的开发中用到了Flash动态图表FusionCharts Free,这是个开源的flash组件。商业版可以使用FusionCharts V3,免费版本的是FusionCharts Free v2.2。下载地址:http://www.fusioncharts.com/free/download/。大家可以去看看,效果还是非常炫的。商业版比免费版能够提供更多的图表,导出pdf,image,csv等功能,当然免费版这些功能大家就别指望了。
一般flash组件都是以flash的形式在网页中呈现的。因此如果要在Winform中Flash图表个人认为有两种方案。1. 利用WebBrowser控件,将url执行包含这个flash的网页。2.利用Flash的com组件shockwave Flash。第一种方式实现方式比较简单,第二种个人认为最好的是有Flex的组件作为容器,这样可以根据传递进来的参数显示不同的图表。
因为免费版没有导出pdf,image,csv等功能,所以只好自己去写了。而且是加载到WebBrowser控件,因此我对WebBrowser进行了扩展。目前常用的Flash图表都可以展示,导出pdf,image,excel,等格式。
相关图片预览
先上几张图片给大家一个直观点的认识
图1.导出的图片
图2.导出的pdf
遇到的问题
1. 如标题所说的关于WebBrowser.DrawToBitmap问题,因为此控件是没有这个方法的,但是你用了也不会出错,但是问题就来了,有时候可以导出图片有时候又不能,加载的网页里面不存在Ajax内容之类的。网上有不少对此问题的解决办法,但是所见之处基本都是错误的。一种普遍的做法如下:
{
while (webbrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
System.Drawing.Rectangle r = new System.Drawing.Rectangle(Point.Empty,
new Size(int.Parse(webbrowser.Document.Body.GetAttribute("scrollWidth")), int.Parse(webbrowser.Document.Body.GetAttribute("scrollHeight"))));
Bitmap bmp = new Bitmap(r.Width, r.Height);
webbrowser.DrawToBitmap(bmp, r);
bmp.Save(bmpPath);
bmp.Dispose();
}
结果就导致了时而可以时而不可以的问题。对这个问题,国外的站点有不错的解决方法:
1.http://bytes.com/topic/c-sharp/answers/605264-taking-screenshot-webbrowser-tab。
2. http://efreedom.com/Question/1-2434156/WebBrowser-DrawToBitmap-Methods
根据上面的方法,我将代码列出来给大家供参考,以上两种方法我用过了效果都很棒(上面的截图就是这样生成的):
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
public void WriteBmp(string bmpPath)
{
int screenWidth = webbrowser.Document.Body.ScrollRectangle.Width;
int screenHeight = webbrowser.Document.Body.ScrollRectangle.Height;
IntPtr myIntptr = webbrowser.Handle;
int hwndInt = myIntptr.ToInt32();
IntPtr hwnd = myIntptr;
// Set hdc to the bitmap
Bitmap bm = new Bitmap(screenWidth, screenHeight);
Graphics g = Graphics.FromImage(bm);
IntPtr hdc = g.GetHdc();
// Snapshot the WebBrowser
bool result = PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
// Save the bitmap, if successful
if (result == true)
bm.Save(bmpPath);
}
第2种方式:
{
public const int SRCCOPY = 13369376;
}
public static class Utilities
{
public static Image CaptureScreen()
{
return CaptureWindow(User32.GetDesktopWindow());
}
public static Image CaptureWindow(IntPtr handle)
{
IntPtr hdcSrc = User32.GetWindowDC(handle);
RECT windowRect = new RECT();
User32.GetWindowRect(handle, ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
IntPtr hdcDest = Gdi32.CreateCompatibleDC(hdcSrc);
IntPtr hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, width, height);
IntPtr hOld = Gdi32.SelectObject(hdcDest, hBitmap);
Gdi32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, ApiConstants.SRCCOPY);
Gdi32.SelectObject(hdcDest, hOld);
Gdi32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
Image image = Image.FromHbitmap(hBitmap);
Gdi32.DeleteObject(hBitmap);
return image;
}
}
public static class User32
{
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
}
public class Gdi32
{
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
//如果是.net的扩展方法,如果你.net库版本比较高就去掉注释
//public static class ControlExtensions
//{
// public static Image DrawToImage(this Control control)
// {
// return Utilities.CaptureWindow(control.Handle);
// }
//}
2.关于导出pdf的问题,大家可以去下载itextsharp开源的组件,学习文档可以参考
1. http://itextpdf.com/book/examples.php。java版的
2. http://www.cnblogs.com/islands/archive/2008/06/27/1231288.html
小结
以上是自己在Flash动态图表开发中一点小小的心得,写出来和大家一起分享,本文的目的给遇到类似问题的朋友一种解决方案,在你搜索完google,再搜索baidu发现都不能解决你问题的时候,或许此文能给你点帮助。