2014-02-07 109 views
3

我正在ASP.NET上用C#构建一个Web应用程序。 在按钮上单击时,显示正在执行数据库查询时的加载图像。然后,我动态创建一个Excel文件,并将其发送给客户端这样的:在事件处理程序结束时执行javascript代码

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代码都是在所有代码执行完毕后运行的,但在这种情况下,一旦文件发送到客户端,它就完全不执行。

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

有没有人有一个想法如何处理?谢谢!

+0

你是不是在这里发送的HTML页面。浏览器正在接收excel文档或将其提供给用户下载,因此没有页面。没有页面 - 没有JavaScript被执行。 – Andrei

+0

@Andrei,我看到谢谢你。 – gg17

回答

3

您只能在一个请求/响应周期中发送或传输1个MIME类型。 (我在这方面的知识是有争议的)。

这就是说,你可以设计一个破解这个。在客户端上使用iframe来“下载文件”。您可以将它的src指向一个相同的ashx文件。

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

解决方案更新:

好,周围挖掘后,“已经发现了我的答案是半生不熟

问题是iframe在下载内容后不会触发它们的onload事件。如果存在src指向的url实际导航到不同的页面,onload事件将触发。这是我设想的。我今天学到了

那么,解决方法是什么?

幸运的是,您可以将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; 
      } 
     } 
    } 
} 
+0

我可以给你举个例子,但是我可以在星期一到达一个合适的电脑,IST :) – deostroll

+0

很好,谢谢!我会在此进行更多搜索,但请在周一举例。 – gg17

+0

哇!太棒了!你帮了我!非常感谢!!! – gg17

1

它看起来像你有一对夫妇的误解在这里。您只有一个请求,并且只有一个来自服务器的响应。创建新线程只会发生在服务器上,并且不会创建额外的响应。

当你发送的Excel文件,你使用:

HttpContext.Current.Response.Clear(); 

通过清除反应,你正在失去你以前添加JavaScript的。它永远不会到达客户端。

如果处理过程相当微不足道(通常只需几秒钟),我只需将加载动画设置为运行几秒钟并停止,方法是在初始onclick事件中设置超时。这并不完美,但它会给用户一些即时的反馈。

如果处理过程需要花费很长的时间或变化很多的时间,那么动画对于正确使用更重要。您可以尝试加载隐藏的中的Excel文件,并附加onload事件以删除加载动画。

您需要创建一个单独的页面来处理生成Excel文件,而不是在服务器端OnClick处理程序中执行。不过,我似乎记得上onload事件的支持对于较早的IE版本来说可能很少见。

+0

对不起,这与我没有看到的deostroll基本相同。 – Nevett

+0

谢谢你解释! – gg17

0

JavaScript在浏览器中加载页面时在客户端运行。你可能有一个隐藏的文本框,在你活动结束哟可以把一个值到该文本框:

txtHidden.Text = "Hola Mundo" 

你必须检查在页面加载的值:

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

你可以把这个在网络用户控制中。 另一种解决方案:

<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"); 
相关问题