WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

ユーザー入力のリセット

by WebSurfer 2012年4月29日 23:44

ユーザーが TextBox や CheckBox に入力した文字、チェックをクリアするという話です。

ユーザー入力のリセット

html の <input type="reset" ... がユーザー入力をクリアするのに使えますが、あらかじめ TextBox.Text や ChechBox.Checked を設定してあると、それらはクリアできません。

また、一旦ポストバックすると TextBox には入力した文字列が(html では <input type="text" ... の value 属性の文字列)、CheckBox にはチェックした結果(html では <input type="checkbox" ... の checked 属性)が設定されるはずです。

その状態では <input type="reset" ... では TextBox も CheckBox もクリアできません。もともと <input type="reset" ... は、元に戻すということらしく、完全にクリアするということではないようです。

完全にクリアするには、サーバー側で行う方法もありますが、わざわざポストバックしてサーバー側で処置するのはムダなので、クライアントスクリプトで対応するのがよさそうです。

JavaScript でも可能だと思いますが、複数の input 要素に同じ処置を繰り返すので jQuery を使うのが簡単です。以下のコードような感じです。

実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

<%@ 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">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[

    // [Uncheck All]ボタンクリックで、すべての TextBox, 
    // CheckBox のチェックを外す。
    $(function () {
      $('#clearAll').click(function () {
        $('input:checkbox').attr('checked', false);
        $('input:text').val("");
      });
    });

  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <div>        
    <input type="button" 
      id="clearAll" value="jQuery でクリア" />
    <br />
    <input id="Reset1" 
      type='reset' value="input type='reset'" />
    <hr />
    <asp:TextBox ID="TextBox1" 
      runat="server" Text="ABC">
    </asp:TextBox>
    <br />
    <asp:TextBox ID="TextBox2" runat="server">
    </asp:TextBox>
    <br />
    <asp:CheckBox ID="CheckBox1" 
      runat="server" Checked="True" />
    <br />
    <asp:CheckBox ID="CheckBox2" runat="server" />
    <br />
    <asp:Button ID="Button1" 
      runat="server" Text="PostBack" />
  </div>    
  </form>
</body>
</html>

Tags: ,

JavaScript

@OutputCache ディレクティブ

by WebSurfer 2012年4月28日 16:50

@ OutputCache ディレクティブ を使ったキャッシュの設定方法は、MSDN ライブラリなどを検索するといろいろ見つかりますが、結局読んでもよく分かりません。(笑)

という訳で、実際にコードを書いて試して見ました。今回調べたのは Location 属性の設定によってどう変わるかということです。いろいろ発見があったので、忘れないように書いておきます。

まず、@ OutputCache ディレクティブを設定しない場合ですが、その場合はサーバーではキャッシュされません。

応答ヘッダは以下のようになりますので、コンテンツはブラウザのユーザー専用キャッシュにのみキャッシュされます。

Cache-Control: private
Date: Sat, 28 Apr 2012 01:44:22 GMT

ただし、ASP.NET ページには有効期限がないため、キャッシュは常に古いと見なされます。そのため、ASPX リソースをリクエストすると、ページがキャッシュされてない場合と同じように、常にサーバーから新しいリソースを取得することになります。

次に、例として、@ OutputCache ディレクティブを以下のように設定した場合、キャッシュがどのように設定されるかを書きます。

<%@ OutputCache 
    Duration="15" 
    Location="xxxxx" 
    VaryByParam="None" %>

Location 属性の xxxxx のところには、None, Client, Downstream, Server, ServerAndClient, Any(デフォルト)のいずれかを指定します。結果はそれぞれ以下のようになります。

(1) None

ブラウザ、プロキシ、サーバーいずれでもキャッシュされません。

ブラウザおよびプロキシにキャッシュの方法を指示する HTTP 応答ヘッダは以下のようになります。

Cache-Control: no-cache
Date: Sat, 28 Apr 2012 01:45:43 GMT
Expires: -1
Pragma: no-cache

なお、Duration と VaryByParam は必須属性ですが、Location="None" と設定してあると Duration を設定しなくてもエラーにはなりません。逆に、Duration が設定してあっても無視されるようです。

(2) Client

ブラウザのみでキャッシュされます。サーバーではキャッシュされません。

応答ヘッダは以下のようになります。

Cache-Control: private, max-age=15
Date: Sat, 28 Apr 2012 02:49:17 GMT
Expires: Sat, 28 Apr 2012 02:49:32 GMT

(3) Downstream

ブラウザおよびプロキシ(もしあれば)のみでキャッシュされます。サーバーではキャッシュされません。

応答ヘッダは以下のようになります。

Cache-Control: public, max-age=15
Date: Sat, 28 Apr 2012 02:56:09 GMT
Expires: Sat, 28 Apr 2012 02:56:24 GMT

(4) Server

サーバーのみでキャッシュされます。Duration 属性に指定した時間が経過すると、キャッシュは破棄されます。その後に要求を受けると、その応答コンテンツが再びキャッシュされます。

応答ヘッダは以下のようになりますので、ブラウザとプロキシではキャッシュされません。

Cache-Control: no-cache
Date: Sat, 28 Apr 2012 02:28:31 GMT
Expires: -1
Pragma: no-cache

なお、サーバーキャッシュは GET 用と POST 用の 2 種類生成されることに注意してください。下に示した検証用のコードで、Duration を十分長い時間にとって、GET で要求した時と、POST で要求した時とで、ラベルに表示される時間を比較してみてください。違う値になるはずです。

(5) ServerAndClient

サーバーとブラウザでキャッシュされます。

応答ヘッダは以下のようになります(Client の場合と同様)。

Cache-Control: private, max-age=15
Date: Sat, 28 Apr 2012 02:37:17 GMT
Expires: Sat, 28 Apr 2012 02:37:32 GMT

(6) Any

ブラウザ、プロキシ、サーバーのすべてでキャッシュされます。

応答ヘッダは以下のようになります(DownStream の場合��同様)。

Cache-Control: public, max-age=15
Date: Sat, 28 Apr 2012 02:18:21 GMT
Expires: Sat, 28 Apr 2012 02:18:36 GMT

なお、Location 属性はデフォルトで Any ですので、Location="Any" を削除しても結果は同じになります。

上に述べた、検証に使ったコードは以下の通りです。

<%@ Page Language="C#" %>
<%@ OutputCache Duration="3600" 
    Location="Server" 
    VaryByParam="None" %> 

<!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)
    {
        Label1.Text = DateTime.Now.ToString();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" 
            runat="server" 
            Text="Button" />
        <asp:Label ID="Label1" runat="server">
        </asp:Label>
    </div>
    </form>
</body>
</html>

最後に、今回参考にしたキャッシュ関係の記事のリンクを張っておきます。

Web 2.0 アプリケーションのパフォーマンスを改善する

プロキシキャッシュ対策

ブラウザキャッシュでパフォーマンス向上

Tags:

Cache

__doPostBack を使ってはいけません

by WebSurfer 2012年4月21日 13:12

プログラマが、ASP.NET が自動生成する __doPostBack という名前の JavaScript 関数を、直接自分のコードに使ってはいけないという話です。

GridView で[選択]ボタンを使わないでポストバックをかけ、SelectedIndexChanged イベントで選択された行を取得

ASP.NET には、クライアントのイベントでサーバーにデータをポストバックするための、クライアントスクリプトを自動生成する機能があります。

それが表題の __doPostBack という名前の JavaScript の関数です。

例えば、GridView で、AutoGenerateSelectButton プロパティを true に設定すると[選択]ボタンが表示されますが、そのハイパーリンクに __doPostBack 関数が以下のように自動的に設定されます(ASP.NET 4 では ' はエスケープされて &#39; になります)。

<td>
  <a href="javascript:__doPostBack('GridView1','Select$0')">
    選択
  </a>
</td>

引数は、前者がデータを受け取って処置をするサーバーコントロールの UniqueID(上の例では GridView1)、後者がイベントデータ(上の例では Select$0 ⇒ 行インデックス 0 が Select されたという意味)になります。

__doPostBack 関数は、この 2 つの引数をそれぞれ __EVENTTARGET と __EVENTARGUMENT という id を持つ隠しフィールドに格納してから form を submit します。

この __doPostBack 関数や隠しフィールドは公開されてないので、将来なにもアナウンスされず変更される可能性があります。なので、プログラマがこの関数や隠しフィールドを使ってコーディングするのは避けた方がよさそうです。

代わりに、GetPostBackEventReference メソッドRaisePostBackEvent メソッド を使うのがお勧めです。

その例は、このブログの先の記事 CheckBox 付き Calendar コントロール でも紹介していますが、ここでも GridView を使って一例を紹介します。

上の画像は、GridView で[選択]ボタンを使わないで、行クリックでポストバックをかけ、SelectedIndexChanged イベントで選択された行を取得するサンプルです。__doPostBack 関数を直接使わないで、GetPostBackEventReference メソッドと RaisePostBackEvent メソッドを使って実現しています。

そのコードは以下の通りです。解説は、コードの中にコメントで書きましたので、そちらを参考にしてください。手抜きですみません。(笑)

実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>

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

<script runat="server">

  // GridView で[選択]ボタンを使わないでポストバックをかけて
  // SelectedIndexChanged イベントで選択された行を取得。
  // ASP.NET AJAX の UpdatePanel を使っているのはオマケ。
    

  // 選択された行をチェックして SelectedIndexChanged イベント
  // を発生させるため RaisePostBackEvent メソッドを override 
  // する。そのため GridView を継承したカスタムコントロールを
  // 作る。
  public class MyGridView : GridView
  {
    // GetPostBackEventReference メソッドで設定したクライアント
    // スクリプト(この例では、下の myGridView_RowCreated イベ
    // ントハンドラで設定している)が起動されると、ポストバッ
    // クがかかり、サーバー側で RaisePostBackEvent メソッドが
    // 起動される。引数 arg には、クライアントスクリプトで設定
    // した GridView の行インデックスが渡される。
    protected override void RaisePostBackEvent(string arg)
    {
      int index;
      bool result = Int32.TryParse(arg, out index);

      if (result)
      {
        if (this.SelectedIndex != index)
        {
          this.SelectedIndex = index;
          this.OnSelectedIndexChanged(EventArgs.Empty);
        }
      }

      base.RaisePostBackEvent(arg);
    }        
  }
    
  // データソース用の DataTable を作成
  protected DataTable CreateDataTable()
  {
    DataTable dt = new DataTable();
    DataRow dr;

    dt.Columns.Add(new DataColumn("ID", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Name", typeof(string)));
    dt.Columns.Add(new DataColumn("Price", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Qty", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Amount", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Remarks", typeof(string)));

    for (int i = 0; i < 5; i++)
    {
      dr = dt.NewRow();
      dr["ID"] = i;
      dr["Name"] = "Item " + i.ToString();
      dr["Price"] = 123000 * (i + 1);
      dr["Qty"] = i + 1;
      dr["Amount"] = 123000 * (i + 1) * (i + 1);
      dr["Remarks"] = "Remarks " + i.ToString();
      dt.Rows.Add(dr);
    }
    return dt;
  }

  protected void Page_Load(object sender, EventArgs e)
  {
    MyGridView myGridView = new MyGridView();
    myGridView.ID = "myGridView1";
    myGridView.RowCreated += 
      new GridViewRowEventHandler(myGridView_RowCreated);
    myGridView.SelectedIndexChanged += 
      new EventHandler(myGridView_SelectedIndexChanged);
    TableItemStyle tableStyle = myGridView.SelectedRowStyle;
    tableStyle.BackColor = System.Drawing.Color.Blue;
    tableStyle.ForeColor = System.Drawing.Color.White;
        
    PlaceHolder1.Controls.Add(myGridView);
        
    if (!IsPostBack)
    {
      myGridView.DataSource = CreateDataTable();
      myGridView.DataBind();
    }
  }

  protected void myGridView_RowCreated(
    object sender, GridViewRowEventArgs e)
  {
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
      // __doPostBack("<UniqueID>", "<RowIndex>") という
      // クライアントスクリプトの文字列が生成される。
      string script =
        Page.ClientScript.GetPostBackEventReference(
          (GridView)sender,
          e.Row.RowIndex.ToString());
            
      // データ行の tr 要素の onclick 属性に、上で生成
      // したスクリプトを設定する。
      e.Row.Attributes["onclick"] = script;
            
      // カーソルを指型にする
      e.Row.Style["cursor"] = "pointer";
    }
  }

  protected void myGridView_SelectedIndexChanged(
    object sender, EventArgs e)
  {
    Label1.Text = "SelectedIndex: " + 
      ((GridView)sender).SelectedIndex.ToString();
  }
   
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <asp:ScriptManager ID="ScriptManager1" runat="server">
  </asp:ScriptManager>
  <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
      <asp:PlaceHolder ID="PlaceHolder1" 
        runat="server">
      </asp:PlaceHolder>
      <asp:Label ID="Label1" runat="server">
      </asp:Label>
    </ContentTemplate>
  </asp:UpdatePanel>
  </form>
</body>
</html>

Tags:

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar