|
Webカスタムコントロールの作成目次
前提条件
はじめに ASP.NETページで利用できるようなサーバーコントロールを設計したいと思ったことはありませんか? 私があるページを手がけていたとき、 もちろん、 私のプロジェクトでは、チェックボックスとして表示されたアイテムのなかからユーザーが任意の数のアイテムを選択できるフォームを作成する必要がありました。ここでは仮に、カテゴリは自動車メーカー、アイテムは車種を表すものとして話を進めます。アイテムとカテゴリはデータベースに格納されていたので、新たなメーカーや車種の追加のほか、既存エントリの変更や削除も行うことができました。 「カテゴリ名と また、実行時にコントロールをフォームに追加するという選択肢も賢明とは言えません。プログラミングによってWebコントロールをプレースホルダや他のコンテナコントロールに追加するのはとても容易です。しかし問題は、ユーザーの指定した値を読み取るためには、ポストバックの状態やチェックボックスの表示と非表示に関わらず、ページを読み込むたびにコントロールの「リビルド」(プログラムによるコントロールの再作成)を行わなければならないという点です。これではサーバーに相当な負荷がかかってしまいます。 私が本当に欲しかったのは、フォームにドラッグアンドドロップしたり、いくつかのプロパティを設定したり、データバインディングコードを追加したりでき、デザイン時にきちんと形ができているコントロールでした。標準のWebコントロールにはぴったり来るものがなさそうだったので、自分の手でカスタムサーバーコントロールを作ることにし、これを「 コントロールの背景知識Webカスタムコントロールは、いくつかの点でユーザーコントロールよりも優れています。まず、ユーザーコントロールは、それを利用するプロジェクトごとにASCXやクラスファイルをコピーしなければならないので、再利用に適していません。また、Visual Studio .NETでデザイナサポートが用意されていないという点でも不利です。ユーザーコントロールをWebフォームに配置してみれば、私の言いたいことがわかるはずです。ユーザーコントロールは汎用的なグレーボックスで表示され、ユーザーコントロールのプロパティ値を示すヒントはIDEから一切提供されません。ユーザーコントロールの主な利点と言えば、作成が容易なので迅速なアプリケーション開発ができるということくらいです。 一方、Webカスタムコントロールには大きな魅力があります。サーバーコントロールにはASCXファイルが存在しないので、非常に簡単に再利用できます。DLLへのプロジェクト参照を設定しさえすれば、すぐに動作させることができます。WebカスタムコントロールはVisual Studio .NETツールボックスに追加でき、こうすることによって再利用は極めて容易になります。さらに、グローバルアセンブリキャッシュ(GAC)にWebカスタムコントロールをインストールすることも可能です。なお、GACの詳細については、本稿の範囲を超えるのでこれ以上は触れません。ともかく、私がWebカスタムコントロールを気に入っている最大の理由は、申し分のないカスタマイズが可能で、デザイン時サポートがあるということです。 Webカスタムコントロールを作成するにあたっての最大の障壁は、コントロール用のHTMLを記述しなければならないという点でしょう。Visual Studio .NETにはWebカスタムコントロールのためのビジュアルデザイナがないので、ツールボックスのアイテムを自作のコントロールにドラッグアンドドロップすることができません。しかし、C#プログラムを習得できるくらいなら、HTMLを覚えるのも苦ではないでしょう。 プロジェクト再利用のための計画これから作成するコントロールを簡単に再利用できるようにするために、新しいWebコントロールライブラリのプロジェクトを用意することにしましょう。 Visual Studio .NETによって、「WebCustomeControl1.cs」というクラスが作成されます。この名前を「CategorizedCheckBoxList.cs」に変更します(なお、クラスファイル内の記述も データバインドプロパティ 今回作成するコントロールにはデータソースをバインドする必要があります。問題を簡単にするために、このコントロールではADO.NETの
System.Data.DataTable型。データソースとして利用されるテーブルを表します。このテーブルには、カテゴリ名の列、チェックボックス値の列、および各チェックボックスのラベルの列を必ず含めなければなりません。今回のコントロールは、カテゴリを第一キー、ラベルを第二キーとしてこのテーブルを自動的にソートします。文字列型。
DataTableのテーブル内で、アイテムの所属カテゴリ名を格納している列の名前を表します。文字列型。
DataTableのテーブル内で、チェックボックスの値を格納している列の名前を表します。DataValueColumnとDataTextColumnに同じ列名を指定できます。DataValueColumnには任意の型のデータを格納できますが、文字データを使用する場合、カンマを含めることはできません。文字列型。
DataTableのテーブル内で、チェックボックスの隣に表示されるラベルを格納している列の名前を表します。 また、ページを読み込むときにチェックマークを入れるべきチェックボックスを指定する手段も必要になります。この機能を用意しておくと、フォームのデフォルト値を設定したり、以前に保存しておいた値をユーザーが編集するようなフォームを実現したりできます。そのためのプロパティを、
文字列値を格納する
ArrayListオブジェクト。選択状態(チェックマークがオンの状態)としてマークすべき値のリストです。このプロパティを利用して、選択状態の値を指定し、ポストバック後に選択状態の値のリストを取得することができます。CSSとその他の視覚的プロパティ CSSクラスセレクタのための追加プロパティを公開することで、
文字列型。一連のチェックボックスを配置するテーブルのスタイルを指定するCSSクラスです。
文字列型。チェックボックスを含む各テーブル列のスタイルを指定するCSSクラスです。
文字列型。カテゴリ見出しを含むセルのスタイルを指定するCSSクラスです。
文字列型。チェックボックスを含むセルのスタイルを指定するCSSクラスです。
文字列型。チェックボックのラベルを含むテーブルセルのスタイルを指定するCSSクラスです。
さらに次のようなプロパティを追加しました。
文字列型。テーブルの幅をピクセル数またはパーセント(%記号を付ける)で指定します。
整数型。テーブルセルの内側の余白を指定します。
整数型。テーブルセルの間隔を指定します。
整数型。チェックボックスの表示に用いる列数を指定します。
ブール型。
Trueの場合は、すべてのチェックボックスを1つの同じテーブルに表示します。Falseの場合は、一連のチェックボックスをカテゴリごとに独立したテーブルに表示します。このプロパティを用意したのは、チェックボックスのラベルの長さがカテゴリごとに大きく異なる場合に、ページの見た目が悪くなってしまうからです。Renderメソッド Webカスタムコントロールを扱うときには、 細かい処理はすべてVisual Studio .Netが面倒を見てくれるので、このWebカスタムコントロールをページ上で使用するための特別なコーディングをする必要はありません。ページにWebカスタムコントロールを配置するだけで、互いにどのようにやりとりをすればよいかをページとコントロールが理解してくれるのです。 では、今回のWebカスタムコントロールの /// <summary> /// Writes out the HTML needed to render this control. /// </summary> /// <param name="output">The HTML text writer the we will utilize. /// This is passed to the control automatically, /// by the host ASPX page.</param> protected override void Render(HtmlTextWriter output) { try { // No need for ViewState this.EnableViewState = false; // Make sure that the htmlFieldName is set. GetHtmlFieldName(); // Should the control be visible? if(this.Visible == true) { // Yes. Render the html. BuildCategorizedCheckBoxList(output); } } catch(Exception ex) { // Something bad happened. // Let’s tell the user what that was. output.Write("Error building CategorizedCheckBoxList:<br>"); output.Write(ex.Message); } } ご覧のとおり、最初にコントロールの /// <summary> /// Retrieves a list of the checkbox values that were /// selected (checked), if the form was submitted. /// This is kind of a poor-man’s view state implementation. /// But unlike view state, /// it doesn’t add anything to the page weight. /// </summary> protected void ReadPostBack() { // See what field name we are assigning to the checkboxes GetHtmlFieldName(); // Were any checkboxes checked? if(HttpContext.Current.Request.Form[htmlFieldName] != null) { // Since we assigned the same field name to all of // the checkboxes, ASP.NET will give us // a comma-delimited list of the selections. // First, conver the list to a string array. string [] Input = HttpContext.Current .Request.Form[htmlFieldName].Split(’,’); // Then, iterate through the array and add // each value to our ArrayList. for(int i = 0; i < Input.Length; i++) { selections.Add(Input[i]); } } } 詳しくは後述しますが、チェックボックスフィールドのHTMLを作成すると、各フィールドに同じ名前が割り当てられていることがわかるでしょう。ASP.NETが 次に示すのは、 /// <summary> /// Returns the unique field name /// that we will assogn to the checkboxes, later. /// </summary> protected void GetHtmlFieldName() { // Pickup the ID assigned to the control // in the consuming ASPX page htmlFieldName = this.ID; } フィールド名が確実に一意であれば、複数の まず、 /// <summary> /// Outputs the HTML for this control. /// </summary> /// <param name="output"></param> protected void BuildCategorizedCheckBoxList(HtmlTextWriter output) { // Do we have any data? if(dataTable == null || dataTable.Rows.Count < 1) { // There is no data, so there’s nothing to render. return; } 次に、チェックボックスのカテゴリ、値、ラベルを示す列を探します。これらの列が見つかれば、ローカル変数にインデックスを割り当てます。この値は後で使用します。テーブルの列を名前で参照するのは、インデックス番号で参照するよりもずっと時間がかかるので、このコードではインデックスで参照することにしました。 初期化時に、これらの列のインデックス値をわざと-1に設定します。すべてそうしておく必要があります。というのは、 // First retrieve the column indexes of // the specified columns. Later, we’ll get // the values that we need using these indexes. // This is faster than referencing a column by name. int CategoryColumnIndex = -1; int TextColumnIndex = -1; int ValueColumnIndex = -1; for(int i = 0; i < dataTable.Columns.Count; i++) { if(dataTextColumn == dataTable.Columns[i].ColumnName) { TextColumnIndex = i; } if(dataValueColumn == dataTable.Columns[i].ColumnName) { ValueColumnIndex = i; } if(dataCategoryColumn == dataTable.Columns[i].ColumnName) { CategoryColumnIndex = i; } } 次に、すべてのカテゴリとそのチェックボックスを同じテーブル上に表示するかどうかを判断します。同じテーブルに表示する場合は、次のようにテーブルの開始タグを書き出します。 /**********************************/ /* Build the html to display of the items */ /**********************************/ // If the consuming page wants one single, shared table, // write the opening tag, now. if(this.sharedTable == true) { output.Write(GetTableTag()); } 話を元に戻しましょう。続いて、 // Create a string for the "previous" category string LastCategory = string.Empty; // Sort the data by category DataView Category = dataTable.DefaultView; Category.Sort = this.dataCategoryColumn; // Assemble a distinct list of the categories // found in the data ArrayList Categories = new ArrayList(); for(int i = 0; i < Category.Count; i++) { if(LastCategory != Category[i][CategoryColumnIndex].ToString()) { Categories.Add(Category[i][CategoryColumnIndex].ToString()); LastCategory = Category[i][CategoryColumnIndex].ToString(); } } これでようやくカテゴリのリストができあがったので、このリストに対してループ処理を行い、各カテゴリ(および対応するチェックボックス)のHTMLを出力します。これを行うために、 // Loop through the categories for(int i = 0; i < Categories.Count; i++) { // Get the rows for this category only DataView CategoryItems = new DataView(dataTable); CategoryItems.RowFilter = String.Format("{0}=’{1}’", this.dataCategoryColumn, Categories[i].ToString().Replace("’","’’")); CategoryItems.Sort = this.dataTextColumn; カテゴリごとに別々のHTMLテーブルを作成する場合は、この時点でテーブルの開始タグを出力します。 // If the consuming page wants a separate table // for each category, write the opening tabel tag // for the current category, now. if(this.sharedTable == false) { output.Write(GetTableTag()); } 今度は、現在処理しているカテゴリ用のHTMLを出力します。ヘルパーメソッドである // Add the category heading to the html OutputCategoryRow(output, (string)Categories[i]); この段階になると、話が少し複雑になってきます。現在処理しているカテゴリに属するアイテム数や、チェックボックスの表示に使用する列数はわかっています。しかし、すべてのアイテムの表示に必要な列数が明確になっていません。 そこで、カテゴリ内の全アイテム数を表示列数で割ることによって、全アイテムの表示に必要な列数を求めます。余りが出た場合には、求めた列数に1を加えます。 // Calculate the total number of rows based on // the item count and the number of columns totalItems = CategoryItems.Count; totalRows = totalItems / columns; // If there was anything left-over as a result of // the division, we need to add another row if(totalItems % columns > 0) { totalRows++; } 次に、列を処理するループに入ります。現在処理中のアイテムのインデックス番号を保持するためのカウンタを用意します。このカウンタの値は0から始まります。各アイテムのHTMLを書き出すたびに、最後のアイテムでないかチェックします( 現在のカテゴリにおける最後のアイテムのHTML出力が終わったら、 // Create an integer to hold the index number // for the current item int CurrentItemIndex = 0; // Now loop through the rows for(int Row = 0; Row < totalRows; Row++) { // Determine the starting index for this row. // This is the same calculation that we would perform // to handle paging in a grid. int Start = (Row * columns); // Create an integer to hold the index number // for the current item int CurrentItemIndex = Start; // Start the row output.Write(""); output.Write("<tr class=""); output.Write(this.rowCssClass); output.Write("">"); output.Write(" "); // Column loop for(int Col = 0; Col < columns; Col++) { // Make sure that we haven’t hit a blank entry. if(CurrentItemIndex == -1) { // Add an empty cell (two, actually) AddEmptyCells(output); } else { // Now add the checkbox and text OutputCheckBox(output, htmlFieldName, CategoryItems[CurrentItemIndex] [TextColumnIndex].ToString(), CategoryItems[CurrentItemIndex] [ValueColumnIndex].ToString(), IsChecked(CategoryItems[CurrentItemIndex] [ValueColumnIndex].ToString()) ); // If we have more data left, // increment the current index counter. if(CurrentItemIndex < (totalItems - 1) && CurrentItemIndex != -1) { // increment the current index CurrentItemIndex++; } else { // We’re at the end of the items // in the data table. Set the value of // the current index to -1, // which our rendering code // ignores (creates empty table cells) CurrentItemIndex = -1; } } // Add a line break output.Write(" "); } この時点で列内のすべての列の処理が終わっているので、列の終わりに必要な処理を行います。
// End the row
output.Write("");
output.Write("</tr>
");
}
このループは、すべての列に対する処理が終了するまで繰り返されます。最後に、カテゴリごとに別々のテーブルを使う場合には、現在のカテゴリテーブルを次のようにして終了させます。
// Table tag
if(this.sharedTable == false)
{
output.Write("</table>
");
}
}
このループは、すべてのカテゴリの処理が終了するまで繰り返されます。共有テーブルを使用する場合は、ループの最後でテーブルの終了タグを出力します。
// Finish the table
if(this.sharedTable == true)
{
output.Write("</table>
");
}
/**********************************/
}
これまで説明していなかったヘルパーメソッドの /// <summary> /// Looks for a match between the current value and /// the list of selected values. /// </summary> /// <param name="currentValue">The value that we want to look for. /// </param> /// <returns>True if the current value is contained in /// the selected list. Otherwise, false.</returns> protected bool IsChecked(string currentValue) { // If we have selections, continue if(selections != null && selections.Count > 0) { // Can we find the current value? if(selections.IndexOf(currentValue) > -1) { // Yes, so this item should be marked // as selected (checked) return true; } else { // No, so this item should not be selected return false; } } else { // Nothing at all was selected, so return false return false; } } コントロールによるHTML出力 ヘルパーメソッドである また、TABLE、TR、およびTDの各タグのHTMLに改行( )とタブ()が追加されていることにも気が付いたかもしれません。こうした記号の追加は、どうしても必要なものではありませんし、かえってWebブラウザがダウンロードするHTMLのサイズを増やすことになります。しかし、結果として得られるHTMLは非常に読みやすいものになります(このページのソースをご覧になればわかります)。ただし、製品版アプリケーションでこのコントロールを実装する場合には、こうした余白文字は削除しておくのがよいでしょう。 デザイン時サポートさて、ここまでは順調です。しかし依然として、Visual Studio .NETのページデザイナでは、このコントロールは汎用的なグレーボックスとして表示されたままです。さらに、プロパティウィンドウには、このコントロールのプロパティが1つも表示されません。このコントロールにデザイン時サポートを加えるためには、まずクラスおよびプロパティの宣言部にコード属性を追加する必要があります。 Visual Studioのデザイン時サポートを加える際には、パブリックプロパティにコード属性を設定します。 [Category("Appearance"), DefaultValue(""), Description("The CSS Class name for the table row" + "containing each item.")] public string RowCssClass { プロパティ宣言部の上に記述した大カッコ内のコードは、このプロパティをプロパティウィンドウにどのように表示するかをVisual Studio .NETに指示しています。 ![]() 一般的な属性
ご覧のとおり、プロパティウィンドウのサポートは簡単に実現できます。 しかし、コントロール自身のデザイン時サポート、つまりブラウザ上でのコントロールの描画をより正確に示すためのデザイン時サポートを追加するには、もう少し複雑な作業が必要です。そのためには、 ただし、Visual Studio .NET IDE内での /// <summary> /// Provides a moderate level of fidelity /// for the CategorizedCheckBoxList control /// in the VS.net IDE. /// </summary> internal class CategorizedCheckBoxListControlDesigner : System.Web.UI.Design.ControlDesigner { /// <summary> /// Provides easy access the properties set in the IDE. /// </summary> protected CategorizedCheckBoxList ccbl; /// <summary> /// Initializes the designer /// </summary> /// <param name="component"></param> public override void Initialize(IComponent component) { // Make sure that this designer is attached to // a CategorizedCheckBoxList if(component is CategorizedCheckBoxList) { base.Initialize (component); ccbl = (CategorizedCheckBoxList)component; } } このクラスで 最初に、Visual Studioで設定されたプロパティにアクセスするための /// <summary> /// Writes the HTML used be VS.net to display /// the control at design-time. /// </summary> /// <returns></returns> public override string GetDesignTimeHtml() { try { // Start building the HTML StringBuilder Sb = new StringBuilder(); // Table Sb.Append("<table"); Sb.Append(" cellspacing=""); Sb.Append(ccbl.CellSpacing.ToString()); Sb.Append("""); Sb.Append(" cellpadding=""); Sb.Append(ccbl.CellPadding.ToString()); Sb.Append("""); Sb.Append(" border="0">"); // Category Row Sb.Append("<tr><td colspan="4""); Sb.Append(" class=""); Sb.Append(ccbl.CategoryCssClass); Sb.Append("""); Sb.Append(">Fruit</td></tr>"); // Item Row Sb.Append("<tr valign="top">"); Sb.Append("<td><input type="checkbox" " + "name="1" value="1" class=""); Sb.Append(ccbl.CheckBoxCssClass); Sb.Append(""></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append("">Apples</td>"); Sb.Append("<td><input type="checkbox" " + "name="1" value="2" class=""); Sb.Append(ccbl.CheckBoxCssClass); Sb.Append(""></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append("">Oranges</td>"); Sb.Append("</tr>"); // Item Row Sb.Append("<tr valign="top">"); Sb.Append("<td><input type="checkbox" " + "name="1" value="3" class=""); Sb.Append(ccbl.CheckBoxCssClass); Sb.Append(""></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append("">Tangerines</td>"); Sb.Append("<td></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append(""></td>"); Sb.Append("</tr>"); // Category Row Sb.Append("<tr><td colspan="4""); Sb.Append(" class=""); Sb.Append(ccbl.CategoryCssClass); Sb.Append("""); Sb.Append(">Vegetables</td></tr>"); // Item Row Sb.Append("<tr valign="top">"); Sb.Append("<td><input type="checkbox" " + "name="2" value="1" class=""); Sb.Append(ccbl.CheckBoxCssClass); Sb.Append(""></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append("">Broccoli</td>"); Sb.Append("<td><input type="checkbox" " + "name="2" value="2" class=""); Sb.Append(ccbl.CheckBoxCssClass); Sb.Append(""></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append("">Green Beans</td>"); Sb.Append("</tr>"); // Item Row Sb.Append("<tr valign="top">"); Sb.Append("<td><input type="checkbox" " + "name="2" value="3" class=""); Sb.Append(ccbl.CheckBoxCssClass); Sb.Append(""></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append("">Potatoes</td>"); Sb.Append("<td><input type="checkbox" " + "name="2" value="4" class=""); Sb.Append(ccbl.CheckBoxCssClass); Sb.Append(""></td>"); Sb.Append("<td class=""); Sb.Append(ccbl.TextCssClass); Sb.Append("">Tomatoes</td>"); Sb.Append("</tr>"); // End the table Sb.Append("</table>"); return Sb.ToString(); } catch(Exception ex) { // Display the error in VS.net, in Design view return String .Concat("<h3>Error</h3>Stack Trace:<br>", ex.StackTrace); } } ここまでくれば、後はこの /// <summary> /// The CategorizedCheckBoxList is like a CheckBoxList, /// but with the ability to categorize the display of items. /// </summary> [Designer( 以上で Webカスタムコントロールの利用カスタムコントロールの使い方としては、ツールボックスからドラッグアンドドロップしてページに配置するのが最も簡単な方法です。作成したコントロールをツールボックスに追加するには、まずツールボックス上で右クリックして[Add/Remove Items]を選択します。 ![]() するとダイアログボックスが表示されるので、そこでローカルPCの.NET Framework Componentsフォルダを選択し、Web Control LibraryプロジェクトのDLLを指定します。ただし、DLLの場所は、プロジェクトをデバッグ構成でビルドした場合はプロジェクトフォルダの下の「binDebug」フォルダに、リリース構成でビルドした場合は「binRelease」になっています。 DLLを追加すると、CategorizedCheckBoxListというコンポーネントが表示されるので選択します。 [OK]をクリックするとツールボックス上に ![]() ASPXページで このコントロールのデータソースとなる それでは、この記事のダウンロードサンプルに収録されている「Default.aspx」ページの内容を見ていきましょう。 private void Page_Load(object sender, System.EventArgs e) { // If the page has not posted-back, // or if it has but the "Show List" checkbox is checked, // get the data for our CategorizedCheckBoxList. if(!IsPostBack || chkShowList.Checked == true) { // Get the data GetMdbData(); } else { // Hide the CategorizedCheckBoxList CategorizedCheckBoxList1.Visible = false; // Hide the "Show List" checkbox chkShowList.Visible = false; // Hide the submit button, too btnTestValues.Visible = false; } } ここでは、コントロールが表示される場合にのみコントロール用データの取得を行っています( 次に、 protected void GetMdbData() { // Create a connetion OleDbConnection Conn = new OleDbConnection(); Conn.ConnectionString = String.Concat( "Provider=Microsoft.Jet.OleDb.4.0;data source=", Server.MapPath("SampleData.mdb")); // Build a data adapter that selects all of the columns // and rows in a saved query called qryCarModelCarMaker, // in the Access database OleDbDataAdapter Adp = new OleDbDataAdapter( "SELECT * FROM qryCarModelCarMaker", Conn); // Create an instance of our Cars typed dataset Cars TypedSampleData = new Cars(); // Use the adapter to fill the CarTable Adp.Fill(TypedSampleData, "CarTable"); // Specify the data properties for // our CategorizedCheckBoxList control CategorizedCheckBoxList1.DataTable = TypedSampleData.CarTable; CategorizedCheckBoxList1.DataTextColumn = "Model"; CategorizedCheckBoxList1.DataValueColumn = "CarModelPK"; CategorizedCheckBoxList1.DataCategoryColumn = "Make"; // Clean-up Conn.Dispose(); Adp.Dispose(); } ここではダイナミックデータベースクエリの結果を格納した型付きの いくつかのアイテムを選択したうえで[Test Checkbox Values]ボタンをクリックすると、選択したチェックボックスの値が表示されます。このサンプルで表示されるのは、選択された車種のプライマリキーの値です。では、選択したアイテムの値の取得方法を見てみましょう。 private void btnTestValues_Click(object sender, System.EventArgs e) { // Were any checkboxes checked? if(CategorizedCheckBoxList1.Selections.Count > 0) { // Yes. Let’s use a string builder to tell // the user what we find. StringBuilder Sb = new StringBuilder(); Sb.Append("The following values were selected:"); // Use an HTML un-ordered list to display the values Sb.Append("<ul>"); // Loop through the selections foreach(string check in CategorizedCheckBoxList1.Selections) { // Add this item to our HTML list Sb.Append("<li>"); Sb.Append(check); Sb.Append("</li>"); } // End the list Sb.Append("</ul>"); // Set the text of our label Label1.Text = Sb.ToString(); } else { // Use our label to tell the user // that nothing was picked. Label1.Text = "No checkboxes were selected."; } } このメソッドを実行すると、選択したチェックボックスの値のリストが次のように表示されます。 ![]() 以上で // If the page has not posted-back, // or if it has but the "Show List" checkbox is checked, // get the data for our CategorizedCheckBoxList. if(!IsPostBack || chkShowList.Checked == true) { // Get the data GetMdbData(); // Select all of the Audi models CategorizedCheckBoxList1.Selections.Add("37"); CategorizedCheckBoxList1.Selections.Add("38"); CategorizedCheckBoxList1.Selections.Add("39"); CategorizedCheckBoxList1.Selections.Add("40"); CategorizedCheckBoxList1.Selections.Add("41"); } なお、この まとめ.NET Frameworkには、さまざまなWebコントロールを含んだツールボックスが用意されています。カスタムコントロールを自分で開発しようとする前に、必ず標準のコントロールの利用を検討してみるべきです。標準のWebコントロールは、ここで紹介した例よりもかなり複雑なものです。上位レベルおよび下位レベルのブラウザのサポートや、豊富なイベントモデルが用意されています。しかも、こうしたWebコントロールについては、ASP.NETのリリースごとにMicrosoftによるアップグレードが期待ができます。 しかし、あなたの要求を満たすコントロールが見つからないときには、どんどん自作してください。ユーザーコントロールに比べれば複雑ですが、Webカスタムコントロールは手に負えないほど難解なものではありませんし、数多くのメリットをもたらしてくれます。あらゆるコントロールの描画に利用されるHTMLについても同じことが言えます。想い描いたアイデアをHTMLで表現する方法が理解できれば、Webカスタムコントロールを構築することができます。 著者紹介Conrad Jalali(Conrad Jalali)
ユーザビリティに重点を置く設計会社、Useful Studiosの共同創立者。ここ5年間はActive Server Pages(ASP)に取り組んでおり、C#とSQL Server 2000を使用したASP.NET開発を専門とする。Sarah Lawrence Collegeを卒業し、教養課程の学士号を取得。Microsoft認定プロフェッショナル(MCP)の資格を所有。妻Elizabethと飼い犬Sparkyと共にワシントンDCに居住。メールの宛先はconrad@smallcog.com。
|