在事件处理程序结束时执行javascript代码

时间:2014-02-07 17:30:37

标签: c# javascript asp.net loading

我正在用C#在ASP.NET上构建一个Web应用程序。 在按钮上单击我显示加载图像,同时正在执行数据库查询。然后我动态创建一个Excel文件并将其发送到客户端,如下所示:

HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=" + filename + ".xlsx");
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.Unicode;
HttpContext.Current.Response.BinaryWrite(p.GetAsByteArray());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End(); 

我收到对话框,加载图片就在那里。

我尝试在上面的代码之前调用一个javascript函数(使用ClientScript.RegisterStartupScript函数),它没有用。据我所知,所有javascript代码都是在所有代码隐藏执行后运行的,但在这种情况下,一旦将文件发送到客户端,它就不会执行。

我还尝试创建一个单独的线程,并删除那里的加载图像。我把断点跟踪它,线程中的代码确实执行,但图像仍然存在。

有没有人知道如何处理这个问题?谢谢!

3 个答案:

答案 0 :(得分:3)

您只能在一个请求/响应周期中发送或传输1 mime类型。 (我在这方面的知识是值得商榷的。)

那就是说,你可以围绕这个设计一个黑客。在客户端上使用iframe“下载文件”。您可以将其src指向执行相同操作的ashx文件。

您需要连接iframe的onload事件,以便您的网页知道下载已完成;这就是你可以执行逻辑的地方。

解决方案更新:

好吧,经过挖掘,已经发现我的答案是半生不熟

问题是iframe在下载后不会触发onload事件。如果src指向的url实际导航到另一个页面,onload事件将触发iff。我想这是设计的。我今天学到了

那么解决方法是什么?!

幸运的是,您可以将cookie传输到客户端。在客户端上,您的网页必须继续轮询此cookie的存在。因此,一旦您的网页能够检测到cookie的存在,这意味着浏览器已完成下载请求。以下帖子对此进行了详细讨论:

http://geekswithblogs.net/GruffCode/archive/2010/10/28/detecting-the-file-download-dialog-in-the-browser.aspx

我将向您展示一些与处理程序文件(模拟下载)和客户端(具有iframe完成工作)相关的代码。这应该给你的要点:

<强> WebForm1.aspx的:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApp.FileDownload.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>iFrame Download</title>
    <script type="text/javascript" src="Scripts/jquery-2.1.0.min.js"></script>
    <script type="text/javascript" src="Scripts/jquery.cookie.js"></script>
    <script type="text/javascript">
        function foo() {
            console.log('foo');
            //execute post-download logic here
        }
        $(function () {            
            $('input').click(function () {
                //make sure we get rid of the 
                //cookie before download
                $.removeCookie('downloaded');

                var intrvl = setTimeout(function () { //this function polls for the cookie through which we track that the file has indeed been downloaded
                    console.log('timer');
                    var value = $.cookie('downloaded');
                    if (value == 'true') {
                        clearTimeout(intrvl);
                        foo();
                    }
                }, 1000);

                //this initiates the download
                $('iframe').attr({
                    'src': 'download.ashx?id=' + $('#tbxRandomNumber').val()
                });

            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="tbxRandomNumber" runat="server"></asp:TextBox>
        <input type="button" value="Download" />
        <iframe src="about:blank" style="display:none"></iframe>
        <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Next Random Number" />
    </div>
    </form>
</body>
</html>

我已经使用jquery cookies plugin来帮助我处理Cookie。

<强> download.ashx:

using System;
using System.Web;

namespace WebApp.FileDownload
{
    /// <summary>
    /// Summary description for download
    /// </summary>
    public class download : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {            
            context.Response.ContentType = "text/plain";
            context.Response.SetCookie(new HttpCookie("downloaded","true")); //setting cookie in the response
            string id = context.Request.QueryString["id"] == null ? "NULL" : context.Request.QueryString["id"];
            string str = string.Format("Content with id {0} was generated at {1}", id, DateTime.Now.ToLongTimeString());

            context.Response.AddHeader("Content-Disposition", "attachment; filename=test.txt");
            context.Response.AddHeader("Content-Length", str.Length.ToString());
            context.Response.Write(str);
            context.Response.End();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

答案 1 :(得分:1)

看起来你在这里有一些误解。您只有一个请求,以及来自服务器的一个响应。创建新线程只会在服务器上发生,并且不会创建其他响应。

当您发送Excel文件时,您正在使用:

HttpContext.Current.Response.Clear();

通过清除响应,您将丢失之前添加的JavaScript。它永远不会到达客户端。

如果处理相当简单(总是只需几秒钟),我只需将加载动画设置为运行几秒钟并通过在初始onclick事件上设置超时来停止。它并不完美,但它会给用户一些即时反馈。

如果处理过程需要很长时间或很长时间,那么动画更重要。您可以尝试在隐藏的<iframe>中加载Excel文件,并附加onload事件以删除加载动画。

您需要创建一个单独的页面来处理生成Excel文件,而不是在服务器端OnClick处理程序中执行。但是,我似乎记得在onload上对<iframe>事件的支持可能与旧的IE版本不一致。

答案 2 :(得分:0)

在浏览器中加载页面时,javascript在客户端中运行。您可能有一个隐藏的文本框,在您活动结束时,您可以将值放入该文本框中:

txtHidden.Text = "Hola Mundo"

您必须检查页面加载时的值:

<script type="text/javascript">
$(document).ready(function(){
  if($("#txtHidden").length > 0 && $("#txtHidden").val() != '')
  {
    alert($("#txtHidden").val());
  }
});
</script>

您可以将其置于Web用户控件中。 另一种解决方案:

<div class='button' id='btnGenerateDownload' onClick='GenerateDownload(this)'>
 Click here <div id='loadingImage' class='loadingImage'></div>
</div>

JQuery的:

function GenerateDownload(caller)
{
   //add loading gif:
   var $loagingGIF = $(caller).children('#loadingImage').eq(0);
   $loagingGIF.addClass('loadingImage');
   var fileGeneratorUrl = 'ghFileGenerator.ashx';
   var downloadHandlerUrl = 'ghDownloadHandler.ashx';
   $.post({data: "File1"}, function(response){
     //remove gif
     $loagingGIF.removeClass('loadingImage');
     if(response != '') //file key
     {
       downloadHandlerUrl += '?key=' + response;
       var $link = $("<a />").attr('href', downloadHandlerUrl).html('download');
       $link.appendTo($(caller));
     }
   });
}

的CSS:

.loadingImage{background: transparent url(images/loading.gif);}

.ashx的:

 string filekey = context.Current.Request.Form("key");