WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

ダウンロードは別ウィンドウで

by WebSurfer 6. August 2010 20:52

ファイルをダウンロードする際、ダウンロード後にも何かの処置を継続し、その結果を表示したい場合はどうすればいいのでしょう?

例えば、Button をクリックするとポストバックがかかり、その Click イベントのハンドラでファイルをダウンロードし、その後そのページを継続して表示するが、ダウンロード後は表示したくない部分がある場合を考えて見ます。

ファイルダウンロード後ページの一部を隠す

ダウンロード後は表示したくない部分を Panel に入れて、Click イベントで Panel.Visible プロパティを false に設定するという手段を考えると思います。

しかしながら、ファイルのダウンロードとその処置を 1 ページで行うとうまくいきません。

何故なら、ボタンがクリックされてポストバックがかかり、サーバーから送られてくるのは HTTP 応答ヘッダとダウンロードされるファイルのバイト列だけだからです。

ボタンクリック後もポスト前の画面が表示されているのは、ブラウザにポスト前の画面が保持されているからで(ここのところ確証はないのですが)、ポストバック後サーバーから送られてきたものが表示されているわけではありません。前の画面だから、Panel の中身は表示されたままです。

Response.End(), Response.Flush() などをしなかったら、Download も処置の継続もうまくのではと思って、いろいろ試してみましたが、1 ページで処置するのは無理でした。

というわけで、ファイルをダウンロードする別のページを作って、それを呼び出すのがよさそうです。例えば、以下のような感じです。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  protected void Button1_Click(object sender, EventArgs e)
  {
     Panel1.Visible = false;
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>ファイルダウンロード</title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h1>ファイルダウンロード後に以下の部分を隠す</h1>
    <asp:Panel ID="Panel1" runat="server">
      <div style="background-color: Silver">
        <h2>隠す部分</h2>
        <asp:Button ID="Button1" 
          runat="server" 
          Text="Download" 
          onclick="Button1_Click" 
          OnClientClick="window.open('Download.aspx', null);" />
     </div>
   </asp:Panel>    
  </div>
  </form>
</body>
</html>

ダウンロードを行う別ページは、何をどのようにダウンロードするかによって千差万別ですが、DB からデータを取得して CSV ファイルにしてダウンロードする場合の例を、ついでにアップしておきます。

この例では、デリミタに使っている改行やコンマがフィールドに含まれているとうまくいませんので注意してください。

<%@ Page Language="C#" ContentType="application/octet-stream" 
ResponseEncoding="Shift_JIS" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  protected void Page_Load(object sender, EventArgs e)
  {        
    string connString = 
      ConfigurationManager.ConnectionStrings["Pubs"].ConnectionString;
    string query = "SELECT * FROM employee";
    SqlConnection sqlConn = new SqlConnection(connString);
    SqlCommand sqlCmd = new SqlCommand(query, sqlConn);
    string csvString = String.Empty;
    try
    {
      sqlConn.Open();
      SqlDataReader reader = sqlCmd.ExecuteReader();
      while (reader.Read())
      {
        for (int i = 0; i < reader.FieldCount; i++)
        {
          if (i == reader.FieldCount - 1)
          {
            csvString += reader[i].ToString() + "\r\n";
          }
          else
          {
            csvString += reader[i].ToString() + ",";
          }
        }
      }
    }
    finally
    {
      sqlConn.Close();
    }

    Encoding encode = Encoding.GetEncoding("shift_jis");
    Response.AppendHeader("Content-Disposition", "attachment; filename=test.csv");
    Response.Write("Employee ID,First Name,Middle Initial,Last Name,Job ID,Job Level,Pub ID,Hire Date\r\n");
    Response.BinaryWrite(encode.GetBytes(csvString));
    Response.End();
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>無題のページ</title>
</head>
<body>
  <form id="form1" runat="server">
  <div>    
  </div>
  </form>
</body>
</html>

なお、IE8 の場合、空白のウィンドウが一旦開いてしまい、「ファイルのダウンロード」ダイアログのボタンをクリックするまで閉じないという気に入らない点があります。

今のところ回避策が見つかっていません。回避策をご存知の方はアドバイスいただけるとうれしいです。

Tags: ,

Upload Download

ハイパーリンクで window.open

by WebSurfer 4. August 2010 12:18

ハイパーリンクを利用して小窓を開く場合、以下の例のようにするのがアクセシビリティの面で好ましいそうです。

<a href="xxx.html" onclick="window.open(this.href, ...); return false;">小窓</a>

window.open(this.href, ...) の ... の部分には第 2, 3 引数が入ります。

第 2 引数は MDN の記事「window.open」によると以下のように設定するそうです。(以前は、特に指定する必要がなければ null で良いと思っていたのですが、'_blank' とした方がよさそうです)

  1. 新しいウィンドウの名前
  2. 既存のウィンドウに第 1 引数の url をロードしたい場合は既存のウィンドウの名前
  3. window.open で常に新しいウィンドウを開きたい場合は '_blank'

第 3 引数は、ウィンドウの大きさや、メニューバーの有無などを指定します。以下のような感じです。

'width=400, height=300, menubar=no, toolbar=no, location=no'

なお、href="window.open(...);" とするのはうまくいきません。小窓が開いた後、元ページは window.open(...) を表示しようとするからです。そういえば、昔、元ウィンドウが [object] という表示になってしまう理由が分からず、かなり悩んだことがありました。(汗)

href="window.open(...); retrun false;" とすれば上記の問題は避けられますが、JavaScript が無効だと小窓どころか何も表示されないので、アクセシビリティの面で好ましくないそうです。

表題とは関係ない話ですが、昔、上記の例のとおり DataGrid コントロールの HyperLinkColumn に設定するにはどうしたらいいか悩んだこともありました(特に onclick 属性の設定)。

調べてみると、HyperLinkColumn の中にできるのは HyperLink オブジェクトなので、DataGrid の ItemDataBound イベントのハンドラで HyperLink を探して、Attributes["onclick"] に無理やり window.open を設定した記憶があります。

そんな面倒なことをしなくても、ItemTemplate に HyperLink コントロールを配置すれば簡単にできたのに・・・いろいろと未熟だったなぁ。まぁ、今でもそうですけど。(苦笑)

Tags:

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  July 2021  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar