WebSurfer's Home

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

Validator の結果で背景を変更

by WebSurfer 2011年7月18日 21:49

RequiredFieldValidator や RegularExpressionValidator の検証結果が無効の場合、対象の TextBox の BackgroundColor を赤などの目立つ色にしてユーザーの注意をひくというサンプルです。

検証結果が無効の場合、対象 TextBox の背景を赤に変更

ヒントは Change Background Color of Invalid Controls (ASP.NET Validator) というページに紹介されていたコードですが、これは TextBox に対し、Validator が一つだけならうまくいきますが、二つあるとうまくいきません。

例えば RequiredFieldValidator と RegularExpressionValidator を組み合わせて使った場合、何も入力しない場合は後者の isvalid は true になって ctrl.style.backgroundColor ="" で上書きされてしまい、TextBox の背景は赤くなりません。

以下に、その問題に対処したサンプルをアップしておきます。

ただし、自分は JavaScript 使いでも jQuery 使いでもないので(と言って、C# 使いでもないですが(汗))、スクリプトの書き方が変かもしれません。でも、一応期待通りに動くことは検証しました。

以下のコードは、実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。この記事の下の方の「2011/7/20 追記」に書いた ErrorMessage と同期を取るためのコードは追加済みです。

<%@ 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 Page_Load(object sender, EventArgs e)
  {
    String csname = "OnSubmitScript";
    Type cstype = this.GetType();
    ClientScriptManager cs = Page.ClientScript;
    if (!cs.IsOnSubmitStatementRegistered(cstype, csname))
    {
      String cstext = "ChangeBackgroundColor();";
      cs.RegisterOnSubmitStatement(cstype, csname, cstext);
    }
  }

  protected void CustomValidator1_ServerValidate(
    object source, ServerValidateEventArgs args)
  {        
    string membership = args.Value.ToLower();

    if (membership == "gold" || membership == "silver")
    {
      args.IsValid = true;
    }
    else
    {
      args.IsValid = false;
    }      
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
  <script type="text/javascript">
  //<![CDATA[
    function CustomValidator1_ClientValidate(sender, args) {
      var membership = args.Value.toLowerCase();
      if (membership === "gold" || membership === "silver") {
        args.IsValid = true;
      } else {
        args.IsValid = false;
      }
    }

    function ChangeBackgroundColor() {
      var color = "#FFAAAA"

      var valid =
        $(Page_Validators).
        filter(function () { return this.isvalid == true; });

      var invalid =
        $(Page_Validators).
        filter(function () { return this.isvalid == false; });

      valid.each(function () {
        $("#" + $(this).get()[0].controltovalidate).
        css("backgroundColor", "");
      });

      invalid.each(function () {
        $("#" + $(this).get()[0].controltovalidate).
        css("backgroundColor", color);
      });
    }
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <table>
    <tr>
      <td>
        User Name
      </td>
      <td>
        <asp:TextBox ID="username" runat="server">
        </asp:TextBox>
      </td>
      <td>
        <asp:RequiredFieldValidator 
          ID="RequiredFieldValidator1" 
          runat="server" 
          ErrorMessage="ユーザー名は必須入力です。" 
          ControlToValidate="username" 
          ForeColor="Red" 
          Display="Dynamic">
        </asp:RequiredFieldValidator>
        <asp:RegularExpressionValidator 
          ID="RegularExpressionValidator1" 
          runat="server" 
          ErrorMessage=
            "半角アルファベットで 40 文字以内にしてください。" 
          ControlToValidate="username" 
          ForeColor="Red" 
          ValidationExpression="^[a-zA-Z''-'\s]{1,40}$" 
          Display="Dynamic">
        </asp:RegularExpressionValidator>
      </td>
    </tr>
    <tr>
      <td>
        Email
      </td>
      <td>
        <asp:TextBox ID="email" runat="server">
        </asp:TextBox>
      </td>
      <td>
        <asp:RequiredFieldValidator 
          ID="RequiredFieldValidator2" 
          runat="server" 
          ErrorMessage="メールアドレスは必須入力です。" 
          ControlToValidate="email" 
          ForeColor="Red" 
          Display="Dynamic">
        </asp:RequiredFieldValidator>
        <asp:RegularExpressionValidator 
          ID="RegularExpressionValidator2" 
          runat="server" 
          ErrorMessage=
            "メールアドレスの形式が正しくありません。" 
          ControlToValidate="email"
          ForeColor="Red" 
          ValidationExpression=
            "\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" 
          Display="Dynamic">
        </asp:RegularExpressionValidator>
      </td>
    </tr>
    <tr>
      <td>
        Membership
      </td>
      <td>
        <asp:TextBox ID="membership" runat="server">
        </asp:TextBox>
      </td>
      <td>
        <asp:RequiredFieldValidator 
          ID="RequiredFieldValidator3" 
          runat="server" 
          ErrorMessage="メンバーシップは必須入力です。" 
          ControlToValidate="membership" 
          ForeColor="Red" 
          Display="Dynamic">
        </asp:RequiredFieldValidator>
        <asp:CustomValidator 
          ID="CustomValidator1" 
          runat="server" 
          ErrorMessage=
            "Gold または Silver でなければなりません。" 
          ControlToValidate="membership"
          ForeColor="Red" 
          OnServerValidate=
            "CustomValidator1_ServerValidate" 
          Display="Dynamic" 
          ClientValidationFunction=
            "CustomValidator1_ClientValidate" >
        </asp:CustomValidator>
      </td>
    </tr>
  </table>
  <asp:Button ID="Button1" runat="server" Text="送信" />
  </form>
</body>
</html>

------------ 2011/7/20 追記 ------------

クライアント側での検証は、form が submit された時だけでなく、TextBox からフォーカスが外れた時も自動的にかかるようで、上記のコードでは ErrorMessage が消えても TextBox の背景は赤いままになってしまいます。

Validator の ErrorMessage と TextBox の背景の同期を取るには、TextBox の onblur 属性にも ChangeBackgroundColor() を設定します。Page_Load ハンドラで以下のようなコードを追加してやるとうまくいきます。

username.Attributes.Add("onblur", 
    "javascript:ChangeBackgroundColor()");
email.Attributes.Add("onblur", 
    "javascript:ChangeBackgroundColor()");
membership.Attributes.Add("onblur", 
    "javascript:ChangeBackgroundColor()");

------------ 2011/7/21 追記 ------------

IE の場合、フォーカスを外しても自動的に検証がかからないケースがあります。Firefox と Chrome でも試しましたが、こちらは期待通り検証がかかります。

具体的には以下のようなケースです。

最初に、空白または無効な文字列を TextBox に入力し、Tab キーでフォーカスを外すとクライアント側で検証がかかって ErrorMessage が表示され、onblur イベントが発生して ChangeBackgroundColor() メソッドが働き TextBox の背景色が赤になります。

次に、再度その TextBox に入力する際、オートコンプリートの一覧からマウスもしくはキー操作で文字列を選んで TextBox に表示し、その状態から Tab キーでフォーカスを外すと、今度は検証はかかりません。従い、有効な文字列なのにエラーとなったままになります。onblur イベントは発生して ChangeBackgroundColor() メソッドが働きますが、検証がかかってないので(即ち、検証結果が NG のままなので)TextBox の背景色は赤のままとなります。

ちなみに、オートコンプリートは一切使わず、有効な文字列を手打ちで TextBox に入力した場合は、フォーカスを外すと期待通り検証がかかります。従い、ErrorMessage は消えて TextBox の背景色も元に戻ります。

動作としては気に入らないですが、どうも IE のバグ仕様(?)らしいということで未対応です。

後で調べて分かったことですが、MSDN ライブラリの Walkthrough: Validating User Input in a Web Forms Page の Note に以下の文がありました。

"If you are using the auto-complete option in Internet Explorer, selecting a value from the auto-complete list will fill a value into the text box, but the client-side validator will not run."

Tags:

Validation

DropDownList を使って絞込み

by WebSurfer 2011年7月17日 14:29

GridView に表示するレコードを DropDownList を使って絞り込むサンプルです。

GridView に表示するレコードを DropDownList を使って絞り込み

以前、実験室 SelectCommand の切り替え にも、2 つの DropDownList を使って GridView に表示されるレコードを絞り込むサンプルを書きましたが、それは SqlDataSource の SelectCommand(正確には SELECT クエリの WHERE 句)を書き換えていて、そのためのコードを書かなければならないのが面倒で、かつ、あまりスマートな方法とはいえません。

今回、ここに書いた方法は、WHERE 句は以下のように固定しておいて、DropDownList の SelectedValue プロパティの値によって全件抽出と条件抽出の両方に対応できるようにしたものです。

WHERE (@CustomerID='ALL' OR o.CustomerID=@CustomerID) 
  AND (@EmployeeID=0 OR e.EmployeeID=@EmployeeID)

上記で、@CustomerID='ALL' と @EmployeeID=0 が全件抽出の条件で、DropDownList.SelectedValue がそれぞれ "ALL" と "0" の時にその条件に一致させるようにします。

そのために、DropDownList の AppendDataBoundItems プロパティを true に設定した上で、全件抽出条件のための ListItem を追加します。なお、EmployeeID については、データ型が int なので、ListItem は以下のように設定しなければなりません。DropDownList.SelectedValue プロパティは string 型を返しますが、データベースプロバイダが型変換してくれます。

<asp:ListItem Value="0">ALL</asp:ListItem>

これによって C# のコードは一行も書かずに、すべてウィザードベースで作ることができます。上の画像の aspx ページのコードは以下の通りです。データベースには Northwind サンプルデータベースの Orders, Customers, Employees テーブルを使っています。

<%@ 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>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT DISTINCT o.CustomerID, c.CompanyName 
        FROM Orders AS o 
        INNER JOIN Customers AS c 
        ON o.CustomerID = c.CustomerID">
    </asp:SqlDataSource>
    Customer: 
    <asp:DropDownList ID="DropDownList1" 
      runat="server" 
      AppendDataBoundItems="True" 
      DataSourceID="SqlDataSource1" 
      DataTextField="CompanyName" 
      DataValueField="CustomerID" 
      AutoPostBack="True">
      <asp:ListItem>ALL</asp:ListItem>
    </asp:DropDownList>
    <br />
    <asp:SqlDataSource ID="SqlDataSource2" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT DISTINCT o.EmployeeID, 
          e.FirstName + ' ' + e.LastName AS Name 
        FROM Orders AS o 
        INNER JOIN Employees AS e 
        ON o.EmployeeID = e.EmployeeID">
    </asp:SqlDataSource>
    Employee: 
    <asp:DropDownList ID="DropDownList2" 
      runat="server" 
      AppendDataBoundItems="True" 
      DataSourceID="SqlDataSource2" 
      DataTextField="Name" 
      DataValueField="EmployeeID" 
      AutoPostBack="True">
      <asp:ListItem Value="0">ALL</asp:ListItem>
    </asp:DropDownList>

    <asp:SqlDataSource ID="SqlDataSource3" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT o.OrderID, c.CompanyName, 
          e.FirstName + ' ' + e.LastName AS Name, 
          o.ShippedDate, o.Freight 
        FROM Orders AS o 
        INNER JOIN Customers AS c 
          ON o.CustomerID = c.CustomerID 
        INNER JOIN Employees AS e 
          ON o.EmployeeID = e.EmployeeID
        WHERE (@CustomerID='ALL' OR o.CustomerID=@CustomerID) 
          AND (@EmployeeID=0 OR e.EmployeeID=@EmployeeID)
        ORDER BY o.OrderID">
        <SelectParameters>
          <asp:ControlParameter ControlID="DropDownList1" 
            Name="CustomerID" 
            PropertyName="SelectedValue" />
          <asp:ControlParameter ControlID="DropDownList2" 
            Name="EmployeeID" 
            PropertyName="SelectedValue" />
        </SelectParameters>
    </asp:SqlDataSource>
    <asp:GridView ID="GridView1" 
      runat="server" 
      AllowPaging="True" 
      AutoGenerateColumns="False" 
      DataKeyNames="OrderID" 
      DataSourceID="SqlDataSource3">
      <Columns>
        <asp:BoundField 
          DataField="OrderID" 
          HeaderText="OrderID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="OrderID" />
        <asp:BoundField 
          DataField="CompanyName" 
          HeaderText="Customer" 
          SortExpression="CompanyName" />
        <asp:BoundField 
          DataField="Name" 
          HeaderText="Employee" 
          ReadOnly="True" 
          SortExpression="Name" />
        <asp:BoundField 
          DataField="ShippedDate" 
          HeaderText="Shipped Date" 
          SortExpression="ShippedDate" 
          DataFormatString="{0:yyyy/M/d}" >
          <ItemStyle HorizontalAlign="Center" />
        </asp:BoundField>
        <asp:BoundField 
          DataField="Freight" 
          HeaderText="Freight" 
          SortExpression="Freight" 
          DataFormatString="${0:N2}" >
          <ItemStyle HorizontalAlign="Right" />
        </asp:BoundField>
      </Columns>
    </asp:GridView>
  </div>
  </form>
</body>
</html>

Tags: ,

ASP.NET

W3C 検証にパスしない

by WebSurfer 2011年6月13日 22:58

ページングする際に &page=n(n はページ番号)というクエリ文字列がページャーのリンクの URL に追加 される場合があります。しかしながら、& のままでは W3C Markup Validation に通りません。HTML エンコー ドして &amp; にする必要があります。この問題には今まで気がつきませんでした。(汗)

この問題を解決するには、User controls/PostList.ascx.cs の InitPaging メソッドを以下のように修正しま す。

private void InitPaging()
{
  string path = Request.RawUrl;

  if (!(Request.QueryString["year"] != null || 
    Request.QueryString["date"] != null))
    path = REMOVE_DEFAULT_ASPX.Replace(path, string.Empty);

  if (path.Contains("?"))
  {
    if (path.Contains("page="))
    {
      int index = path.IndexOf("page=");
      path = path.Substring(0, index);
    }
    else
    {
      path += "&";
    }
  }
  else
  {
    path += "?";
  }

  int page = GetPageIndex();
  string url = path + "page={0}";

  // 下記の追加のみ
  url = url.Replace("&", "&amp;");

  hlNext.HRef = string.Format(url, page);		
  hlPrev.HRef = string.Format(url, page + 2);

  if (page == 0)
  {
    hlNext.Visible = false;
  }
  else
  {
    (Page as BlogBasePage).AddGenericLink(
      "next", 
      "Next page", 
      hlNext.HRef);
    Page.Title += " - Page " + (page + 1);
  }

  if (hlPrev.Visible)
    (Page as BlogBasePage).AddGenericLink(
      "prev", 
      "Previous page", 
      string.Format(url, page + 2));
}

Tags:

BlogEngine.NET

About this blog

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

Calendar

<<  2024年3月  >>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar