郁闷!C#导出EXCEL生成报表和柱状图遇到难题了!附大量代码大家来帮忙、学习参考下!

gramaster 2010-03-25 09:17:50
前一阵,帮老板开发个数据分析系统,要能根据老板的想法利用选择的数据表的数据字段(包括数据字段之间互相运算生成新字段)来生成各种报表,现在系统完成了,但是还是很不完美。
主要的问题是EXCEL生成图的问题,因为系统的数据表很多个表(数据量也很大,经常上几十万行数据),而且分析字段也不固定,这意味着不好利用实现准备好的模板,c#打开模板把数据写到相应的地方,自动就生成图的方法,因为图的DATATABLE区域是不固定的,行数和列数都不固定。
我只好尝试用C#操作EXCEL类,将DATAVIEW的数据写入EXCEL,然后再生成柱状图,花了2天时间找资料,现在可以生成图了,但是生成的图不好看,细节上无法控制。
我把生成图的代码贴下,我再附上XML方式出EXCEL的代码,只是没办法出图,而且设置文件头为自己想要的格式比较麻烦,要一行行写,还是EXCEL类库方式好,灵活方便,美观。
protected void exportdt_Click(object sender, EventArgs e)
{
//以下是用MS.Excel类库操作excel工作簿方式输出gridview数据并做图
Excel.Application app = new Excel.Application();
if (app == null)
{
return;
}
//以下是EXCEL.APPLICATION控制EXCEL方法
app.Visible = true; //如果只想用程序控制该excel而不想让用户操作时候,可以设置为false
app.UserControl = true;
app.DisplayAlerts=false;

Excel.Workbooks workbooks = app.Workbooks;

//Excel.Workbook workbook = workbooks.Add(Type.Missing); //根据模板产生新的workbook
Excel.Workbook workbook = workbooks.Open(@"D:\eaexcel\ea.xls", Type.Missing,
false,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing
); //或者根据绝对路径打开工作簿文件a.xls

stringinit();
Excel.Sheets sheets = workbook.Worksheets;
Excel._Worksheet worksheet = (Excel._Worksheet)sheets.get_Item(1);
if (worksheet == null)
{
return;
}

worksheet.get_Range(worksheet.Cells[1, 1], worksheet.Cells[1, FieldsSelectListBox.Items.Count + 2]).Merge(Type.Missing);//记号A
worksheet.Cells[1,1] = "本表共输入企业" + dataview.Rows.Count + "家;时间:" + starttime.Text.Trim() + ",数据来源:" + TableList.SelectedItem.Text.Trim() + ",依据:" + FieldNameLabel.Text.Trim();
for (int i = 0; i < FieldsSelectListBox.Items.Count ; i++)
{
worksheet.Cells[2, i+1] = FieldsSelectListBox.Items[i].Text.Trim();
}
worksheet.Cells[2, FieldsSelectListBox.Items.Count + 1] = "所属分类区间";//FieldsSelectListBox这个控件中放了分析数据做聚类分析的N个分类区间的中文名(为了让用户看名字就知道这类的意义)
worksheet.Cells[2, FieldsSelectListBox.Items.Count + 2] = "所属区间分类条件";//给高级用户看的,因为允许用户自定特定的分类条件,显示出条件的语句,以便高级用户能纠正错误
worksheet.Cells[2, FieldsSelectListBox.Items.Count + 3] = "分类区间序号";
worksheet.Cells[2, FieldsSelectListBox.Items.Count + 4] = "所属分类区间";//这行和下行代码生成的数据区域就是EXCEL生成柱状图的数据源
worksheet.Cells[2, FieldsSelectListBox.Items.Count + 5] = "企业数量";

string strQuery = "select * from sorttmp order by sortscript";
string strQuery2 = "select * from sortcount order by scnum";
//下面是利用QueryTable想EXCEL导出大量数据的方式,效率高,我试过其他方式都不理想
Excel._QueryTable qtb = worksheet.QueryTables.Add(@"OLEDB;Provider=SQLOLEDB.1;Data Source=84EBE6E6C5D9460\LOCALHOST;Password=sa;User ID=sa;Initial Catalog=economicanalyse;", worksheet.get_Range("A3", Type.Missing), strQuery);
qtb.RefreshStyle = Microsoft.Office.Interop.Excel.XlCellInsertionMode.xlInsertEntireRows;
qtb.FieldNames = false;
qtb.Refresh(false);
Excel._QueryTable qtb2 = worksheet.QueryTables.Add(@"OLEDB;Provider=SQLOLEDB.1;Data Source=84EBE6E6C5D9460\LOCALHOST;Password=sa;User ID=sa;Initial Catalog=economicanalyse;", worksheet.get_Range((char)((int)'A' + FieldsSelectListBox.Items.Count + 2) + "3", Type.Missing), strQuery2);//写到这句的时候很郁闷,为什么记号A这句get_Range可以用2个单元格CELL表示,但是这里就只能用A3,B4之类的行列序号表示了,用记号A的方式就出错,只好用这个方法了,有直接的方法一定要告诉我哦
qtb2.RefreshStyle = Microsoft.Office.Interop.Excel.XlCellInsertionMode.xlInsertEntireRows;
qtb2.FieldNames = false;
qtb2.Refresh(false);

//下面是画图表了
workbook.Charts.Add(Type.Missing,Type.Missing,1,Type.Missing);
workbook.ActiveChart.ChartType = Excel.XlChartType.xlColumnClustered;//定义图类型
workbook.ActiveChart.SetSourceData(worksheet.get_Range((char)((int)'A' + FieldsSelectListBox.Items.Count + 3) + "3", (char)((int)'A' + FieldsSelectListBox.Items.Count + 4) +Convert.ToString(GroupFSptListBox.Items.Count+2)), Excel.XlRowCol.xlRows);//图数据源
workbook.ActiveChart.Location(Excel.XlChartLocation.xlLocationAsObject, "Sheet1");//表示图示画在SHEET1的,改成自己的SHEET名就好
workbook.ActiveChart.HasTitle=true;//没有这个标题就出不来开始我没加这个标题就是出不来
workbook.ActiveChart.ChartTitle.Text = TableList.SelectedItem.Text.Trim() + "分类图";
workbook.ActiveChart.ChartTitle.AutoScaleFont = false;//这个也要不然字体大小就默认自动缩放就不是14了
workbook.ActiveChart.ChartTitle.Font.Size = 14;
workbook.ActiveChart.ChartTitle.Font.Bold = true;//加粗
Excel.Axis xAxis = (Excel.Axis)workbook.ActiveChart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary);//定义X轴
xAxis.Delete(); //这个也琢磨了好一会,因为有了这个下面会多个数字1,我开始想不写上面那句定义X轴的是不是就没了,但是发现还是一样,结果就用了这个,主坐标轴无X轴,果然下面光秃秃了,好看多了哈
Excel.Axis yAxis = (Excel.Axis)workbook.ActiveChart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary);
yAxis.HasTitle = true;
yAxis.AxisTitle.AutoScaleFont = false; //不关掉自动缩放的话后面的字体大小无法设置
yAxis.AxisTitle.Font.Size=12; //Y轴标题字体大小
yAxis.AxisTitle.Text = FieldNameLabel.Text.Trim();
yAxis.TickLabels.AutoScaleFont = false;
yAxis.TickLabels.Font.Size = 12; //Y轴坐标轴字体大小
Excel.Range oResizeRange;
oResizeRange = (Excel.Range)worksheet.Rows.get_Item(GroupFSptListBox.Items.Count+3, Type.Missing);
worksheet.Shapes.Item("Chart 1").Top = (float)(double)oResizeRange.Top; //调图表的位置上边距
oResizeRange = (Excel.Range)worksheet.Columns.get_Item(FieldsSelectListBox.Items.Count+3, Type.Missing);
worksheet.Shapes.Item("Chart 1").Left = (float)(double)oResizeRange.Left;//调图表的位置左边距

workbook.ActiveChart.ApplyDataLabels(Microsoft.Office.Interop.Excel.XlDataLabelsType.xlDataLabelsShowValue, false, false, false, false, false, true, false, false, false);//设置绘图区的数据标志(就是柱子顶上出现值)显示出值来,我这里就是数量
Excel.Series oSeries;//实例化Series类
Excel.DataLabels oDLabels ;//实例化DataLabels类,查找DataLabels.font,发现只有Excel.DataLabels有这个属性,问题之所在


for (int i = 0; i < ZoneListBox.Items.Count;i++ )
{
oSeries = (Excel.Series)workbook.ActiveChart.SeriesCollection(i+1);
oSeries.HasDataLabels = true;//每根柱子都有数据标签
oSeries.Border.ColorIndex = 45;//每根柱子边框颜色是黄色(不是指柱子的颜色哦,柱子颜色系统自动区别开的,要自定义也行,但最好别给自己找麻烦),不同的数字代表不同的颜色


//oDLabels = (Excel.DataLabels)(((Excel.Series)workbook.ActiveChart.SeriesCollection(i + 1)).DataLabels(i+1));//郁闷说我接口不对
//oDLabels.Font.Size = 11;//上面一行过不了,这行就不能设置标签字体大小,结果出来的图标签默认字体太大,当柱子多的时候,因为柱子不够宽,顶上的数据标签会重叠到一起,没法看了
}


worksheet.Shapes.Item("Chart 1").Width =ZoneListBox.Items.Count * 20 + (int)(workbook.ActiveChart.Legend.Width) + 200; //调图表的宽度,这样根据柱子的数量乘以一个宽度值再加上图例的宽度再加上余量(左右边距什么的)出来的图就不会太小了,基本上不错了,稍微放大缩小下就好,非常方便
worksheet.Shapes.Item("Chart 1").Height = ZoneListBox.Items.Count * 10+200; //调图表的高度

workbook.ActiveChart.PlotArea.Width = ZoneListBox.Items.Count * 20; //设置绘图区宽度
workbook.ActiveChart.PlotArea.Top = 20;
workbook.ActiveChart.PlotArea.Height = ZoneListBox.Items.Count * 10; //设置绘图区高度
workbook.ActiveChart.PlotArea.Left = 20;

//设置Legend图例的位置和格式
workbook.ActiveChart.HasLegend = true;
workbook.ActiveChart.Legend.AutoScaleFont = false;
workbook.ActiveChart.Legend.Top = 10; //具体设置图例的上边距
//workbook.ActiveChart.Legend.Left = 450;//具体设置图例的左边距
workbook.ActiveChart.Legend.Font.Size = 9.5;
workbook.ActiveChart.Legend.Position = Excel.XlLegendPosition.xlLegendPositionRight;

//workbook.ActiveChart.Shapes.AddTextbox(MsoTextOrientation.msoTextOrientationHorizontal, 49, 260, 293, 43);//郁闷之所在,我用录制宏的办法在VBA代码里看到就是这么做的,怎么我用C#这么做就没有文本框出来呢,能出文本框的话,我就想在绘图区下面(X轴给我关掉了)空白的地方加上文本框,里面做些有意义的说明给初级用户看

//以下是保存EXCEL文件
string fname = TableList.SelectedItem.Text.Trim() + DateTime.Today.ToString("yyyyMMdd") + new Random(DateTime.Now.Millisecond).Next(10000).ToString() + ".xls";
workbook.SaveCopyAs(Server.MapPath(". ") + "\\" + fname.ToString());
workbook.Close(Type.Missing, Type.Missing, Type.Missing);
workbooks.Close();
app.Quit();
workbook = null;
workbooks = null;
app = null;
GC.Collect();
string path = Server.MapPath(fname.ToString());
System.IO.FileInfo file = new System.IO.FileInfo(path.ToString().Trim());
Response.Clear();
Response.Buffer = true;
Response.Charset = "GB2312 ";
Response.ContentEncoding = System.Text.Encoding.UTF8;
//添加头信息,为 "文件下载/另存为 "对话框指定默认文件名
Response.AddHeader("Content-Disposition","attachment;filename="+HttpUtility.UrlEncode(file.FullName,System.Text.Encoding.UTF8));

//添加头信息,指定文件大小,让浏览器能够显示下载进度
Response.AddHeader("Content-Length ", file.Length.ToString());
Response.ContentType = "application/octet-excel ";
//把文件流发送到客户端
Response.WriteFile(file.FullName);
Response.Flush();
//停止页面的执行
Response.End();
}
总结下我的问题:1,为什么很多场合下比如worksheet.QueryTables.Add方法和workbook.ActiveChart.SetSourceData方法里面都有参数get_range,这些情况下一定要用get_range("A3","C5")这样的,你用get_range(worksheet.Cells[3, 1], worksheet.Cells[5, 3])就会出错;
2,到底怎么定义数据标签DataLabels的属性,比如字体、大小之类,因为数据标签可能比较多,你出图以后一个个手工改太累了;
3,如何在图中间添加文本框以及定义它的属性。
...全文
2058 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
LengFengKong 2011-10-27
  • 打赏
  • 举报
回复
楼主,能把C#生成Excel的三种形式的报表的源码发我一份学习下不?
邮箱 lengfengkong@sina.com
yf41100454 2011-10-20
  • 打赏
  • 举报
回复
//oDLabels = (Excel.DataLabels)(((Excel.Series)workbook.ActiveChart.SeriesCollection(i + 1)).DataLabels(i+1));//郁闷说我接口不对
//oDLabels.Font.Size = 11;//上面一行过不了,这行就不能设置标签字体大小,结果出来的图标签默认字体太大,当柱子多的时候,因为柱子不够宽,顶上的数据标签会重叠到一起,没法看了



这个问题 解决了?? 我遇到这个问题 找不到解决方法
能 发下解决方案吗 邮箱 yy1358@sina.com
YJP1314 2011-08-30
  • 打赏
  • 举报
回复
请问 你第二个问题是怎么解决的?
feihan33 2011-08-23
  • 打赏
  • 举报
回复
楼主,我现在也遇到了这样的一个困难,能不能给我个例子让我学学,谢谢了
pansy5 2010-04-30
  • 打赏
  • 举报
回复
楼主,你试没试过用水晶报表来做这个东西
zlkingdom 2010-04-30
  • 打赏
  • 举报
回复
加文本框的时候要定位吧
njw1028 2010-04-30
  • 打赏
  • 举报
回复

// Excel 可以直接打开的
DLExitFormManage efm = new DLExitFormManage();
DataTable dt = efm.GetDLNoNormalExitListDetail("", 1); // 得到要导出的数据
StringWriter sw = new StringWriter();
sw.WriteLine("部门\t姓名\t英文名\t工号\t性别\t入职日");
foreach (DataRow dr in dt.Rows)
{
sw.WriteLine(dr["deptcode"] + "\t" + dr["empcname"] + "\t" + dr["empename"] + "\t" + dr["empid"] + "\t" + dr["gender"] + "\t" +
dr["entrydate"]);
}
sw.Close();
Response.AddHeader("Content-Disposition", "attachment; filename=ExitListDetail.xls");
Response.ContentType = "application/ms-excel";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");
Response.Write(sw);
Response.End();


pansy5 2010-04-30
  • 打赏
  • 举报
回复
老帖子了,怎么还没解决?
帮顶一下!
gramaster 2010-04-30
  • 打赏
  • 举报
回复
楼上已加!
liji2009 2010-04-30
  • 打赏
  • 举报
回复
帮LZ顶起来,之前我也做过类型的程序,需求没有那么复杂!

可以加我QQ共同研究一下(327258502)
gramaster 2010-04-28
  • 打赏
  • 举报
回复
自顶一下,沉下去好久了,浮上来碰下运气,哈哈!
wbsfcom 2010-04-09
  • 打赏
  • 举报
回复
确实够长的,学习
suners 2010-04-09
  • 打赏
  • 举报
回复
deng dai
gramaster 2010-04-09
  • 打赏
  • 举报
回复
如何在图片中添加文本框啊?谁知道啊?
gramaster 2010-04-02
  • 打赏
  • 举报
回复
问题1,2已经自己解决,问题3还是不行,workbook.ActiveChart.Shapes.AddTextbox()之后,发现文本框是看不到的,怎么回事?有么有达人啊?
gramaster 2010-04-02
  • 打赏
  • 举报
回复
问题就是,不知道怎么设置文本的内容啊。
wzp144650 2010-04-02
  • 打赏
  • 举报
回复
也太长了吧。。
littlegang 2010-04-02
  • 打赏
  • 举报
回复
加Textbox后是否还要设置大小等,另外文本的内容要设置吧
pansy5 2010-03-26
  • 打赏
  • 举报
回复
学习,帮你顶
gramaster 2010-03-26
  • 打赏
  • 举报
回复
我知道代码长没人看,但是不贴出来的话,不知道我要干什么不好给出答案。
加载更多回复(1)
【课程内容】所涉及的具体内容包括输入录入技巧、排序、筛选、函数公式、数据透视表、图表、汇总等功能应用,并结合大量的企业应用实例,以互动的方式将解决思路和操作过程逐一呈现。【课程特点】1、190节大容量课程:包含了Excel软件的大部分知识点;2、创新的教学模式:手把手教您电子表格,一看就懂,一学就会;3、完美贴心的操作提示:让您的眼睛始终处于操作的焦点位置,不用再满屏找光标;4、语言简洁精练:瞄准问题的核心所在,减少对思维的干扰,并节省您宝贵的时间;5、视频短小精悍:即方便于您的学习和记忆,也方便日后对功能的检索;【互动教程的特点】•互动性-首创互动式学习,不同于以往的任何一种学习方式,不看视频不看书,轻松,高效,好玩-手把手教学,一步步引导操作,实时看到效果,就像自己在操作一样,信心满满-即点即学,课程内可根据自己的需要,随时调整界面上方进度条,重复操作,加强记忆-强大的学习跟踪系统,对整体学习进度一目了然,及时调整学习计划,查疑补漏•人性化-界面设计简洁,操作简单,没有繁琐的按钮,一点就可直接进入学习状态-贴心小提示,读懂你的小心思,零基础快速入门,学习无压力,不尴尬-超多原理解析,疑问解答,如同专业Excel导师亲身指导,不翻书快速记忆,Excel小白迅速成长•实用性-课程由浅入深,操作过程详细剖析,一步步模仿,马上就会做。-涉及排序、筛选、函数公式、数据透视表、图表、汇总等核心功能的课程编排,通俗易懂不头疼-互动+观看视频,两种学习方式切换,上班路上,地铁里享受随时随地自由学习通过本课程的学习,您将逐步掌握Excel 2016的各项功能和使用技巧。从而提高您的办公效率,早做完,不加班!!!

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧