ASP.net Webフォームで、コントローラのHTMLを動的に生成、追加し、イベントハンドラを紐付ける方法

概要

ASP.net Webフォームで、コントローラのHTMLを動的に生成、追加し、イベントハンドラを紐付ける(正確には紐付いてはいませんが。。。)方法について説明します。
今回はbuttonコントローラ(buttonタグ)を動的に追加する方法を例として紹介します。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

  • 「Page.Form.Controls.Add(button);」で動的にコントローラを追加できるのですが、この方法では任意の場所や、動的に作成しているHTML内に設定することができません。
  • コントロールのHTML化(HTMLの生成)は、RenderControlメソッドを使用しますが、StringWriterを使うのがポイントです。
  • 動的に生成し、かつControls.Addを使用しない場合、イベントハンドラと紐付けられません。そのため、どのボタンが押下されたのかをRequest[“__EVENTTARGET”]を使って判定して、イベント用のメソッドを呼び出します。

サンプルコード

protected void Page_Load(object sender, EventArgs e)
{
    // 出力用のWriterの準備。StringWriterを用意するのがポイント。
    StringBuilder builder = new StringBuilder();
    StringWriter writer = new StringWriter(builder);
    HtmlTextWriter htmlWriter = new HtmlTextWriter(writer);

    // ボタンコントロールの作成
    Button btn = new Button();
    btn.Text = "新規ボタン";
    btn.ID = "newButton";  // ボタンを複数設置するときはIDが重複しないように!
    // JavaScript用のScriptである「__doPost」を作成する。
    string script = Page.ClientScript.GetPostBackEventReference(btn, string.Empty);
    btn.OnClientClick = script;
    btn.UseSubmitBehavior = false;  // trueだと「__doPost」がHTMLに反映されない。
    btn.RenderControl(htmlWriter);
  // HtmlWriterに出力

    // innerAreaはデザイナ上で追加した「<div id="innerArea" runat="server">」タグのID
    // Writerの大元であるStringBuilderでHTMLの文字列出力
    innerArea.InnerHtml += builder.ToString();
 

  // ..中略..

    if (isPostBack) {
        // イベントが発生しないので対象ボタンを確認してメソッドを呼び出す。
        // 通常のイベントはPage_Loadが終わってから呼び出されるが、
        // これはPage_Loadの実行中であるため、Page_Loadの最後に記載する
        string eventTarget = (string)Request["__EVENTTARGET"];
        if (! String.IsNullOrEmpty(eventTarget) && eventTarget == "newButton")
        {
            // 別途用意したイベントハンドラ用のメソッドを呼び出す。
            Btn_Click(sender, e);
        }
    }

// イベントハンドラ用に用意しているメソッド
protected void Btn_Click(object sender, EventArgs e)
{
    // ..省略..

ASP.net Webフォームで、どのようなイベントが発生したのか(イベントハンドラ)をコード上で確認・取得する方法

概要

ASP.net Webフォームで、どのようなイベントが発生したのか(イベントハンドラ)をコード上で確認・取得する方法について説明します。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

Requestの添字「”__EVENTTARGET”」や「”__EVENTARGUMENT”」で確認することができます。
※ウォッチ式で確認する場合は注意が必要です。サンプルコードの下の解説を参照してください。

サンプルコード

string eventTarget = (string)Request["__EVENTTARGET"];
string eventArgument = (string)Request["__EVENTARGUMENT"];


// eventTargetの値は"gridView1"
// eventArgumentの値は"Select$1"

ウォッチ式で確認するときの注意事項

ウォッチ式で確認した場合の表示は以下のとおりです。
例として、GridViewで行を選択したときのものを簡単に示します。
__EVENTTARGETはRequestの直下には存在していないので注意してください。
添字ではRequest[“__EVENTTARGET”]なのに不思議です。。。何故なのかは調べていませんが、エイリアスでも設定されているのでしょう(適当)

Request
 - Form
   - _entriesArray
     - [0]
       - Key:"__EVENTTARGET"
       - Value
         - [0]:"gridView1"
      - [1]
       - Key:"__EVENTARGUMENT"
       - Value
         - [0]:"Select$1"

ASP.NET WebフォームでCSSのStyle属性をコード上から追加、変更する方法

概要

ASP.netのWebフォームでコントロールのCSSを修正するためにStyleプロパティを変更しようとすると「プロパティ’Style’は’ReadOnly’です。」のエラーになります。
ここではStyleを変更する正しい方法を解説します。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

Attributesプロパティから変更するのが正しいやり方です。

サンプルコード

「プロパティ’Style’は’ReadOnly’です。」のエラーになる書き方

Button.Style = "display:none";

Styleを変更するための正しい書き方

// 変更する時もAddメソッドでOKです。同じキーなら上書きされます。
Button.Attributes.CssStyle.Add("display", "block");

ASP.NET Webフォームで「1 つのページには、1 つのサーバー側 Form タグのみを指定できます」のエラー

概要

ASP.NET Webフォームで「1 つのページには、1 つのサーバー側 Form タグのみを指定できます」のエラーが出た場合の原因と対応方法についてです。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

原因について

単純に「formタグ」が2つ以上設定されているために発生するエラーです。

通常のHTMLであればformタグは2つあっても問題ありませんが、ASP.NetのWebフォームでは1画面にformタグは1つまで、となっています。

なぜならば通常のホームページと異なり、画面上で「ボタンを押した」「値が変わった」など、Windowsアプリ開発で「イベント」と呼ばれているものが発生した場合、WebフォームではサーバーにPost送信され、画面が更新されるためです。これは先程述べた「イベント」駆動(Driven)の開発をWeb上の開発に当てはまめて開発効率を向上させる狙いがあります。

しかしながら、それ故1つの画面に1つのFormとして全てのイベントを集約するようになっています。

対応方法について

対応方法はとても単純で、1画面に1つのformタグとしてください。formタグが2つあればどちらか削除してください。

※マスターページ(テンプレート)を用いている場合、マスターページと個別ページの両方に記載されてしまうことがあるので注意してください。

ASP.NET WebフォームでGridViewの特定列をカラム名で非表示にする

概要

ASP.NETのWebフォームの表(GridView)でデータを持っているけれど表示はしたくない列(Column)が存在する場合、RowCreatedイベントでCellsに列番号を指定しますが、カラム名では指定できません。そのため、ひと手間加えてカラム名で非表示にする方法を解説します。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

  • DataTable.Columns.IndexOfメソッドを用いて該当カラム名の列番号を事前に取得しておきます。
  • GridViewの「AutoGenerateEditButton」プロパティで生成される「編集」や「選択」「削除」などのボタン(リンク)のためのCellがRowデータの最初にあります。そのため、IndexOfで調べた値+1が実際の列番号になります。

サンプルコード

C#

// GridViewで非表示にするセルのindexの配列
を持つprivate変数を用意しておく。
private List<int> hiddenCellList = new List<int>(); 

// GridViewにDataBindするDataTableから列番号を取得するための処理をPage_Loadなどから呼び出す。
private void SetHiddenCellList(DataTable table)
{
    hiddenCellList.Add(table.Columns.IndexOf("隠したい列の列名その1"));
    hiddenCellList.Add(table.Columns.IndexOf("隠したい列の列名その2"));
}

// GridViewの行作成時のRowCreatedイベント。事前に調べておいた列番号を非表示にする。
protected void gridView_RowCreated(object sender, GridViewRowEventArgs e)
{
    If(e.Row.RowType == DataControlRowType.DataRow || e.Row.RowType == DataControlRowType.Header)
    {
        foreach(int i in hiddenCellList)
        {
            e.Row.Cells[i].Visible = false;
        }
    }
}