最近在使用Report Service做报表,客户要求报表要以表格形式和图形形式显示,当时我想直接修改ReportViewer的工具栏。于是上网查了相关资料,发现这样方案不太可能,就算能够动态增加按钮,但是对于后台处理也比较麻烦,从通用性上考虑也不太乐观。
后来看到客户端的代码,如下:
ReportViewer发到客户端其实就是div加table。突然萌生了一种想法,就是通过js前台动态加按钮,然后回传给服务器处理。
实现效果图:
前台脚本使用的是jQuery,选择jQuery的原因有两个:一、使用起来简单;二、浏览器兼容性支持的好。
为了这段代码通用,开发人员用起来方便,利用了jQuery的($.extend())功能。
插件代码如下:
//ReportViewer控件增加工具按钮 (function() { $.extend($.fn, { methods: { createButton: function(width, height, type, uri, controlId) { var A = $("<a></a>"); A.attr("id", type + "_" + "graph"); A.attr("href", "###"); A.attr("uri", uri); A.css("margin-left", "5px"); var img = $("<img />"); img.attr("src", "../img/" + type + ".png"); img.css("width", width); img.css("height", height); img.css("margin-top", "4px"); A.prepend(img); A.click(function() { $("input[id$='hid" + controlId + "']").val($(this).attr("uri")); var lb = $("a[id$='lb" + controlId + "']"); __doPostBack(lb.attr("id").replace(/_/g, "$"),''); }); return A; } }, ReportViewAddTool: function(options) { options = $.extend({ width: 15, height: 15, url: { table: "###" }, controlId: "CallBack" }, options); //按钮图片的宽度与高度 var width = options.width; var height = options.height; var url = options.url; var controlId = options.controlId; var toolbar = $(this).children("div").eq(0); //创建图片按钮的div var div = $("<div id='divRVT'></div>"); div.css({ "display": "inline", "font-family": "Verdana", "height": "30px", "font-size": "8pt" }); $.each(url, function(k, v) { div.prepend($.fn.methods.createButton(width, height, k, v, controlId)); }); toolbar.children("div").eq(0).append(div); } } ); })(jQuery);
客户端实例代码:
<script type="text/javascript"> $(function() { $(".reportTool").ReportViewAddTool({ url: { table: "SettleSheetRecycleStatistic", column: "SettleSheetRecycleStatisticGraph"} }); }); </script> <div class="divReportV"> <rsweb:ReportViewer ID="rvPayPlan" runat="server" Width="1000px" Height="390px" Visible="true" CssClass="reportTool"> </rsweb:ReportViewer> <asp:HiddenField ID="hidCallBack" runat="server" /> <asp:LinkButton ID="lbCallBack" runat="server" OnClick="lbCallBack_Click"></asp:LinkButton> </div>
报表实现的核心思想就是aspx页面通过ReportViewer控件去请求不同的rdl报表文件去显示不同的报表,这些报表可以是图形报表或表格报表。
见上代码核心的方法就两个ReportViewAddTool和createButton,ReportViewAddTool方法是提供给用户使用的接口,createButton是内部用来创建按钮的。
createButton: function(width, height, type, uri, controlId)
width:图片按钮的宽度
height:图片按钮的高度
type:报表类型(表格、柱状图、饼状图、线状态等等)
uri:每种报表类型对应的rdl文件名
controlId:回发控件的Id
这个方法实现细节主要是图片、A标签的构建。当时在实现的时候遇到了一个头疼的问题,就是A.Click事件回传服务器的时候,那个服务器端控件(LinkButton)触发不了,一般通过js提交是通过__doPostBack方法。因为在实际项目中,我们做的页面不是简单的页面,有可能是有模板页,有可能是用户控件等等。所以有些控件的ID发到客户端会改变。
A.click(function() { $("input[id$='hid" + controlId + "']").val($(this).attr("uri")); var lb = $("a[id$='lb" + controlId + "']"); __doPostBack(lb.attr("id").replace(/_/g, "$"),''); });
上面代码就是解决父子控件问题的,解决的思想就是:不管它的id怎么变,它们都是以最初的id为结尾的。通过jQuery强大的选择器很容易就可以找到元素。
细心的朋友会发现lb.attr("id").replace(/_/g, "$")这段代码,功能是将客户端的id中的”_”符号替换成”$”字符。这段代码很重要,要不然服务器端方法触发不了(控件存在于父控件中)。
下面谈谈提供给用户的接口:
ReportViewAddTool: function(options) { options = $.extend({ width: 15, height: 15, url: { table: "###" }, controlId: "CallBack" }, options); }
调用方法
$(".reportTool").ReportViewAddTool({ url: { table: "SettleSheetRecycleStatistic", column: "SettleSheetRecycleStatisticGraph"} });
这边为了简单起见只生成了表格类型的按钮(table)和状图案类型的按钮(column)。
引号里的内容是rdl文件名(回发时请求不同的报表内容)
在页面设计中,另外需要使用两个控件:隐藏域控件(用于保存rdl文件名,供服务器端处理使用)和LinkButton控件(担任Handler角色,处理用户请求)
<asp:HiddenField ID="hidCallBack" runat="server" /> <asp:LinkButton ID="lbCallBack" runat="server" OnClick="lbCallBack_Click"></asp:LinkButton>
隐藏控件为了保存rdl文件名,LinkButton用于触发后台方法。
实现效果图:
图1:
图2: