カスタマイズされた並べ替えユーザー インターフェイスを作成する (C#)
並べ替えられたデータの長いリストを表示する場合は、区切り文字行を導入して関連データをグループ化すると非常に役立ちます。 このチュートリアルでは、このような並べ替えユーザー インターフェイスを作成する方法について説明します。
はじめに
並べ替えられた列に少数の異なる値しかない、並べ替えられたデータの長いリストを表示する場合、エンド ユーザーは、差の境界が発生する場所を正確に識別するのが難しい場合があります。 たとえば、データベースには 81 個の製品がありますが、カテゴリの選択肢は 9 つだけです (8 つの一意のカテゴリと NULL
オプション)。 シーフードカテゴリに該当する製品を調べることに関心があるユーザーの場合を考えてみましょう。 1 つの GridView 内のすべての 製品を一覧表示するページから、ユーザーは、すべてのシーフード製品をまとめてグループ化するカテゴリ別に結果を並べ替えるのが最善の策であると判断する場合があります。 カテゴリ別に並べ替えた後、ユーザーはリストを探して、シーフードグループ化された製品の開始と終了を探す必要があります。 結果はカテゴリ名でアルファベット順に並べられているため、シーフード製品を見つけることは難しくありませんが、グリッド内の項目のリストを厳密にスキャンする必要があります。
並べ替えられたグループ間の境界を強調するために、多くの Web サイトでは、このようなグループ間に区切り記号を追加するユーザー インターフェイスが使用されています。 図 1 に示すような区切り記号を使用すると、ユーザーは特定のグループをより迅速に見つけて境界を特定し、データに存在する個別のグループを確認できます。
図 1: 各カテゴリ グループが明確に識別されている (クリックするとフルサイズの画像が表示されます)
このチュートリアルでは、このような並べ替えユーザー インターフェイスを作成する方法について説明します。
手順 1: 標準の並べ替え可能な GridView の作成
GridView を拡張して拡張並べ替えインターフェイスを提供する方法を調べる前に、まず、製品を一覧表示する標準の並べ替え可能な GridView を作成しましょう。 まず、フォルダー内の CustomSortingUI.aspx
ページを PagingAndSorting
開きます。 ページに GridView を追加し、そのプロパティを ID
に ProductList
設定し、それを新しい ObjectDataSource にバインドします。 レコードを選択するために クラス s GetProducts()
メソッドをProductsBLL
使用するように ObjectDataSource を構成します。
次に、GridView に 、および BoundFields と UnitPrice
Discontinued CheckBoxField のみが含まれるSupplierName
ProductName
CategoryName
ような構成を行います。 最後に、GridView のスマート タグの [並べ替えを有効にする] チェック ボックスをオンにするか、その AllowSorting
プロパティを に true
設定して、並べ替えをサポートするように GridView を構成します。 ページにこれらの追加を CustomSortingUI.aspx
行った後、宣言型マークアップは次のようになります。
<asp:GridView ID="ProductList" runat="server" AllowSorting="True"
AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" EnableViewState="False">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:C}"
HeaderText="Price" HtmlEncode="False" SortExpression="UnitPrice" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
TypeName="ProductsBLL"></asp:ObjectDataSource>
ブラウザーでこれまでの進行状況を確認してください。 図 2 は、データがカテゴリ別にアルファベット順に並べ替えられている場合の、並べ替え可能な GridView を示しています。
図 2: 並べ替え可能な GridView のデータがカテゴリ別に並べ替えられている (フルサイズの画像を表示する をクリックします)
手順 2: 区切り文字行を追加するための手法を確認する
汎用の並べ替え可能な GridView が完了したら、残っているのは、一意の並べ替えられた各グループの前に GridView に区切り行を追加できることです。 しかし、このような行を GridView に挿入するにはどうすればよいですか? 基本的に、GridView の行を反復処理し、並べ替えられた列の値間の相違点を特定し、適切な区切り行を追加する必要があります。 この問題を考えると、ソリューションが GridView のイベント ハンドラーのどこかにあるのは当然の RowDataBound
ようです。 「 データに基づくカスタム書式設定」 チュートリアルで説明したように、このイベント ハンドラーは、行のデータに基づいて行レベルの書式設定を適用する場合に一般的に使用されます。 ただし、 RowDataBound
このイベント ハンドラーから GridView にプログラムで行を追加できないため、イベント ハンドラーはここではソリューションではありません。 実際、GridView の Rows
コレクションは読み取り専用です。
GridView に行を追加するには、次の 3 つの選択肢があります。
- これらのメタデータ区切り行を、GridView にバインドされている実際のデータに追加します
- GridView がデータにバインドされたら、GridView のコントロール コレクションにインスタンスを追加
TableRow
します - GridView コントロールを拡張し、GridView の構造の構築を担当するメソッドをオーバーライドするカスタム サーバー コントロールを作成する
多くの Web ページまたは複数の Web サイトでこの機能が必要な場合は、カスタム サーバー コントロールを作成するのが最適な方法です。 ただし、これにはかなりのコードと、GridView の内部作業の深さについての徹底的な調査が必要になります。 そのため、このチュートリアルではそのオプションは考慮しません。
他の 2 つのオプションは、GridView にバインドされている実際のデータに区切り文字行を追加し、そのバインド後に GridView のコントロール コレクションを操作するオプションです。問題を異なる方法で攻撃し、ディスカッションにメリットがあります。
GridView にバインドされたデータへの行の追加
GridView がデータ ソースにバインドされると、データ ソースによって返される各レコードに 対して が作成 GridViewRow
されます。 そのため、GridView にバインドする前にデータ ソースに区切り記号レコードを追加することで、必要な区切り行を挿入できます。 図 3 に、この概念を示します。
図 3: データ ソースに区切り文字行を追加する 1 つの手法
特別な区切り記号レコードがないため、区切り記号レコードという用語を引用符で囲んで使用します。むしろ、データ ソース内の特定のレコードが通常のデータ行ではなく区切り記号として機能するようにフラグを設定する必要があります。 この例では、 で構成ProductRows
される GridView にインスタンスをバインドProductsDataTable
しています。 レコードのプロパティを に-1
設定することで、レコードに区切り行としてフラグを設定CategoryID
する場合があります (このような値は正常に存在できなかったため)。
この手法を利用するには、次の手順を実行する必要があります。
- GridView (インスタンス) にバインドするデータをプログラムで
ProductsDataTable
取得する - GridView の プロパティと
SortDirection
プロパティに基づいてデータをSortExpression
並べ替える - 内の
ProductsDataTable
をProductsRows
反復処理し、並べ替えられた列の違いがどこにあるかを探します - 各グループ境界で、区切り記号レコード
ProductsRow
インスタンスを DataTable に挿入します。このインスタンスはCategoryID
に-1
設定されています (または、レコードを区切り記号レコードとしてマークするために決定された指定)。 - 区切り文字行を挿入した後、プログラムによってデータを GridView にバインドします
これら 5 つの手順に加えて、GridView の RowDataBound
イベントのイベント ハンドラーも提供する必要があります。 ここでは、それぞれDataRow
をチェックし、CategoryID
それが区切り行 (設定が である-1
行) であるかどうかを判断します。 その場合は、書式設定またはセルに表示されるテキストを調整する必要があります。
並べ替えグループの境界を挿入するためにこの手法を使用するには、GridView Sorting
のイベントのイベント ハンドラーを提供し、 と SortDirection
の値を追跡する必要もあるため、上記よりも少し多くの作業がSortExpression
必要です。
データバインド後の GridView のコントロール コレクションの操作
データを GridView にバインドする前にメッセージングするのではなく、データが GridView にバインドされた 後 に区切り行を追加できます。 データ バインディングのプロセスによって GridView のコントロール階層が構築されます。実際には、単に Table
行のコレクションで構成されるインスタンスであり、それぞれがセルのコレクションで構成されます。 具体的には、GridView のコントロール コレクションには、そのルートにある オブジェクト、GridViewRow
GridView にバインドされた 内の各レコードDataSource
の (クラスからTableRow
派生した) 、および TableCell
内の各データ フィールドの各GridViewRow
インスタンス内の オブジェクトがDataSource
含まれますTable
。
各並べ替えグループの間に区切り行を追加するには、作成後にこのコントロール階層を直接操作できます。 GridView のコントロール階層は、ページのレンダリング時までに最後に作成されたと確信できます。 したがって、この方法はクラスの Render
メソッドをPage
オーバーライドします。その時点で、GridView の最終的な制御階層が更新され、必要な区切り行が含まれます。 図 4 は、このプロセスを示しています。
図 4: GridView のコントロール階層を操作する代替手法 (フルサイズの画像を表示する をクリックします)
このチュートリアルでは、この後者の方法を使用して、並べ替えのユーザー エクスペリエンスをカスタマイズします。
注意
このチュートリアルで説明するコードは、 Teemu Keiski のブログ エントリ「 GridView Sort Grouping でビットを再生する」で提供されている例に基づいています。
手順 3: GridView のコントロール階層に区切り文字行を追加する
コントロール階層が作成され、そのページ訪問時に最後に作成された後にのみ、区切り行を GridView のコントロール階層に追加する必要があるため、この追加はページ ライフサイクルの最後に実行し、実際の GridView コントロール階層が HTML にレンダリングされる前に実行します。 これを実現できる最新のポイントは クラスの Render
イベントです。このイベントはPage
、次のメソッド シグネチャを使用して分離コード クラスでオーバーライドできます。
protected override void Render(HtmlTextWriter writer)
{
// Add code to manipulate the GridView control hierarchy
base.Render(writer);
}
クラスの Page
元 Render
のメソッドが呼び出 base.Render(writer)
されると、ページ内の各コントロールがレンダリングされ、コントロール階層に基づいてマークアップが生成されます。 したがって、両方とも を呼び出して、ページがレンダリングされるようにし、 を呼び base.Render(writer)
出 base.Render(writer)
す前に GridView コントロール階層を操作して、レンダリング前に区切り行が GridView コントロール階層に追加されるようにすることが不可欠です。
並べ替えグループ ヘッダーを挿入するには、まず、ユーザーがデータの並べ替えを要求していることを確認する必要があります。 既定では、GridView の内容は並べ替えされないため、グループの並べ替えヘッダーを入力する必要はありません。
注意
ページが最初に読み込まれるときに GridView を特定の列で並べ替える場合は、最初のページアクセス時に GridView メソッド Sort
を呼び出します (後続のポストバックでは呼び出しません)。 これを実現するには、条件内のイベント ハンドラーに Page_Load
この呼び出しを if (!Page.IsPostBack)
追加します。 メソッドの詳細については、「 レポート データのページングと並べ替え 」チュートリアルの情報を Sort
参照してください。
データが並べ替えられたと仮定すると、次のタスクは、データが並べ替えられた列を特定し、その列の値の違いを探して行をスキャンすることです。 次のコードでは、データが並べ替えられていることを確認し、データの並べ替えの基準となる列を検索します。
protected override void Render(HtmlTextWriter writer)
{
// Only add the sorting UI if the GridView is sorted
if (!string.IsNullOrEmpty(ProductList.SortExpression))
{
// Determine the index and HeaderText of the column that
//the data is sorted by
int sortColumnIndex = -1;
string sortColumnHeaderText = string.Empty;
for (int i = 0; i < ProductList.Columns.Count; i++)
{
if (ProductList.Columns[i].SortExpression.CompareTo(ProductList.SortExpression)
== 0)
{
sortColumnIndex = i;
sortColumnHeaderText = ProductList.Columns[i].HeaderText;
break;
}
}
// TODO: Scan the rows for differences in the sorted column�s values
}
GridView がまだ並べ替えられていない場合、GridView の SortExpression
プロパティは設定されていません。 したがって、このプロパティに何らかの値がある場合にのみ、区切り行を追加します。 その場合は、データが並べ替えられた列のインデックスを次に決定する必要があります。 これを行うには、GridView のコレクションをループ処理し、GridView SortExpression
の Columns
プロパティと等しいプロパティを持SortExpression
つ列を検索します。 列のインデックスに加えて、 プロパティも取得 HeaderText
します。これは、区切り文字の行を表示するときに使用されます。
データの並べ替えの基準となる列のインデックスを使用して、最後の手順として GridView の行を列挙します。 行ごとに、並べ替えられた列の値が前の行の並べ替えられた列の値と異なるかどうかを判断する必要があります。 その場合は、コントロール階層に新 GridViewRow
しいインスタンスを挿入する必要があります。 これを行うには、次のコードを使用します。
protected override void Render(HtmlTextWriter writer)
{
// Only add the sorting UI if the GridView is sorted
if (!string.IsNullOrEmpty(ProductList.SortExpression))
{
// ... Code for finding the sorted column index removed for brevity ...
// Reference the Table the GridView has been rendered into
Table gridTable = (Table)ProductList.Controls[0];
// Enumerate each TableRow, adding a sorting UI header if
// the sorted value has changed
string lastValue = string.Empty;
foreach (GridViewRow gvr in ProductList.Rows)
{
string currentValue = gvr.Cells[sortColumnIndex].Text;
if (lastValue.CompareTo(currentValue) != 0)
{
// there's been a change in value in the sorted column
int rowIndex = gridTable.Rows.GetRowIndex(gvr);
// Add a new sort header row
GridViewRow sortRow = new GridViewRow(rowIndex, rowIndex,
DataControlRowType.DataRow, DataControlRowState.Normal);
TableCell sortCell = new TableCell();
sortCell.ColumnSpan = ProductList.Columns.Count;
sortCell.Text = string.Format("{0}: {1}",
sortColumnHeaderText, currentValue);
sortCell.CssClass = "SortHeaderRowStyle";
// Add sortCell to sortRow, and sortRow to gridTable
sortRow.Cells.Add(sortCell);
gridTable.Controls.AddAt(rowIndex, sortRow);
// Update lastValue
lastValue = currentValue;
}
}
}
base.Render(writer);
}
このコードは、GridView のコントロール階層のルートにある オブジェクトをプログラムで参照 Table
し、 という名前 lastValue
の文字列変数を作成することから始めます。 lastValue
は、現在の行の並べ替えられた列の値と前の行の値を比較するために使用されます。 次に、GridView の Rows
コレクションが列挙され、各行に対して、並べ替えられた列の値が変数に currentValue
格納されます。
注意
特定の行の並べ替えられた列の値を決定するには、セルの Text
プロパティを使用します。 これは BoundFields には適していますが、TemplateFields や CheckBoxFields などでは必要に応じて機能しません。 ここでは、間もなく別の GridView フィールドを考慮する方法について説明します。
次に currentValue
、 変数と lastValue
変数が比較されます。 異なる場合は、コントロール階層に新しい区切り文字行を追加する必要があります。 これは、オブジェクトRows
のコレクション内Table
の のGridViewRow
インデックスを決定し、新しい GridViewRow
インスタンスと TableCell
インスタンスを作成してから、 と をコントロール階層に追加TableCell
GridViewRow
することによって実現されます。
区切り行の 1 行 TableCell
は、GridView の幅全体にまたがるように書式設定され、CSS クラスを使用して SortHeaderRowStyle
書式設定され、並べ替えグループ名 (Category など) とグループの値 (飲料など) の両方が表示されるようにプロパティを持 Text
ちます。 最後に、 lastValue
が の currentValue
値に更新されます。
並べ替えグループ ヘッダー行 SortHeaderRowStyle
の書式設定に使用する CSS クラスは、ファイルで指定する Styles.css
必要があります。 どんなスタイル設定でも自由に使用できます。私は次を使用しました:
.SortHeaderRowStyle
{
background-color: #c00;
text-align: left;
font-weight: bold;
color: White;
}
現在のコードでは、並べ替えインターフェイスは BoundField による並べ替え時に並べ替えグループ ヘッダーを追加します (図 5 を参照してください。これは、仕入先による並べ替え時のスクリーンショットを示しています)。 ただし、他のフィールド型 (CheckBoxField や TemplateField など) で並べ替える場合、並べ替えグループ ヘッダーはどこにも見つかりません (図 6 を参照)。
図 5: 並べ替えインターフェイスには、BoundFields による並べ替え時に並べ替えグループ ヘッダーが含まれています (フルサイズの画像を表示する をクリックします)。
図 6: CheckBoxField の並べ替え時にグループ ヘッダーの並べ替えが見つかりません (フルサイズの画像を表示する をクリックします)
CheckBoxField による並べ替え時に並べ替えグループ ヘッダーが見つからないのは、コードで現在、 プロパティText
だけをTableCell
使用して各行の並べ替えられた列の値を決定しているためです。 CheckBoxFields の場合、TableCell
s Text
プロパティは空の文字列です。代わりに、値は、コレクションControls
内にある CheckBox Web コントロールをTableCell
介して使用できます。
BoundFields 以外のフィールド型を処理するには、変数が currentValue
チェック に割り当てられているコードを拡張して、コレクションControls
に CheckBox が存在するようにするTableCell
必要があります。 を使用 currentValue = gvr.Cells[sortColumnIndex].Text
する代わりに、このコードを次のように置き換えます。
string currentValue = string.Empty;
if (gvr.Cells[sortColumnIndex].Controls.Count > 0)
{
if (gvr.Cells[sortColumnIndex].Controls[0] is CheckBox)
{
if (((CheckBox)gvr.Cells[sortColumnIndex].Controls[0]).Checked)
currentValue = "Yes";
else
currentValue = "No";
}
// ... Add other checks here if using columns with other
// Web controls in them (Calendars, DropDownLists, etc.) ...
}
else
currentValue = gvr.Cells[sortColumnIndex].Text;
このコードでは、現在の行の並べ替えられた列 TableCell
を調べて、コレクション内に Controls
コントロールがあるかどうかを判断します。 が存在し、最初のコントロールが CheckBox の場合、 currentValue
CheckBox の Checked
プロパティに応じて、変数は Yes または No に設定されます。 それ以外の場合、値は s Text
プロパティからTableCell
取得されます。 このロジックは、GridView に存在する可能性がある任意の TemplateField の並べ替えを処理するためにレプリケートできます。
上記のコードを追加すると、中止された CheckBoxField による並べ替え時に並べ替えグループ ヘッダーが表示されるようになりました (図 7 を参照)。
図 7: CheckBoxField の並べ替え時にグループ ヘッダーの並べ替えが表示されるようになりました (フルサイズの画像を表示する をクリックします)
注意
、SupplierID
、または UnitPrice
フィールドのデータベース値CategoryID
を持つNULL
製品がある場合、これらの値は既定で GridView に空の文字列として表示されます。つまり、値を持つNULL
製品の区切り行のテキストは Category: のように読み上げられます (つまり、Category: Beverages のように Category: の後に名前はありません)。 ここに値を表示する場合は、BoundFields NullDisplayText
プロパティを表示するテキストに設定するか、区切り行の Text
プロパティに を割り当てるcurrentValue
ときに Render メソッドで条件付きステートメントを追加できます。
まとめ
GridView には、並べ替えインターフェイスをカスタマイズするための多くの組み込みオプションは含まれていません。 ただし、少し低レベルのコードでは、GridView のコントロール階層を微調整して、よりカスタマイズされたインターフェイスを作成できます。 このチュートリアルでは、並べ替え可能な GridView の並べ替えグループ区切り行を追加する方法について説明しました。これにより、個別のグループとそれらのグループの境界をより簡単に識別できます。 カスタマイズされた並べ替えインターフェイスのその他の例については、Scott Guthrie s A Few ASP.NET 2.0 GridView の並べ替えのヒントとテクニックに関するブログ エントリをチェックします。
幸せなプログラミング!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・自分自身 ASP.NET 24時間で2.0です。 にアクセスmitchell@4GuysFromRolla.comすることも、ブログを介して アクセスすることもできます。これは でhttp://ScottOnWriting.NET確認できます。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示