DataList,SqlServer,统计图表,分页

 MS SQL SERVER 图像或大文本的输入输出

如何不通过其他工具,把图片、声音等存储到sql中
用image类型
方法:
1、建立过程
CREATE PROCEDURE sp_textcopy (
  @srvname    varchar (30),
  @login      varchar (30),
  @password    varchar (30),
  @dbname      varchar (30),
  @tbname      varchar (30),
  @colname    varchar (30),
  @filename    varchar (30),
  @whereclause varchar (40),
  @direction  char(1))
AS
DECLARE @exec_str varchar (255)
SELECT @exec_str =
        'textcopy /S ' + @srvname +
        ' /U ' + @login +
        ' /P ' + @password +
        ' /D ' + @dbname +
        ' /T ' + @tbname +
        ' /C ' + @colname +
        ' /W "' + @whereclause +
        '" /F ' + @filename +
        ' /' + @direction
EXEC master..xp_cmdshell @exec_str 
2、建表和初始化数据
create table 表名 (编号 int,image列名 image)
go
insert 表名 values(1,0x)    -- 必须的,且不是null
insert 表名 values(2,0x)    -- 必须的,且不是null
go
3、读入
sp_textcopy '你的服务器名','sa','你的密码','库名','表名','image列名','c:/图片.bmp','where 编号=1','I' --注意条件是 编号=1
sp_textcopy '你的服务器名','sa','你的密码','库名','表名','image列名','c:/bb.doc','where 编号=2','I' --注意条件是 编号=2
go
4、读出成文件
sp_textcopy '你的服务器名','sa','你的密码','库名','表名','image列名','c:/图片.bmp','where 编号=1','O' --注意条件是 编号=1
sp_textcopy '你的服务器名','sa','你的密码','库名','表名','image列名','c:/bb.doc','where 编号=2','O' --注意条件是 编号=2
go
如果报textcopy不是可执行文件的话,你就到
C:/Program Files/Microsoft SQL Server/MSSQL/Binn
目录下拷备 textcopy.exe到:
C:/Program Files/Microsoft SQL Server/80/Tools/Binn

MS SQL SERVER 图像或大文本的输入输出
在MS SQL SERVER 安装目录下有个可执行文件叫 TEXTCOPY.EXE
可对 MS SQL SERVER 中的文本或图像数据进行输入输出.
不过你可以在MS-DOS方式下执行textcopy /? 得到它的描述。
下面是这个工具的描述:
Copies a single text or image value into or out of SQL Server. The val
ue
is a specified text or image 'column' of a single row (specified by th
e
"where clause") of the specified 'table'. 
If the direction is IN (/I) then the data from the specified 'file' is
copied into SQL Server, replacing the existing text or image value. If
the
direction is OUT (/O) then the text or image value is copied from
SQL Server into the specified 'file', replacing any existing file.
TEXTCOPY [/S ][sqlserver]] [/U [login]] [/P ][password]]
  [/D ][database]] [/T table] [/C column] [/W"where clause"]
  [/F file] [{/I | /O}] [/K chunksize] [/Z] [/?]
  /S sqlserver       The SQL Server to connect to. If 'sqlserver' is n
ot
                     specified, the local SQL Server is used.
  /U login           The login to connect with. If 'login' is not spec
ified,
                     a trusted connection will be used.
  /P password        The password for 'login'. If 'password' is not
                     specified, a NULL password will be used.
  /D database        The database that contains the table with the tex
t or
                     image data. If 'database' is not specified, the d
efault
                     database of 'login' is used.
  /T table           The table that contains the text or image value.
  /C column          The text or image column of 'table'.
  /W "where clause"  A complete where clause (including the WHERE keyw
ord)
                     that specifies a single row of 'table'.
  /F file            The file name.
  /I                 Copy text or image value into SQL Server from 'fi
le'.
  /O                 Copy text or image value out of SQL Server into '
file'.
  /K chunksize       Size of the data transfer buffer in bytes. Minimu
m
                     value is 1024 bytes, default value is 4096 bytes.
  /Z                 Display debug information while running.
  /?                 Display this usage information and exit.
You will be prompted for any required options you did not specify.
为此, 可写一个存储过程,调用这个命令
CREATE PROCEDURE sp_textcopy (
  @srvname     varchar (30),
  @login       varchar (30),
  @password    varchar (30),
  @dbname      varchar (30),
  @tbname      varchar (30),
  @colname     varchar (30),
  @filename    varchar (30),
  @whereclause varchar (40),
  @direction   char(1))
AS
DECLARE @exec_str varchar (255)
SELECT @exec_str =
         'textcopy /S ' + @srvname +
         ' /U ' + @login +
         ' /P ' + @password +
         ' /D ' + @dbname +
         ' /T ' + @tbname +
         ' /C ' + @colname +
         ' /W "' + @whereclause +
         '" /F ' + @filename +
         ' /' + @direction
EXEC master..xp_cmdshell @exec_str
下面是一个拷贝图像到SQL Server的pubs数据库的例子, 表名pub_info, 字段名
logo,图像文件名picture.bmp,保存到pub_id='0736'记录 sp_textcopy @srvn
ame = 'ServerName',
            @login = 'Login',
            @password = 'Password',
            @dbname = 'pubs',
            @tbname = 'pub_info',
            @colname = 'logo',
            @filename = 'c:/picture.bmp',
            @whereclause = " WHERE pub_id='0736' ",
            @direction = 'I'
 

 
博客网站汇总 优秀网站
 

设计模版office:office" />

页眉<HeaderTemplate>  

</HeaderTemplate>

 

页脚<FooterTemplate>

</FooterTemplate>

 

数据记录<ItemTemplate>

</ItemTemplate>

                  

<AlternatingItemTemplate>   交替显示项

</AlternatingItemTemplate>

 

<SelectedItemTemplate>选中时的显示方式   

</SelectedItemTemplate>

 

<EditItemTemplate> 编辑时的显示方式

</EditItemTemplate>

 

<SeparatorTemplate>  数据记录分隔符

</SeparatorTemplate>

 

编辑模版,里面可以嵌入控件,绑定数据。

<ItemTemplate>

     <table>

         <tr>

         <td><%# DataBinder.Eval(Container.DataItem, "持股名称") %></td>

         <td><%# DataBinder.Eval(Container.DataItem, "市值", "{0:n}") %></td>

         <td><%# DataBinder.Eval(Container.DataItem, "净值", "{0:n}") %></td>

         </tr>

     </table>

</ItemTemplate>

 

 

设置外观

RepeatLayout        属性设置显示方式

RepeatDirection     显示方向

RepeatColumns      列数

 

 

事件

加入模版列的按钮会将其click事件反升到 ItemCommand 事件,也可设置 CommandName

来响应不同的事件,如设为:edit,即引发EditCommand()等。

注:若设为:select 则会引发SelectedIndexChanged ItemCommand事件

 

SelectedItemTemplate模版  添加详细信息的控件,当用户选择了该项,选择模版则显示。

private void DataList1_ItemCommand(……)

{

    switch(e.CommandName)

    {

        case "select":

            this.DataList1.SelectedIndex=e.Item.ItemIndex;

            string s=(string)this.DataList1.DataKeys[e.Item.ItemIndex];

            //在此获得该条记录的详细数据,在SelectedItemTemplate模版里显示。

            break;

        case "unselect":

            this.DataList1.SelectedIndex=-1;

            break;

       

    }

    this.DataList1.DataBind();//一定要

}

 

 

EditItemTemplate模版

    编辑

            this.DataList1.EditItemIndex=e.Item.ItemIndex;

            this.DataList1.DataBind();

    更新:

            得到主键

string s=(string)this.DataList1.DataKeys[e.Item.ItemIndex];

得到模版里的控件

TextBox box=(TextBox)e.Item.FindControl("TextBox1");

更新记录

this.DataList1.DataBind();

    取消:

            this.DataList1.EditItemIndex=-1;

            this.DataList1.DataBind();

 

删除项

一次勾选多条记录,一次删除

            foreach(DataListItem i in this.DataList1.Items)

            {

                bool IsChecked=((CheckBox)i.FindControl("deletectr")).Checked;

                if(IsChecked)

                {

                    string s=(string)this.DataList1.DataKeys[e.Item.ItemIndex];

                    删除操作

                }

        }

 

 

 

运行中自定义DataList控件

//当创建DataList控件中的任意项时

private void DataList1_ItemCreated(object sender, System.Web.UI.WebControls.DataListItemEventArgs e)

{

    switch(e.Item.ItemType)

    {

        case ListItemType.Header:

            e.Item.ForeColor=Color.Red;

            e.Item.BackColor=Color.Black;

            break;

        case ListItemType.Item:

            e.Item.BackColor=Color.Black;

            break;

    }

   

}

 

//当模版中的项被数据绑定时发生,数据被显示到客户端前加以访问的最后机会

private void DataList1_ItemDataBound(object sender, System.Web.UI.WebControls.DataListItemEventArgs e)

{

    if((e.Item.ItemType==ListItemType.Header)||(e.Item.ItemType==ListItemType.Item))

    {

        System.Data.Common.DbDataRecord drv=

            (System.Data.Common.DbDataRecord)e.Item.DataItem;

        if((decimal)drv["库存量"]<1000)

        {

            e.Item.ForeColor=Color.Red;

        }

    }

   

}

 另种方式

 if((e.Item.ItemType==ListItemType.Header)||(e.Item.ItemType==ListItemType.Item))

            {

                DataRowView drv=(DataRowView)e.Item.DataItem;

                string department=(string)drv["部门"];

                switch(department)

                {

                    case "销售部":

                        e.Item.BackColor=Color.Black;

                        break;

                    case "技术部":

                        e.Item.BackColor=Color.Red;

                        break;

                }

            }

Net中调用Js方法问题归类.

1.如何在.cs里面写js的事件
   Q1: Response.Write("<script language='javascript'></script>");
   Q2:Page.RegisterStartupScript("js","<script>alert('dfdf')</script>");
   Q3:Page.RegisterOnSubmitStatement("onsubmit","<script>alert('ddff')</script>");
            可以直接写到<form   >里去,把上面的代码加到page_load事件里
  Q4:使用Page.RegisterClientScriptBlock("Click","<script>function isValid(){.....}</script>");注意,其中的名称"Click"不能和已有的输出脚本块名称重复,以免带来不必要的麻烦。意见:输出前使用Page.IsClientScriptBlockRegistered进行名称判断。或者干脆给每个脚本的名称都使生成GUID.对应于Page.RegisterStartupScript方法也有Page.IsStartupScriptRegistered进行判断


2.服务端的Button怎么触发js函数啊?我在page_load里加入btn_send.Attributes.Add("OnClick","datacheck()");没用啊?
    Q1:btn_send.Attributes.Add("OnClick","return datacheck()");
    Q2:<script language=javascript>
        function dclick()
        {
              alert("hello");
        }
        </script>

        btn.Attributes["onclick"]="javascript:dclick();";

   Q3:一个很好的例子,四种方法来激发JS。
html:
<%@ Page language="c#" Codebehind="VC1.aspx.cs" AutoEventWireup="false" Inherits="WebApplicationCSharp.form1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
 <HEAD>
  <title>Click 事件使用示范</title>
  <meta content="True" name="vs_showGrid">
  <meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
  <meta content="C#" name="CODE_LANGUAGE">
  <meta content="JavaScript" name="vs_defaultClientScript">
  <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
 </HEAD>
 <body MS_POSITIONING="GridLayout">
  <script language="JavaScript">
      function sayhello()
      {    
       alert("大家好/n/n欢迎光临");
      }    
  </script>
  <form id="form1" method="post" runat="server">
   <INPUT id="btnSubmit1" style="FONT-SIZE: 12pt; Z-INDEX: 101; LEFT: 26px; POSITION: absolute; TOP: 21px" type="submit" value="请按我" οnclick="sayhello()">
   <INPUT id="btnSubmit2" style="FONT-SIZE: 12pt; Z-INDEX: 102; LEFT: 26px; POSITION: absolute; TOP: 87px" type="submit" value="请按我" οnclick="sayhello()" runat="server" NAME="btnSubmit2">
   <asp:button id="btnSubmit3" style="Z-INDEX: 103; LEFT: 26px; POSITION: absolute; TOP: 153px" runat="server" Text="请按我" Font-Size="12pt"></asp:button>
   <INPUT id="btnSubmit4" style="FONT-SIZE: 12pt; Z-INDEX: 104; LEFT: 25px; POSITION: absolute; TOP: 223px" type="button" value="请按我" οnclick="sayhello();" runat="server" NAME="btnSubmit4"></form>
 </body>
</HTML>


cs:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace WebApplicationCSharp
{
 /// <summary>
 /// VC1 的摘要描述。
 /// </summary>
 public class form1 : System.Web.UI.Page
 {
  protected System.Web.UI.WebControls.Button btnSubmit3;
  protected System.Web.UI.WebControls.DropDownList ColorDropList;
  protected System.Web.UI.HtmlControls.HtmlInputButton btnSubmit4;
  protected System.Web.UI.HtmlControls.HtmlInputButton btnSubmit2;
 
  private void Page_Load(object sender, System.EventArgs e)
  {
   btnSubmit3.Attributes.Add("onclick", "sayhello()");
  }

  #region Web Form Designer generated code
  override protected void OnInit(EventArgs e)
  {
   //
   // CODEGEN: 此呼叫为 ASP.NET Web Form 设计工具的必要项。
   //
   InitializeComponent();
   base.OnInit(e);
  }
  
  /// <summary>
  /// 此为设计工具支持所必需的方法 - 请勿使用程式码编辑器修改
  /// 这个方法的内容。
  /// </summary>
  private void InitializeComponent()
  {   
   this.btnSubmit3.Click += new System.EventHandler(this.btnSubmit3_Click);
   this.btnSubmit2.ServerClick += new System.EventHandler(this.btnSubmit2_ServerClick);
   this.btnSubmit4.ServerClick += new System.EventHandler(this.btnSubmit4_ServerClick);
   this.ID = "form1";
   this.Load += new System.EventHandler(this.Page_Load);

  }
  #endregion

  private void btnSubmit2_ServerClick(object sender, System.EventArgs e)
  {
   btnSubmit2.Value = DateTime.Now.ToString();
  }

  private void btnSubmit3_Click(object sender, System.EventArgs e)
  {
   btnSubmit3.Text = DateTime.Now.ToString();
  }

  private void btnSubmit4_ServerClick(object sender, System.EventArgs e)
  {
   btnSubmit4.Value = DateTime.Now.ToString();
  }
   
  
 }
}




4.如何给DataGrid中的TextBox加Js事件?Datagrid1的模板列中有名为"TextBox1"的TextBox控件,如何为它加上Js事件,如onkeydown?请用C#
    Q1:DataGrid的ItemDataBound事件里写

TextBox txt = e.Item.Cells[1].FindControl("TextBox1") as TextBox;
if (txt != null)
{
    txt.Attributes.Add("onClick","jsFunction();");
}

Q2:itemDataBound里面

if(e.Item.ItemIndex > -1)
{
   TextBox tb = (TextBox)e.Item.FindControl("TextBox1);
   if(tb != null)
       tb.Attributes.Add("onkeydown","yourjsfunction();");
}

Q3:在ItemDataBound内
if(e.Item.ItemType==ListItemType.Item||e.Item.ItemType==ListItemType.AlternatingItem)
{
   TextBox txt = (TextBox)e.Item.FindControl("TextBox1");
   if(txt != null)
{  
   txt.Addributes["onkeydown"]="YourJavascriptFunctionName()";
 }
}

Q4:在datagrid的ItemDataBind事件里
private void dg_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)

    TextBox t=e.Item.FindControl("TextBox1");
    t.Attribute.Add("onkeydown","alert('hello!')");



5.我在DataGrid中添加了编辑列(更新,删除),

<asp:editcommandcolumn buttontype="LinkButton" updatetext="更新" canceltext="取消" edittext="编辑"></asp:editcommandcolumn>
         <asp:buttoncolumn text="删除" commandname="Delete"></asp:buttoncolumn>

在itemdatabinding事件中怎样为DataGrid的编辑列(更新,删除)添加js的confirm提示框啊?
就是当点击了编辑列(更新,删除)的时候弹出js的提问框啊!

    Q1:private void DataGrid1_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
  {
   if(e.Item.ItemIndex<0)  return;
   if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
   {

             e.Item.Attributes.Add("OnClick","javascript:return confirm()"); 

   }

  }

    Q2:可以在ItemDataBound事件处理程序中添加,看这个帖子:
http://community.csdn.net/Expert/topic/3200/3200879.xml?temp=.5592005

Q3:在属性生成器---列--删除的文本里 加入
<div id=del οnclick="javascript:return confirm('是否删除');"删除<div>
    Q4:datagrid.items[i].cells[j].attributes.ass("onclick","if(!confirm('hello')){return false}");

------------->>分页用的函数<<-------------- 文章参考: http://www.yesky.com/SoftChannel/72342380468043776/20030614/1707838.shtml 首页 上一页 下一页 尾页 public void PagingStatus() { int int_index=datagrid.CurrentPageIndex; int int_total_page=datagrid.PageCount; pnlPaging.visible=true; lblPaging.Text="第"+(int_index+1).ToString()+"页"+" "+"共"+int_total_page.ToString()+"页"; if(int_index==0) //当前显示页为首页时 { lbtnFirst.Enabled = false; lbtnPre.Enabled = false; lbtnNext.Enabled = true; lbtnLast.Enabled = true; } else if (index>0 && index<(cnt-1) ) //当前显示页为中间页时 { lbtnFirst.Enabled = true; lbtnPre.Enabled = true; lbtnNext.Enabled = true; lbtnLast.Enabled = true; } else (index == (cnt-1)) 当前显示页为末页时 { lbtnFirst.Enabled = true; lbtnPre.Enabled = true; lbtnNext.Enabled = false; lbtnLast.Enabled = false; } } public void PagerButtonClick(object sender, EventArgs e) { DataSet dsBook = openDataBase(); string arg = ((LinkButton)sender).CommandArgument.ToString(); switch(arg) { case "next": //下一页 if (dgdBook.CurrentPageIndex < (dgdBook.PageCount - 1)) { dgdBook.CurrentPageIndex++; } break; case "pre": //上一页 if (dgdBook.CurrentPageIndex > 0) { dgdBook.CurrentPageIndex--; } break; case "last": //尾页 dgdBook.CurrentPageIndex = (dgdBook.PageCount - 1); break; case "first": //首页 dgdBook.CurrentPageIndex = 0; break; efault: //其他 break; } dgdBook.DataBind(); PagingStatus(); } ----------->>存贮过程分页>>------------ 参考文献 http://www.blog.edu.cn/user2/32244/archives/2005/285782.shtml CREATE PROCEDURE p_PageRecordset_Table ( @TableName NVARCHAR(100),--全局临时表名称 @PageSize INT, --每页的记录条数 @PageNumber INT, --当前页面 @TotalSize INT, --总记录条数 @TotalPage INT OUTPUT --总页数 ) AS BEGIN SET NOCOUNT ON DECLARE @SqlText AS NVARCHAR(1000) -- 计算总页数 IF @PageSize>0 BEGIN SET @TotalPage=@TotalSize/@PageSize IF (@PageSize*@TotalPage)<>@TotalSize SET @TotalPage=@TotalPage+1 END ELSE BEGIN SET @TotalPage=1 END -- 校正输入参数 IF @PageNumber<1 SET @PageNumber=1 IF @PageNumber>@TotalPage SET @PageNumber=@TotalPage IF @PageSize<=0 OR @TotalSize=0 BEGIN --如果设置PageSize小于等于0,表示不分页。 SET @SqlText=' SELECT * FROM ' + @TableName + ' DROP TABLE ' + @TableName END ELSE BEGIN SET @SqlText=' SET NOCOUNT ON SELECT * FROM ' + @TableName + ' WHERE ' + CAST((@PageNumber-1)*@PageSize+1 AS NVARCHAR(30)) + '<=ROWNUM and ROWNUM<=' + CAST(@PageNumber*@PageSize AS NVARCHAR(30)) + ' ORDER BY ROWNUM DROP TABLE ' + @TableName END -- PRINT @SqlText EXEC(@SqlText) End GO -------------------------------------调用实例: DECLARE @PageSize INT DECLARE @PageNumber INT DECLARE @TotalSize INT DECLARE @TotalPage INT SET @PageSize=5 SET @PageNumber=1 SET NOCOUNT ON -- 把查询的结果放到一个临时表中,供分页处理。 SELECT CAST(EmployeeID as INT) AS EmployeeID, -- 如果源表中有自编号的字段,要转换一下。 LastName, FirstName, BirthDate, Address, Region, PostalCode, Country, IDENTITY(INT,1,1) AS ROWNUM -- 添加一个新的编号列,供分页存储过程使用。 INTO #tbl_p_Page_List -- 可以随机生成一个临时表名 FROM Employees ORDER BY LastName,FirstName -------------------------------------------------- -- 以下是通用的分页过程 -------------------------------------------------- --取得总记录条数 SELECT @TotalSize=@@ROWCOUNT -- 调用通用的分页处理过程 -- 注意:临时表中必须有自动编号的字段 IDENTITY(INT,1,1) AS ROWNUM EXEC p_PageRecordset_Table '#tbl_p_Page_List', @PageSize,@PageNumber,@TotalSize,@TotalPage OUTPUT -------------------------------------------------- PRINT @TotalSize PRINT @TotalPage GO
htt
统计图表--微软技术社区期刊
http://www.mscenter.edu.cn/zhuanti/dianziqikan/4/article3.htm
作者:郭斌 时间:2003年10月
作者手机:13571878390
作者项目:Syn-Data
负责人名称: 韦敏宗
负责人Email: hansmail@sina.com

Syn-Data基于Internet数据协同会议系统是利用最新流媒体通信技术实现的一个具有实时多点语音、视频、数据通讯综合应用能力的系统。它不仅实现基于Internet的具有多人音频、多人视频、共享电子白板、共享文档等交流手段的实时数据协同、实时讨论的功能,而且实现单机的课件录制,全程录制回放等功能,具有对带宽要求低,高质量音频视频,与Web无缝集成,强的抗网络拥塞丢包能力和支持防火墙和应用代理等能力。它使用户可以利用普通的PC机、标准的视频采集设备、耳机和麦克风,实现基于Internet的实时数据协同、实时讨论。Syn-Data致力于有效地节约时间和经费,提高了用户的工作效率,使任何人不受时间、地点的限制,可充分享受网络时代给大家带来的实时交互式多媒体通信服务。使用Syn-Data,终端用户可以实现共享演示文档、应用程序、网页及桌面等,同时提供音、视频的无缝嵌入。

BlastTeam:该文为Blast Tean技术原创文章之一。因为是一系列文章,故文章描述是以章节来描述的。BlastTeam最终将把所有的技术原创文章汇编成册。
概述
在Web程序开发中,图形和图表是很好的数据表现形式。往往是表格中的大量数据让用户产生无法处理,无从获取所需要的信息。而以图表方式提供数据的话就可以达到简单清爽,简单易懂并且一目了然的效果。利用图表,管理人员可以方便的掌握销售与生产数据,从而做出相应的判断。
在ASP.NET Web程序中,生成图表有以下的选择:
● ASP.NET内建的图形库(GDI+,位于System.Drawing 命名空间)
使用简单的图形,GDI+能够创建饼图、柱状图、线性图。但是这种方法过于底层,不适于创建复杂的图形。
● 各种ASP.NET图表控件
网上有一些ASP.NET的图表控件,但许多控件非常昂贵,而且与最常用的图表应用Excel差别很大。
● Office Web Components
Microsoft Office Web Components 包含在 Microsoft Office 2000 中。它们是用于向 Web 页添加电子表格、图表和数据处理功能的 ActiveX 控件的集合。可以直接在浏览器中处理数据,并以图表的形式显示数据。由于其基于Office的强大功能,以及与Office相同的用户界面,无疑是ASP.NET中图表生成的明智选择。
本章主要包括以下几个方面内容:
● 基于GDI+的图表生成。
● 基于Office Web Components的图表生成。
● 基于Office Web Components的报表生成。
经过本章的学习,将掌握ASP.NET中统计图表的实现,利用图表将网站的数据完美呈现给用户。
方案设计
本节分别介绍GDI+与Office Web Components的具体使用,为后面的章节打下基础。
使用GDI+
GDI+ 是 GDI(Windows XP之前版本提供的图形设备接口)的后续版本。GDI+ 是一种应用程序编程接口 (API),负责在屏幕和打印机上显示信息。
在ASP.NET中,利用GDI+可以创建简单的柱状图和饼图。
ASP.NET页面GDI+图像使用
在完整的生成柱状图和饼图之前,先从简单的ASP.NET页面图像使用开始。
在System.Draw命名空间中包含了创建、编辑图像的所有类。创建图像时,主要使用Bitmap类和Graphics类。为了便于理解,可以把Bitmap类想象成画板,Graphics类想象成画笔。Bitmap类主要用于创建画板以及在完成后图像的保存。Graphics类主要用来绘制图像、图形和线条。
首先使用下面的代码创建画板。(本小节所有代码需要添加System.Drawing命名空间与System.Drawing.Image命名空间)
Bitmap myPalette = new Bitmap(600, 400); //创建600*400的画板
有了画板,还需要创建Graphics类的实例来创建画笔,指定画板。代码如下
Graphics myGraphics = Graphics.FromImage(myPalette);
有了画笔和画板,只要使用Graphics类中的各种方法在画板上绘制图像、图形和线条就可以了。
Graphics类中的方法分为两类:绘制方法与填充方法。例如,DrawRectangle方法与FillRectangle方法。绘制方法仅仅绘制出图形的轮廓,而填充方法绘制出图形的轮廓同时填充图形的内部。
下面的代码绘制了简单的图形:
int width=150,height=50;
// 创建黑色背景椭圆
myGraphics.FillEllipse(new SolidBrush(Color.Black), 300, 150, width, height);
// 创建蓝色背景椭圆
myGraphics.FillEllipse(new SolidBrush(Color.LightBlue), 300, 150, width - 10, height - 10);
// 创建输出文本
string textOut = "ASP.NET";
//指定字体
Font fontOut = new Font("Times New Roman", 16, FontStyle.Bold|FontStyle.Italic);
//指定文本居中
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
// 绘制文本
myGraphics.DrawString(textOut,fontOut,new SolidBrush(Color.Black),new Rectangle(0,0,width,height),stringFormat);
图已经画好了,只剩下将图保存下来。要将保存的图在网页中显示,可以在下面两种方式中任选其一:
● 将图像保存在服务器的文件系统中,使用HTML的<img>标记来显示。
● 直接将图像的二进制流输出到Response对象的输出流。
两种方式各有千秋。第一种方式适合于创建不需要变动的图片(例如网站广告图片),能够创建一次,满足今后的所有要求。但会在服务器端保留下临时文件。第二种方式适用于动态的创建图片供页面显示,不能满足今后的需要,却也不会留下临时文件。
下面分别写出这两种方式的代码:
● 保存文件方式代码:
保存文件方式首先需要在Aspx文件中添加<Img>标记
<!-- 指定显示文件为tmpFile.jpg -->
<img src = “tmpFile.jpg”>
然后在代码中保存文件即可:
//将文件保存为当前页面所在目录下的tmpFile.jpg
myPalette.Save(Server.MapPath("")+@"/tmpFile.jpg",ImageFormat.Jpeg);
● 直接输出方式代码:
//直接将图片以二进制流的方式输出到Response对象的输出流。
myPalette.Save(Response.OutputStream, ImageFormat.Jpeg);
将代码加入页面的PageLoad事件中即可得到如图18-1效果。
      
       图18-1 GDI+图像使用效果
创建柱状图
在知道了如何使用GDI+创建简单图像并显示到页面后,创建复杂一些的柱状图就非常自然了。
使用简单的FillRectangle,DrawRectangle,DrawString方法,即可实现基本的柱状图。代码如下:
//初始化Bitmap类实例与Graphics类实例准备画图
const int width = 600, height = 400;
Bitmap myPalette = new Bitmap(width,height);
Graphics myGraphics = Graphics.FromImage(myPalette);
// 绘制白色背景
myGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0, width, height);
// 设定显示数据
string [] DataName = {"Jan","Feb","Mar","Apr","May","Jun"};
int [] Data = {100,20,50,60,240,20};
//设定显示颜色
Color [] myColors = {
Color.Blue,
Color.Red,
Color.Yellow,
Color.Purple,
Color.Orange,
Color.Brown
};
//绘制柱图
for(int i = 0;i<DataName.Length;i++)
{
//填充柱图
myGraphics.FillRectangle(new SolidBrush(myColors[i]),(i*40)+30,300 - Data[i],20,Data[i]+5);
//绘制柱图边界
myGraphics.DrawRectangle(new Pen(Color.Black),(i*40)+30,300 - Data[i],20,Data[i]+5);
//绘制柱图上方数据
myGraphics.DrawString(Data[i].ToString(), new Font("宋体", 9), Brushes.Black, new PointF((i*40)+30,300-Data[i]-20));
//绘制柱图下标
myGraphics.DrawString(DataName[i], new Font("宋体", 9), Brushes.Black, new PointF((i*40)+30,320));
}
//输出图像
myPalette.Save(Response.OutputStream, ImageFormat.Jpeg);
// 清除所用绘图对象
myGraphics.Dispose();
myPalette.Dispose();
将上述代码写入页面CodeBehind文件的PageLoad事件中即可看到如图18-2效果:
       
          图18-2 GDI+柱状图效果
使用Office Web Components
Office Web Components是用于向 Web 页添加电子表格、图表和数据处理功能的 ActiveX控件的集合。
利用Office Web Components可以方便的来绘制简单的柱状图与饼图。不必像在GDI+中需要考虑画图的细节。
使用Office Web Components要求
使用Office Web Components需要系统中装有Office2000以上版本。在工程的引用中添加Office Web Components即可。
具体步骤如下:
在解决方案资源管理器的引用文件夹上单击鼠标右键选择添加引用,在出现的添加引用对话框中选择COM标签,选择Microsoft Office Web Components,双击选中,点击确定即可。图18-3、18-4显示了该过程。
       
            图18-3 添加引用           图18-4 添加Office Web Components引用

使用Office Web Components绘制柱状图
使用Office Web Components绘制图表不同于直接使用GDI+,主要的工作从绘图的细节转移到对于图表的设置。步骤如下:
● Step1 创建ChartSpace对象来放置图表
ChartSpace是用来放置图表的类,图表完成后用它来输出。
OWC.ChartSpace objCSpace = new OWC.ChartSpaceClass ();
● Step2 使用ChartSpace对象的Add方法创建图表
ChartSpace的Add方法创建图表,参数表示所创建图表的索引。
OWC.WCChart objChart = objCSpace.Charts.Add (0);
● Step3 指定图表的类型
通过设定Chart类对象的Type属性来指定图表的类型。
objChart.Type = OWC.ChartChartTypeEnum.chChartTypeColumnClustered;
本例创建柱状图,选择了chChartTypeColunmClustered类型。
其他的类型包括:chChartTypeArea 面积图、chChartTypeBarClustered 条形图、chChartTypePie 饼图、chChartType RadarLine 雷达线图、chChartTypeSmoothLine 平滑曲线图、chChartTypeDoughnut 环形图等等。
图18-5至18-10显示了部分图表的简单实例。
       
         图18-5 曲线图          图18-6 条形图          图18-7 面积图
       
         图18-8 环形图           图18-9 饼图          图18-10 雷达图
● Step4 设定图示说明
图示说明主要包括图例(用颜色表示数据类型)、图题(图表的标题)、XY轴的数据说明(一般用来说明各轴上的数据单位)。设定代码如下:
//指定图表是否需要图例
objChart.HasLegend = true;

//给定标题
objChart.HasTitle = true;
objChart.Title.Caption= "上半年月收入图";

//给定x,y轴的图示说明
objChart.Axes[0].HasTitle = true;
objChart.Axes[0].Title.Caption = "万元";
objChart.Axes[1].HasTitle = true;
objChart.Axes[1].Title.Caption = "月份";
● Step5 添加数据
添加数据主要设定Chart类对象的SeriesCollection属性。首先使用SeriesCollection的Add方法创建一组数据。然后使用SetData方法具体添加数据。代码如下:
(注意:数据的格式是以'/t'间隔的字符串)
//添加一组图表数据
objChart.SeriesCollection.Add(0);
//给定该组数据的名字
objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimSeriesNames,
+ (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,”上半年收入”);
//给定数据分类
objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
+ (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,
"Jan"+'/t'+"Feb"+'/t'+"Mar"+'/t'+"Apr"+'/t'+"May"+'/t'+"Jun"+'/t' );
//给定数据值
objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
(int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,
"100"+'/t'+"20"+'/t'+"50"+'/t'+"60"+'/t'+"240"+'/t'+"20"+'/t');
● Step6 显示数据
显示数据是使用Chart类对象的ExportPicture方法将生成的图表创建为图片,然后显示的。代码如下:
//输出成GIF文件,参数为文件名、格式、图片大小
objCSpace.ExportPicture(Server.MapPath("")+@"/tmpFile.gif", "GIF", 400, 300);
//从生成的图片创建Bitmap对象,输出到Response输出流
Bitmap myPalette = new Bitmap(Server.MapPath("")+@"/tmpFile.gif",true);
myPalette.Save(Response.OutputStream,System.Drawing.Imaging.ImageFormat.Gif);
经过了以上的步骤,将代码输入页面的PageLoad事件代码段中,运行程序就可以得到如图18-11效果。
        
        图18-11 Office Web Components柱状图示例
使用Office Web Components绘制饼图
绘制饼图与绘制柱状图的区别不是很大,需要注意的是饼图没有XY轴,所以不能设置XY轴的图示说明。在绘制柱状图的代码上去掉关于XY轴图示说明的代码即可。
完整代码如下:
//初始化图表数据
string [] DataName = {"Jan","Feb","Mar","Apr","May","Jun"};
int [] Data = {100,20,50,60,240,20};
//声明存储数据分类和数据值的字符串
string strDataName = "";
string strData = "";
//循环按格式生成存储数据分类与数据值的字符串
for(int i=0;i< Data.Length;i++)
{
strCategory += DataName[i]+'/t';
strValue += Data[i].ToString()+'/t';
}
//创建ChartSpace对象来放置图表
OWC.ChartSpace objCSpace = new OWC.ChartSpaceClass ();

//在ChartSpace对象中添加图表,Add方法返回chart对象
OWC.WCChart objChart = objCSpace.Charts.Add (0);

//指定图表的类型为饼图
objChart.Type = OWC.ChartChartTypeEnum.chChartTypePie;
//指定图表是否需要图例
objChart.HasLegend = true;
//给定标题
objChart.HasTitle = true;
objChart.Title.Caption= "上半年月收入图";

//添加一个series
objChart.SeriesCollection.Add(0);

//给定数据分类
objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
+ (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,strDataName);

//给定数据值
objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
(int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,strData);
//输出成GIF文件.
objCSpace.ExportPicture(Server.MapPath("")+@"/tmpFile.gif", "GIF", 400, 300);
Bitmap myPalette = new Bitmap(Server.MapPath("")+@"/tmpFile.gif",true);
myPalette.Save(Response.OutputStream,System.Drawing.Imaging.ImageFormat.Gif);
将上述代码写入页面文件的PageLoad事件处理代码中,运行得到如图18-12效果。
         
        图18-12 Office Web Components饼图示例
公司盈利状况统计
前面介绍了Office Web Components的情况,本节将通过公司盈利状况统计来介绍Office Web Components柱状图在具体实例中的使用。
数据库设计
为了实现公司盈利状况统计。首先,需要设计相关的数据库表。在实际情况中,公司的盈利就是收入的总和与支出的总和之差。而每笔收入与支出都是在一次交易中完成的。基于以上考虑,同时为了实现简单。设计数据库表单如下:
表名 T_Deal 别名 交易表
表项      说明   类型     是否可空
DealTime   交易时间  DateTime     否
DealIncome  交易金额  int       否
DealContent  交易内容  Varchar(50)   否
DealObject  交易对象  Varchar(20)   是
Comment    备注    Varchar(50)   是
注意:为了简单起见,用交易金额统一表示收入与支出。用正数的交易金额表示收入,负数的交易金额表示支出。这样计算盈利时只需将交易金额求和即可。
按照上表的格式在SqlServer中创建表。添加样例数据供程序使用。
然后创建下面的存储过程来实现公司盈利状况的统计。
CREATE PROCEDURE sp_SelectIncome
@year int
AS

Select sum(DealCount),Datepart(mm,DealTime) From T_Deal
where DATEPART(yy,DealTime)=@year
Group By Datepart(mm,DealTime)
GO
该存储过程选择交易时间的年份与输入参数@year相等的数据,并将选择得到的数据按交易时间的月份分组。返回每组交易金额的总和以及该组的交易月份。
界面设计
新建Web工程WebChart。将WebForm1.aspx改名为OWCChart.aspx。同时,将其代码文件中的类名改为OWCChart。
界面如图18-13所示:
      
          图18-13 公司盈利统计界面
该界面主要包括两部分:一个PlaceHolder控件用来放置生成的图表构成显示图表部分。一个用来选择统计年份的DropDownList控件,一个用来确定生成图表的Button控件,一个用来显示错误信息的Label控件构成了图表的生成部分。
同样为了界面整洁使用Table将所用控件放在表格中。按照图18-13安排好界面后就可以为控件设置属性了,主要包括以下几个方面的设置:
● PlaceHolder控件的设置
PlaceHolder控件在本程序中用于放置生成的图表,只需设置其Id属性为ChartPlaceHolder即可。
● DropDownList控件的设置
DropDownList控件在本程序中用于选择统计年份,设置其Id属性为ddlYear。并为其添加ListItem 2000,2001,2002,2003。
<asp:ListItem Value="2000">2000</asp:ListItem>
<asp:ListItem Value="2001">2001</asp:ListItem>
<asp:ListItem Value="2002">2002</asp:ListItem>
<asp:ListItem Value="2003">2003</asp:ListItem>
● Button控件的设置
Button控件设置Id属性为btnSumbit,Text属性为“确定”即可。
● Label控件的设置
Label控件设置Id属性为Info即可。
代码实现
在完成了上面的界面设计后,就要进入后台代码的编写了。下面就将分模块介绍各部分功能的代码实现。
数据读入
为了显示公司盈利状况统计,首先需要将统计的结果从数据库中读入。读入数据的代码包括以下两部分。
● 创建数据库联接
为了方便程序的配置,将数据库联接字段保存在Web.Config文件中。如此一来,在需要修改数据库联接字段时只需要修改Web.Config文件即可,不需要修改程序代码,重新编译。
在Web.Config文件中的<configuration>字段中加入如下代码:
<appSettings>
<add key="ConnectStr"
value="server=localhost;uid=yourid;pwd=yourpas;database=Info;"/>
</appSettings>
其中localhost要改为自己的数据库服务器名,uid,pwd分别为数据库用户id和密码,database为数据库名。
设置好联接字段后就可在代码中对其进行引用了。
主要使用AppSettingReader对象的GetValue方法获取”ConnectStr”字段信息,该方法需要两个参数,第一个指定要引用的字段,第二个参数指定需要的类型。返回一个Object类型的变量。需要使用Convert的ToString方法将其转换为字符串类型
引用代码如下:
//全局数据库联接
System.Data.SqlClient.SqlConnection MyConnection;
private void Page_Load(object sender, System.EventArgs e)
{
// 在此处放置用户代码以初始化页面
if(Page.IsPostBack==false) // 页面首次加载时
{

//创建Web.Config文件应用程序设置字段读取对象
System.Configuration.AppSettingsReader ConnectionString = new System.Configuration.AppSettingsReader();
//创建数据库联接
MyConnection = new System.Data.SqlClient.SqlConnection();
//设置数据库联接的连接字段
MyConnection.ConnectionString = Convert.ToString(ConnectionString.GetValue("ConnectStr",System.Type.GetType("System.String")));
}
}
● 利用数据库联接读取数据
有了前面创建的数据库联接就可以从数据库中读取数据了。
读取数据代码如下:
//读取数据函数,参数为需要统计的年份,返回DataSet
DataSet ReadData(string Year)
{
//创建DataSet
DataSet dsIncome = new DataSet();
//设置存储过程名
string SpName = "sp_SelectIncome";
//创建Sql命令
SqlCommand IncomeCmd = new SqlCommand(SpName,MyConnection);
//设定数据库命令类型为存储过程
IncomeCmd.CommandType = CommandType.StoredProcedure;
//打开数据库联接
MyConnection.Open();
//创建并设定存储过程参数
SqlParameter IncomeYear = new SqlParameter("@year",SqlDbType.Int,4);
IncomeYear.Value=Convert.ToInt16(Year);
//为Sql命令添加参数
IncomeCmd.Parameters.Add(IncomeYear);
//创建Sql数据桥接器
SqlDataAdapter adapter = new SqlDataAdapter(SpName,MyConnection);
//指定桥接器Sql命令
adapter.SelectCommand = IncomeCmd;
//填充DataSet
adapter.Fill(dsIncome,"Income");
//关闭数据库联接
MyConnection.Close();
}
数据显示
使用ReadData方法读出数据,接下来就是显示数据了。显示数据同样需要两个步骤。
● 处理数据库读出的数据
由于从数据库读出的数据不能完全满足显示的要求,有可能某个月份没有交易,那么返回的DataSet中就不会包含该月的数据。但显示时需要所有月份的数据。所以直接显示数据之前先要对数据进行加工。代码如下:
//创建存储数据的数组,MyMonthIncome存放每月数据,MyMonthName存放月份缩写
int[] MyMonthIncome = new int[12];
string[] MyMonthName = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

//声明存放显示用字符串的变量,strMonthName存放月份信息,strMonthIncome存放数据
string strMonthName = "";
string strMonthIncome = "";
//对存在数据的月份将数据保存在MyMonthName
for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
{
MyMonthIncome[Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][1])-1] = Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][0]);
}
//用已有的数据来生成图表显示所需的字符串
for(int i=0;i< 12;i++)
{
strMonthName += MyMonthName[i]+'/t';
strMonthIncome += MyMonthIncome[i].ToString()+'/t';
}
● 使用Office Web Components显示数据
经过上一步骤,图表显示所需的字符串已经放入了strMonthName和strMonthIncome中,下面使用18.2节中关于Office Web Components的知识就可以大功告成了。需要注意的是在生成图片后使用了PlaceHolder的.Controls属性的Add方法将动态生成的<img>标签放入页面。为了方便后面的使用,将显示数据的代码写为函数。代码如下:
private void MakeLineChart(string Year)
{
//使用ReadData函数读出数据
DataSet dsIncome = ReadData(Year);
//以下插入处理数据库读出的数据部分的代码,不再重复
//….上一步骤中处理数据库读出数据代码

//创建ChartSpace对象来放置图表
OWC.ChartSpace mySpace = new OWC.ChartSpaceClass ();
//在ChartSpace对象中添加图表,Add方法返回chart对象
OWC.WCChart myChart = mySpace.Charts.Add (0);

//指定图表的类型为线性图
myChart.Type = OWC.ChartChartTypeEnum.chChartTypeLine;
//指定图表是否需要图例
myChart.HasLegend = true;
//给定标题
myChart.HasTitle = true;
myChart.Title.Caption= ddlYear.SelectedItem.Text + "月收入图";
//给定x,y轴的图示说明
myChart.Axes[0].HasTitle = true;
myChart.Axes[0].Title.Caption = "万元";
myChart.Axes[1].HasTitle = true;
myChart.Axes[1].Title.Caption = "月份";
//添加一个series
myChart.SeriesCollection.Add(0);
//给定series的名字
myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimSeriesNames,
+ (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strSeriesName);
//给定分类
myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
+ (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strCategory);
//给定值
myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
(int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strValue);
//输出成GIF文件.
string strAbsolutePath = (Server.MapPath(".")) + @"/images/tempFile.gif";
mySpace.ExportPicture(strAbsolutePath, "GIF", 700, 350);
//创建GIF文件的相对路径.
string strRelativePath = "./images/tempFile.gif”
//生成显示图片的<img>标签
string strImageTag = "<IMG SRC='" + strRelativePath + "'/>";
//把图片添加到placeholder.
ChartPlaceHolder.Controls.Add(new LiteralControl(strImageTag));
18.3.3.3 按钮点击事件
有了前面的MakeLineChart函数,在aspx页面的设计模式下双击btnSumbit创建按钮点击事件。修改代码如下:
private void btnSubmit_Click(object sender, System.EventArgs e)
{
MakeLineChart(ddlYear.SelectedItem.Text);
}
至此,公司盈利状况统计功能完全实现,运行结果如图18-16:
        
         图18-16 公司盈利状况统计效果
公司收入分块图
上一节介绍了Office Web Components的柱状图的使用,实现了对公司盈利状况统计。本节将通过公司收入分块图的实现来介绍Office Web Components中饼装图的使用。
数据库设计
为了实现公司收入分块图,为T_Deal表增添交易类别字段。扩充后的T_Deal表如下:
表名 T_Deal 别名 交易表
表项      说明   类型     是否可空
DealTime   交易时间  DateTime     否
DealIncome  交易金额  int       否
DealContent  交易内容  Varchar(50)   否
DealObject  交易对象  Varchar(20)   是
DealCategory 交易类别  Varchar(20)   否
Comment     备注   Varchar(50)   是
按照新表的格式重新在SqlServer中创建表。添加样例数据供程序使用。并且创建如下存储过程实现公司收入分块统计。
CREATE PROCEDURE sp_SelectCategory
@year int
AS

Select sum(DealCount),DealCategory From T_Deal
where DATEPART(yy,DealTime)=@year
Group By DealCategory
GO
该存储过程选择交易时间的年份与输入参数@year相等的数据,并将选择得到的数据按交易类别分组。返回每组交易金额的总和以及该组的交易类别。
界面设计
为了简便同时利用已有成果,在现有的基础上修改无疑是最好的选择。因此,本节的程序直接在上一节的程序上修改。在原有界面上添加一个DropDownList来选择不同的图表内容。新的界面如图18-17:
      
         图18-17 公司收入分布界面
新增的DropDownList属性设置为Id=ddlChartType,并为其添加Item
<asp:ListItem Value="Income">公司盈利状况</asp:ListItem>
<asp:ListItem Value="Category">公司收入分块图</asp:ListItem>
代码实现
在完成了上面的界面设计后,就要进入后台代码的编写了。由于是在上一节的基础上,所以只需增加新功能。
数据读入
由于已经有了创建数据库联接部分,下面只需要读出数据即可。数据读入部分代码与上一节的代码相似,不同之处只是所调用的存储过程不同,为了简化代码,修改ReadData函数,为其增加参数SpName 指定调用的存储过程。将原有程序中声明SpName的语句删除即可。
//读取数据函数,参数Yesr为需要统计的年份SpName为调用存储过程名,返回DataSet
DataSet ReadData(string Year,string SpName)
{
//创建DataSet
DataSet dsIncome = new DataSet();
//设置存储过程名,通过新增参数完成,将此句去除
//string SpName = "sp_SelectIncome";
//以下部分不做修改,不再重复

}
注意:修改ReadData函数后,在上一节MakeLineChart函数中调用ReadData的代码需要为其增加参数。
private void MakeLineChart(string Year)
{
//使用ReadData函数读出数据
DataSet dsIncome = ReadData(Year,“sp_SelectIncome”);
//以下部分不做修改

}
数据显示
使用ReadData方法读出数据,接下来就是显示数据了。显示数据的代码也只需对上一节代码做部分修改即可。声明绘制分类收入的函数,将MakeLineChart函数内容复制并修改如下:
private void MakePieChart(string Year)
{
//使用ReadData函数读出数据
DataSet dsCategory = ReadData(Year);
//创建存储数据的数组,MyCategory存放类别数据,MyMonthName存放类别名称
int[] MyCategory = new int[dsIncome.Tables["Income"].Rows.Count];
string[] MyCategoryName = new string[dsIncome.Tables["Income"].Rows.Count];

//声明存放显示用字符串的变量,strMonthName存放月份信息,strMonthIncome存放数据
string strCategoryName = "";
string strCategory = "";
//声明总收入,用来计算各分类收入百分比
int IncomeSum = 0;
//将数据放入数组,同时计算总收入
for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
{
MyCategory[i] = Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][0]);
MyCategoryName[i] = Convert.ToString(dsIncome.Tables["Income"].Rows[i][1]);
IncomeSum += MyCategory[i];
}
//用已有的数据来生成图表显示所需的字符串
for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
{
//计算出各分类所占百分比
int PercentCategory= 100*MyCategory[i]/IncomeSum;
strCategory += MyCategoryName[i]+" "+PercentCategory.ToString()+ "%"+'/t';
strValue += MyCategory[i].ToString()+'/t';
}
//下面代码与上一节基本相同不再重复
//仅给出需要修改的部分

//指定图表的类型为线性图 改为饼图
myChart.Type = OWC.ChartChartTypeEnum.chChartTypePie;
//指定图表是否需要图例
myChart.HasLegend = true;
//给定标题
myChart.HasTitle = true;
myChart.Title.Caption= ddlYear.SelectedItem.Text + "收入图";
//给定x,y轴的图示说明 ,去掉XY轴图示说明部分
/*
myChart.Axes[0].HasTitle = true;
myChart.Axes[0].Title.Caption = "万元";
myChart.Axes[1].HasTitle = true;
myChart.Axes[1].Title.Caption = "月份";
*/

}
18.3.3.3 按钮点击事件
由于增加了新功能,按钮点击的代码修改如下:
private void btnSubmit_Click(object sender, System.EventArgs e)
{
//根据ddlChartType的选项判断执行的内容
if(ddlChartType.SelectedItem.Value=="Income")
MakeLineChart(ddlYear.SelectedItem.Text); //显示公司盈利统计
else if(ddlChartType.SelectedItem.Value=="Category")
MakePieChart(ddlYear.SelectedItem.Text);//显示收入分布
}
至此,公司盈利状况统计功能完全实现,运行后选择收入分布点击确定按钮。结果如图18-18:
       
        图18-18 公司收入分块图效果
报表产出
前面的几个小节完成了对数据的统计并以图表的形式呈现给用户,使用户能够一目了然的获取所需信息。这一节将把统计结果以Excel报表的形式输出,以免用户提交报表时手工输入的麻烦,提高工作效率。
报表产出主要使用了Office Web Components的Spreadsheet控件。利用该控件创建并编辑数据表格,并将最终结果输出到Excel报表。步骤如下:
● Step1创建SpreadsheetClass对象,用来放置数据表格
类似于Chart控件中的ChartSpace,Spread控件中也需要创建一个放置SpreadsheetClass的对象作为单个表的容器。
SpreadsheetClass exl = new SpreadsheetClass();
● Step2利用SpreadsheetClass的ActiveSheet获得当前处于活动状态的表格
一个SpreadsheetClass对象就相当于一个运行中的Excel,通过其ActiveSheet属性能够得到当前处于活动状态的表格。一个Worksheet对象就相当于Excel中的一张表格。将SpreadsheetClass对象的ActiveSheet属性赋值给Worksheet对象。就可以在后面的代码中对表格进行操作了。
OWC.Worksheet ws = exl.ActiveSheet;
● Step3 编辑表格
编辑表格使用的是Worksheet对象的Cells属性。Cells属性就代表着表格中的每个单元格。使用Cells[row,col]的格式引用,row表示行号,col表示列号。需要注意的是行号和列号都是从1开始的,而不是像C#的数组是从0开始。例如Cells[2,2]就表示表格的第二行,第二列的单元格。下面是产生盈利状况统计报表的编辑表格代码(该段代码添加在MakePieChart函数末尾,其中的变量延用之前的声明):
//为表格设定标题
ws.Cells[1, 1] = "收入(万元)";
ws.Cells[1,2] = "类别";
ws.Cells[1,3] = "所占比重";
//将数据写入表格
for(int i=0;i<dsIncome.Tables[0].Rows.Count;i++)
{
ws.Cells[i+2,1] = MyCategory[i].ToString();
ws.Cells[i+2,2] = MyCategoryName[i];
int Percent = MyMonthIncome[i]*100/IncomeSum;
ws.Cells[i+2,3] = Percent.ToString() + "%";
}
//将总收入写入表格
ws.Cells[dsIncome.Tables[0].Rows.Count + 2,1] = IncomeSum.ToString();
ws.Cells[dsIncome.Tables[0].Rows.Count + 2,2] = "总和";
ws.Cells[dsIncome.Tables[0].Rows.Count + 2,3] = "100%";
Step4 导出表格
导出表格使用Worksheet对象的Export方法,将表格导出为Excel文件即可。考虑到可能出现异常,使用了try,catch来捕获可能出现的异常,输出错误信息。
try
{
//输出Excel报表到服务器文件系统
ws.Export(Server.MapPath(" ") + @"/Excel/report.xls", OWC.SheetExportActionEnum.ssExportActionNone);
}
catch
{
//错误时输出错误提示
Info.Text = "保存报表错误,请与管理员联系";
}
将上述代码添加到MakePieChart函数的末尾,重新运行,在工程所在文件夹下的子Excel目录中就会有report.xls文件。其结果如图18-19。
       
        图18-19 生成报表结果图
小结
这一章先对ASP.NET中生成统计图表进行了介绍,然后对GDI+与Office Web Components的使用进行了详细说明,为后面做好了知识储备。随后利用公司盈利状况统计和公司收入分块图两个实例详细的介绍了如何利用Office Web Components与数据库结合绘制统计图表以及生成报表。
通过本章的学习,读者对于.NET中统计报表的生成有了深刻的理解,相信精美、清晰的报表一定会为成为Web程序的亮点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值