摘要
本文介绍一个免费的、完整的、very easy 的在Web页和RDLC报表中呈现、打印条码的解决方案。
效果
笔者最近遇到了一个B/S结构的项目,需要在报表中打印条码。效果如下
恰巧,笔者不久前在网上找到了一个免费的条码控件,请见下图
这是由昆明科本软件有限公司推出的一款十分不错的条码控件,支持十余种国际通用的条码格式,生成的图片的大小和样式可调。可以由此下载
科本条形码主页,现在已经升级到了1.5版,附带示例工程。(我使用的时候还是1.0版,包括本篇文章的示例代码所使用的也是1.0版控件)。
可惜这个控件只支持Windows程序。我想在Web程序中使用,能办到么?答案是肯定的,因为这个控件非常体贴地提供了一个 MakeImage() 函数,直接使用这个函数就能获得条码图片。哈哈,看过本系列第三篇《动态生成图片》的朋友可能已经心中雪亮了,没错,使用同样的路数就可以将它用在Web程序中了。我为制作了一个示例程序,可以在本文的最后下载。
示例程序详解
MyHandler.cs与第三篇看起来差不多,只不过生成图片的工具由 GDI+ 变成了条码控件。为了使用条码控件,需要在 mylib.system.web 类库里添加对条码控件(“barcode.dll”)和System.Windows.Form的引用
为了使用RDLC报表,我们的数据源由第三篇中的数组改成了一个Domain Object:
VisitorTraffic.cs
1 using System;
2 using System.Data;
3 using System.Configuration;
4 using System.Web;
5 using System.Web.Security;
6 using System.Web.UI;
7 using System.Web.UI.WebControls;
8 using System.Web.UI.WebControls.WebParts;
9 using System.Web.UI.HtmlControls;
10 using System.Collections.Generic;
11
12 /// <summary>
13 /// VisitorTraffic 的摘要说明
14 /// </summary>
15 public class VisitorTraffic
16 {
17 private string _website_name;
18 private string _visitor_traffic;
19
20 public static List<VisitorTraffic> find_all()
21 {
22 List<VisitorTraffic> result = new List<VisitorTraffic>();
23 result.Add(new VisitorTraffic("1. 使用分治法实现的全排列算法", "50"));
24 result.Add(new VisitorTraffic("2. 让Ruby的数组支持任意起始下标", "16"));
25 result.Add(new VisitorTraffic("3. 输出二叉树的方法", "14"));
26
27 return result;
28 }
29
30 public VisitorTraffic(string website_name, string visitor_traffic)
31 {
32 _website_name = website_name;
33 _visitor_traffic = visitor_traffic;
34 }
35
36 public string website_name
37 {
38 get { return _website_name; }
39 set { _website_name = value; }
40 }
41
42 public string visitor_traffic
43 {
44 get { return _visitor_traffic; }
45 set { _visitor_traffic = value; }
46 }
47 }
48
VisitorTraffic 类的两个属性 website_name 和 visitor_traffic 分别表示网页名称和访问量。静态函数 find_all() 通过硬编码的方式返回3条有用的数据。VisitorTraffic 类放置在Web应用程序的 App_Code 文件夹下。
Default.aspx 中放置一个 GridView 控件和和一个 ReportViewer 控件。在Page_Load() 时初始化这两个控件。
Default.aspx
1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
2
3 <%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
4 Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
5 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6 <html xmlns="http://www.w3.org/1999/xhtml">
7 <head runat="server">
8 <title>无标题页</title>
9 </head>
10 <body>
11 <form id="form1" runat="server">
12 <div>
13 <asp:Label ID="Label2" runat="server" Font-Bold="True" ForeColor="#0000C0" Text="GridView:"></asp:Label>
14 <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="3"
15 GridLines="Vertical" BackColor="White" BorderColor="#999999" BorderStyle="None"
16 BorderWidth="1px">
17 <FooterStyle BackColor="#CCCCCC" ForeColor="Black" />
18 <Columns>
19 <asp:TemplateField HeaderText="网址">
20 <ItemTemplate>
21 <asp:Label ID="Label1" runat="server" Text='<%# Eval("website_name") %>'></asp:Label>
22 </ItemTemplate>
23 </asp:TemplateField>
24 <asp:TemplateField HeaderText="访问量">
25 <ItemTemplate>
26 <asp:Image ID="Image1" runat="server" ImageUrl='<%# "~/MyHandler.jxd?data=" + Eval("visitor_traffic") %>' />
27 </ItemTemplate>
28 </asp:TemplateField>
29 </Columns>
30 <RowStyle BackColor="#EEEEEE" ForeColor="Black" />
31 <SelectedRowStyle BackColor="#008A8C" Font-Bold="True" ForeColor="White" />
32 <PagerStyle BackColor="#999999" ForeColor="Black" HorizontalAlign="Center" />
33 <HeaderStyle BackColor="#000084" Font-Bold="True" ForeColor="White" />
34 <AlternatingRowStyle BackColor="#DCDCDC" />
35 </asp:GridView>
36 <br />
37 <asp:Label ID="Label3" runat="server" Font-Bold="True" ForeColor="#0000C0" Text="RDLC 报表:"></asp:Label>
38 <rsweb:ReportViewer ID="ReportViewer1" runat="server" Width="443px">
39 </rsweb:ReportViewer>
40 </div>
41 </form>
42 </body>
43 </html>
44
Default.aspx.cs
1 using System;
2 using System.Data;
3 using System.Configuration;
4 using System.Web;
5 using System.Web.Security;
6 using System.Web.UI;
7 using System.Web.UI.WebControls;
8 using System.Web.UI.WebControls.WebParts;
9 using System.Web.UI.HtmlControls;
10
11 using System.Collections.Generic;
12 using Microsoft.Reporting.WebForms;
13
14 public partial class _Default : System.Web.UI.Page
15 {
16 protected void Page_Load(object sender, EventArgs e)
17 {
18 // 为 GridView 设置数据源
19 GridView1.DataSource = VisitorTraffic.find_all();
20 GridView1.DataBind();
21
22 // 初始化报表
23 ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Report.rdlc");
24 ReportViewer1.LocalReport.EnableExternalImages = true; // 允许使用外部图片
25
26 // 获取 MyHandler.jxd 的完整路径
27 string barcode_url = Request.Url.Scheme + "://"
28 + Request.Url.Authority
29 + Request.ApplicationPath
30 + "/MyHandler.jxd?data="; //-> "http://localhost:6344/HttpHandlerDemo/MyHandler.jxd?data="
31
32 // 将 MyHandler.jxd 的完整路径通过报表参数传给报表
33 ReportViewer1.LocalReport.SetParameters(new ReportParameter[] { new ReportParameter("barcode_url", barcode_url) });
34
35 // 为报表设置数据源
36 ReportViewer1.LocalReport.DataSources.Add(
37 new Microsoft.Reporting.WebForms.ReportDataSource("VisitorTraffic", VisitorTraffic.find_all()));
38 }
39 }
40
GridView 的设置基本保持第三篇的样子没变,在此就不在赘述了。下面着重介绍一下在RDLC报表里呈现条码的方法。在RDLC报表里使用外部图片,需要
- 在代码中将报表对象的 EnableExternalImages 属性设为 true。
- 将“图像”控件放置在表控件中。
- 将“图像”控件的“Source”属性设为“External”。
- 将“图像”控件的“Value”属性设为图片的地址。
在进行到上面的第四步(将“图像”控件的“Value”属性设为图片的地址)时,麻烦出现了。天杀的比尔居然要求在“Source”属性为“External”的情况下,“Value”必须以 http://, https://, ftp://, file:, mailto:, 或 news: 之一开头。换句话说,不允许我将Value设成 "~/MyHandler.jxd?data="+ Fields!visitor_traffic.Value 这种相对路径。可是我在RDLC里如何能得到 MyHandler.jxd 的完整路径呀?!我曾经试过不用图像控件,直接在“访问量”字段中写 "<img src='~/MyHandler.jxd?data=" + Fields!visitor_traffic.Value + "' />"。期望能骗过RDLC,直接输出IMG标记,结果RDLC十分智能地把所有的“ <”字符全部替换成了< 痛哭十分钟...
最后只好用了比较龌龊的方法:先在 Default.aspx.cs 中取得 MyHandler.jxd 的完整URL,然后通过报表参数(参数名为barcode_url)传递给RDLC报表对象(Default.aspx.cs 第26~33行)。而图像控件的Value属性就变成:Parameters!barcode_url.Value + Fields!visitor_traffic.Value
下载本篇全部源代码
本系列到此就结束了。我们并没有介绍太多HTTP处理程序的理论知识,对HTTP Handler的利用也仅仅局限于将它作为一个“虚拟页面”,您看得一定十分不过瘾吧 ?HTTP 处理程序的另外一个重要的应用是实现URL重写,Scott Mitchell 的
《URL Rewriting in ASP.NET》对这个主题进行了深入的探讨,并给出了一个完整的解决方案。《
ASP.NET 2.0高级编程》一书有对HTTP模块的详细描述,可以
在线免费试读。希望本系列可以作为您通往精通HTTP处理技术之路的第一块垫脚石,再见。
本系列共6篇文章
实战 HTTP 处理程序(HTTP Handler) (6)——条码随意打 <- you are here.
实战 HTTP 处理程序(HTTP Handler) (5)——不用临时文件,直接打开动态生成的文件
实战 HTTP 处理程序(HTTP Handler) (4)——与Web程序共享Session
实战 HTTP 处理程序(HTTP Handler) (3)——动态生成图片
实战 HTTP 处理程序(HTTP Handler) (2)——向HTTP 处理程序传递参数
实战 HTTP 处理程序(HTTP Handler) (1)——创建一个最简单的 HTTP Handler