ほぼすべてのデータ プレゼンテーション Web アプリケーションでは、データの表示方法を整理し、ユーザーに混乱を与えないようにすることが主な目標の 1 つです。 1 ページあたり 20 件のレコードを表示することは確かに許容できますが、1 ページあたり 10,000 件のレコードを表示すると、ユーザーに不便が生じやすくなります。データを複数のページに分割して表示する、つまりデータをページングすることは、このような問題を解決する最も一般的な方法です。
1. 概要
ASP.NET 自体は、データ ページングをサポートするコントロールを 1 つだけ提供します。つまり、DataGrid ページング コントロールは、イントラネット環境での使用に適しています。DataGrid ページング コントロールによって提供される機能は提供されないようです。柔軟な Web アプリケーションを構築するには十分です。理由の 1 つは、DataGrid コントロールが Web デザイナーがページング コントロールを配置できる場所とページング コントロールの外観に制限を課していることです。たとえば、DataGrid コントロールではページング コントロールを垂直方向に配置できません。ページング テクノロジを利用できるもう 1 つのコントロールは、Repeater です。Web 開発者は、Repeater コントロールを使用してデータの表示方法を迅速に構成できますが、ページング機能は開発者自身が実装する必要があります。データ ソースは常に変化しており、データの表示方法は多岐にわたります。これらの変化する条件に合わせてページング コントロールをカスタマイズするのは明らかに時間の無駄です。特定のプレゼンテーション コントロールに限定されないユニバーサルなページング コントロールを構築すると、時間の節約に大きく役立ちます。
優れたユニバーサル データ コントロールは、通常のページング機能を提供するだけでなく、次のこともできます。
⑴ 「ホームページ」、「前のページ」、「次のページ」、「最後のページ」のページング ナビゲーション ボタンを提供します。
⑵ データ表示状況に応じてステータスを調整します。つまり、データ感度があります。ページング コントロールが 1 ページあたり 10 件のレコードを表示するように設定されているが、実際には 9 件のレコードしかない場合、データが複数のページに分割されて表示される場合、ページング コントロールは表示されません。最初のページ 「ページ」ボタンは表示されず、最後のページの「次のページ」ボタンと「最後のページ」ボタンも表示されません。
⑶ 特定のデータ表示制御に依存できない。
⑷ 既存および将来のさまざまなデータソースに適応する能力。
⑸ 表示モードは簡単に設定でき、さまざまなアプリケーションに簡単に統合できる必要があります。
⑹ ページングの準備ができたら、他のコントロールを思い出させます。
⑺ 経験の浅いWebデザイナーでも問題なく使用できるはずです。
⑻ ページング情報に関する属性データを提供します。
現在、上記の機能を提供する市販のコントロールがいくつか市販されていますが、いずれも高価です。多くの開発者にとって、ユニバーサル ページング コントロールを自分で構築することは理想的な選択です。
図 1 は、この記事のユニバーサル ページング コントロールの実行インターフェイスを示しています。表示に使用されるコントロールは、Repeater コントロールです。ページング コントロールは、4 つのナビゲーション ボタンとページ番号リンクのセットという 2 種類のコンポーネントで構成されます。
ユーザーは、表示コントロールを簡単に変更したり、ページング コントロール自体の外観を変更したりできます。たとえば、ページング コントロールと連携する表示コントロールが DataGrid コントロールに置き換えられ、ページ番号リンクと 4 つのナビゲーション ボタンが 2 行に表示されます。
ASP.NET は、ユーザー コントロール、複合コントロール、カスタム コントロールというカスタム Web コントロールを作成する 3 つの方法をサポートしています。 3 番目のタイプのコントロールであるカスタム コントロールの名前は、誤解を招きやすいです。実際、3 つのコントロールはすべてカスタム コントロールと見なす必要があります。複合コントロールと Microsoft のいわゆるカスタム コントロールの違いは、前者では CreateChildControls() メソッドが必要であることです。CreateChildControls() メソッドを使用すると、特定のイベントに基づいてコントロール自体を再描画できます。この記事のユニバーサル ページャーでは、複合コントロールを使用します。
次の UML シーケンス図は、ユニバーサル ページング コントロールの一般的なメカニズムの概要を示しています。
私たちの目標は、ユニバーサル ページング コントロールをデータを表すコントロールから独立させることですが、ページング コントロールがデータにアクセスする何らかの方法が必要であることは明らかです。 Control クラスから継承するすべてのコントロールは、DataBinding イベントを提供します。ページャー自体を DataBinding イベントのリスナーとして登録するので、ページャーはデータについて学習し、データを変更できます。 Control クラスから継承するすべてのコントロールにはこの DataBinding イベントがあるため、ページャー コントロールは特定のデータ プレゼンテーション コントロールに依存しないという目標を達成します。つまり、ページャー コントロールは Control クラスから派生するすべてのコントロールにバインドできます。つまり、ほぼすべての Web コントロールにバインドできます。
2. コア機能 プレゼンテーション
コントロールが DataBinding イベントをトリガーすると、ページング コントロールは DataSource プロパティを取得できます。残念ながら、Microsoft は、IdataSourceProvider など、すべてのデータ バインディング クラスが実装するインターフェイスを提供しておらず、Control または WebControl クラスから継承するすべてのコントロールが DataSource プロパティを持つわけではないため、唯一実現可能な Control クラスへのアップキャストには意味がありません。方法 Reflection APIを通じてDataSoruceプロパティを直接操作する方法です。イベント ハンドラー メソッドについて説明する前に、イベント ハンドラーを登録するには、まずプレゼンテーション コントロールへの参照を取得する必要があることに注意してください。ページング コントロールは、単純な文字列プロパティ BindToControl を公開します。
パブリック文字列 BindToControl
{
得る
{
if (_bindcontrol == null)
throw new NullReferenceException("ページング コントロールを使用する前に、BindToControl プロパティを設定してコントロールにバインドしてください。");
_bindcontrol を返します;}
set{_bindcontrol=value;}
メソッド
は非常に重要であるため、標準の NullReferenceException をスローする代わりに、より明確なメッセージをスローすることが最善です。ページング コントロールの OnInit メソッドで、プレゼンテーション コントロールへの参照を解決します。この例では、(コンストラクターではなく) OnInit イベント ハンドラーを使用して、JIT コンパイルされた aspx ページに BindToControl が設定されていることを確認する必要があります。
protected オーバーライド void OnInit(EventArgs e)
{
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += 新しい EventHandler(BoundControl_DataBound);
Base.OnInit(e);
...
、
ページング コントロールの親コントロールを検索することで完了します。ここで、親とはページ自体です。たとえば、ページング コントロールが Table コントロールなどの別のコントロールに埋め込まれている場合、Parent 参照は実際には Table コントロールへの参照になります。 FindControl メソッドは現在のコントロール コレクションのみを検索するため、コレクション内にプレゼンテーション コントロールが存在しない限り検索することはできません。より安全なアプローチは、ターゲット コントロールが見つかるまでコントロールのコレクションを再帰的に検索することです。
BoundControl を見つけたら、ページング コントロールを DataBinding イベントのリスナーとして登録します。ページング コントロールはデータ ソース上で動作するため、このイベント ハンドラーが呼び出しチェーンの最後のイベント ハンドラーであることが重要です。ただし、プレゼンテーション コントロールが OnInit イベント ハンドラーに DataBinding イベント ハンドラーを登録している限り (既定の動作)、ページング コントロールがデータ ソースを操作するときに問題はありません。
DataBound イベント ハンドラーは、プレゼンテーション コントロールの DataSource プロパティを取得する役割を果たします。
private void BoundControl_DataBound(オブジェクト送信者,System.EventArgs e)
{
if (HasParentControlCalledDataBinding) が戻る;
タイプ type = sender.GetType();
_datasource = type.GetProperty("データソース");
if (_datasource == null)
throw new NotSupportedException("ページング コントロールでは、プレゼンテーション コントロールに DataSource が含まれている必要があります。");
オブジェクト データ = _datasource.GetGetMethod().Invoke(sender,null);
_builder = アダプター[data.GetType()];
if (_builder == null)
throw new NullReferenceException("次のデータ ソース タイプを処理するための適切なアダプターがインストールされていません: "+data.GetType());
_builder.Source = データ
;
BindParent();
RaiseEvent(DataUpdate,this);
}
DataBound では、Reflection API を通じて DataSource プロパティを取得し、実際のデータ ソースへの参照を返そうとします。データ ソースがわかったので、ページング コントロールはデータ ソースを操作する方法も知る必要があります。ページング コントロールを特定のプレゼンテーション コントロールに依存しないようにするには、問題はさらに複雑になります。ただし、ページング コントロールを特定のデータ ソースに依存させると、柔軟なページング コントロールを設計するという目標が達成できなくなります。プラグイン アーキテクチャを使用して、ページング コントロールがさまざまなデータ ソース (.NET によって提供されるデータ ソースであってもカスタム データ ソースであっても) を確実に処理できるようにする必要があります。
堅牢でスケーラブルなプラガブル アーキテクチャを提供するために、[GoF] Builder パターンを使用してソリューションを構築します。
図 4
IDataSourceAdapter インターフェイスは、データを操作するためのページング コントロールに必要な最も基本的な要素を定義します。これは「プラグ」に相当します。
パブリックインターフェイス IDataSourceAdapter
{
int TotalCount{get;}
オブジェクト GetPagesData(int start,int end);
、
データを処理する前にデータ ソースに含まれる要素の合計数を返しますが、GetPaggedData メソッドは元のデータのサブセットを返します。たとえば、データ ソースが 20 個の要素を含む配列であると仮定すると、ページング コントロールが表示されます。データが 1 ページあたり 10 要素である場合、最初のページの要素のサブセットは配列要素 0 ~ 9 で、2 番目のページの要素のサブセットは配列要素 10 ~ 19 です。 DataViewAdapter は、DataView タイプのプラグを提供します:
内部クラス DataViewAdapter:IDataSourceAdapter
{
プライベート DataView _view;
内部 DataViewAdapter(DataView ビュー)
{
_view = ビュー;
}
public int 合計数
{
get{return (_view == null) 0 : _view.Table.Rows.Count;}
}
パブリック オブジェクト GetPagesData(int start, int end)
{
DataTable テーブル = _view.Table.Clone();
for (int i = start;i<=end && i<= TotalCount;i++)
{
table.ImportRow(_view[i-1].Row);
}
テーブルを返します。
}
、
元の DataTable のクローンを作成し、元の DataTable 内のデータを新しい DataTable にインポートする IDataSourceAdapter の GetPaggedData メソッドを実装します。 Web 開発者から実装の詳細を隠し、Builder クラスを通じてよりシンプルなインターフェイスを提供するために、このクラスの可視性は意図的に内部に設定されています。
パブリック抽象クラスAdapterBuilder
{
プライベート オブジェクト _source;
プライベート void CheckForNull()
{
if (_source == null) throw new NullReferenceException("正当なデータ ソースが提供される必要があります");
}
パブリック仮想オブジェクト ソース
{
得る
{
CheckForNull();
_source を返します;}
セット
{
_ソース = 値;
CheckForNull();
}
}
パブリック抽象 IDataSourceAdapter アダプター{get;}
、
IdataSourceAdapter 型に対してより管理しやすいインターフェイスを提供します。抽象化レベルが向上したため、AdapterBuilder はデータをページングする前に前処理を実行するための命令も提供します。さらに、このビルダーは、DataViewAdapter などの実際の実装クラスもページング コントロールのユーザーに対して透過的にします。
public class DataTableAdapterBuilder:AdapterBuilder
{
DataViewAdapter
_adapter;
{
得る
{
if (_adapter == null)
{
DataTable テーブル = (DataTable)Source;
_adapter = 新しい DataViewAdapter(table.DefaultView);
}
_adapter を返す;
}
}
public override IDataSourceAdapter アダプター
{
得る
{
ViewAdapter を返します。
}
}
}
パブリック クラス DataViewAdapterBuilder:AdapterBuilder
{
DataViewAdapter
_adapter;
{
得る
{ // 遅延したインスタンス化
if (_adapter == null)
{
_adapter = 新しい DataViewAdapter((DataView)Source);
}
_adapter を返す;
}
}
public override IDataSourceAdapter アダプター
{
get{ViewAdapter を返す;}
}
、
汎用的な DataAdapter を構築することは理にかなっている場合があります。実際には、DataTable を処理する別のコンストラクターを追加するだけで十分です。残念ながら、ユーザーが DataTable を処理するために別の機能を必要とする場合は、クラス全体を置き換えるか継承する必要があります。同じ IdataSourceAdapter を使用する新しい Builder を構築する場合、ユーザーはアダプターの実装方法をより自由に選択できます。
ページング コントロールでは、適切な Builder クラスを見つける操作は、タイプ セーフなコレクションによって完了します。
パブリック クラス AdaptorCollection:DictionaryBase
{
プライベート文字列 GetKey(キーを入力)
{
キーを返します。フルネーム;
}
パブリックAdapterCollection() {}
publicvoid Add(Type キー,AdapterBuilder 値)
{
Dictionary.Add(GetKey(キー),値);
}
publicbool を含む (Type キー)
{
return Dictionary.Contains(GetKey(key));
}
publicvoid Remove(キーを入力)
{
Dictionary.Remove(GetKey(key));
}
public AdaptorBuilder this[キーを入力]
{
get{return (AdapterBuilder)Dictionary[GetKey(key)];}
set{Dictionary[GetKey(key)]=値;}
}
AdaptorCollection は DataSource 型に依存しており、DataSource は BoundControl_DataBound を通じて巧みに導入されています
。
ここで使用されるインデックス キーは Type.FullName メソッドです。これにより、各型のインデックス キーの一意性が保証されます。同時に、各型に対して Builder が 1 つだけ存在することを保証する責任も、AdapterCollection に割り当てられます。 Builder 検索を BoundControl_DataBound メソッドに追加すると、結果は次のようになります
。
{
get{return _adapters;}
ブール
HasParentControlCalledDataBinding
{
get{return _builder != null;}
private void BoundControl_DataBound(オブジェクト送信者,System.EventArgs e
)
{
if (HasParentControlCalledDataBinding) が戻る;
タイプ type = sender.GetType();
_datasource = type.GetProperty("データソース");
if (_datasource == null)
throw new NotSupportedException("ページング コントロールでは、プレゼンテーション コントロールに DataSource が含まれている必要があります。");
オブジェクト データ = _datasource.GetGetMethod().Invoke(sender,null);
_builder = アダプター[data.GetType()];
if (_builder == null)
throw new NullReferenceException("次のデータ ソース タイプを処理するための適切なアダプターがインストールされていません: "+data.GetType());
_builder.Source = データ
;
BindParent();
RaiseEvent(DataUpdate,this);
、
HasParentControlCalledDataBinding を使用して、ビルダーが作成されているかどうかを確認します。作成されている場合、適切なビルダーを見つける操作は実行されなくなります。アダプター テーブルの初期化は、コンストラクター
public Pager()
で行われます。
{
SelectedPager=new System.Web.UI.WebControls.Style();
UnselectedPager = 新しい System.Web.UI.WebControls.Style();
_adapters = 新しいアダプタコレクション();
_adapters.Add(typeof(DataTable),new DataTableAdapterBuilder());
_adapters.Add(typeof(DataView),new DataViewAdapterBuilder());
実装される最後のメソッドは BindParent で、データを処理して返すために使用されます
。
private void BindParent()
{
_datasource.GetSetMethod().Invoke(BoundControl,
新しいオブジェクト[]{_builder.Adapter.GetPaggedData(StartRow,ResultsToShow*CurrentPage)});
データ処理は実際にはアダプターによって行われるため、このメソッドは非常に簡単です
。
このプロセスが完了したら、もう一度 Reflection API を使用しますが、今回はプレゼンテーション コントロールの DataSource プロパティを設定します。
3. インターフェイスの設計
これまでのところ、ページング コントロールのコア機能はほぼ実装されていますが、適切な表示方法が不足している場合、ページング コントロールはあまり役に立ちません。
プレゼンテーション メソッドをプログラム ロジックから効果的に分離するには、テンプレートを使用するか、より具体的には、Itemplate インターフェイスを使用するのが最善の方法です。実際、Microsoft はテンプレートの威力を明確に理解しており、ページ パーサー自体も含め、ほぼあらゆる場所でテンプレートを使用しています。残念ながら、テンプレートは一部の人が考えているほど単純な概念ではなく、その本質を真に理解するには時間がかかります。幸いなことに、この分野には多くの情報があるため、ここでは詳しく説明しません。ページング コントロールに戻ると、ホーム ページ、前のページ、次のページ、最後のページ、そしてもちろん各ページの番号という 4 つのボタンがあります。 4 つのナビゲーション ボタンは、LinkButton クラスではなく ImageButton クラスから選択されています。プロの Web デザインの観点から見ると、単調なリンクよりグラフィック ボタンの方が明らかに便利です。
public ImageButton FirstButton{get {return First;}}
public ImageButton LastButton{get {return Last;}}
public ImageButton PreviousButton{get {return Previous;}}
public ImageButton NextButton{get {return Next;}}
ページ番号は、データ ソース内のレコード数と各ページに表示されるレコード数に依存するため、動的に構築されます。ページ番号はパネルに追加され、Web デザイナーはパネルを使用してページ番号を表示する場所を指定できます。ページ番号を作成するプロセスについては後で詳しく説明します。ここで、ユーザーがページング コントロールの外観をカスタマイズできるように、ページング コントロールのテンプレートを提供する必要があります。
[テンプレートコンテナ(typeof(LayoutContainer))]
パブリック Iテンプレートのレイアウト
{
get{return (_layout;}
set{_layout =value;}
パブリック
クラス LayoutContainer:Control,INamingContainer
{
publicLayoutContainer()
{this.ID = "ページ";}
}
LayoutContainer クラスは、テンプレートのコンテナーを提供します。一般に、テンプレート コンテナーにカスタム ID を追加することは常に良いことです。これにより、イベントの処理時やページ呼び出しの際の問題が回避されます。次の UML 図は、ページング コントロールのプレゼンテーション メカニズムを説明します。
図 5
テンプレート作成の最初のステップは、aspx ページでレイアウトを定義することです。
<レイアウト>
<asp:ImageButton id="最初" Runat="サーバー" imageUrl="play2L_dis.gif"
AlternateText="ホーム"></asp:ImageButton>
<asp:ImageButton id="前" Runat="サーバー" imageUrl="play2L.gif"
AlternateText="前のページ"></asp:ImageButton>
<asp:ImageButton id="次へ" Runat="サーバー" imageUrl="play2.gif"
AlternateText="次のページ"></asp:ImageButton>
<asp:ImageButton id="Last" Runat="server" imageUrl="play2_dis.gif"
AlternateText="最後のページ"></asp:ImageButton>
<asp:Panel id="ページャー" Runat="server"></asp:Panel>
</LAYOUT>
このレイアウトの例には、テーブルなどの書式要素が含まれていません。もちろん、実際のアプリケーションでは書式要素を追加できます(追加する必要があります)。詳細については、後ほど説明を参照してください。
Itemplate インターフェイスは、テンプレートを解析してコンテナをバインドするメソッド InstantiateIn を 1 つだけ提供します。
プライベート void InstantiateTemplate()
{
_container = 新しい LayoutContainer();
Layout.InstantiateIn(_container);
最初 = (ImageButton)_container.FindControl("最初");
前 = (ImageButton)_container.FindControl("前");
Next = (ImageButton)_container.FindControl("Next");
Last = (ImageButton)_container.FindControl("Last");
Holder = (Panel)_container.FindControl("Pager");
this.First.Click += new System.Web.UI.ImageClickEventHandler(this.First_Click);
this.Last.Click += new System.Web.UI.ImageClickEventHandler(this.Last_Click);
this.Next.Click += new System.Web.UI.ImageClickEventHandler(this.Next_Click);
this.Previous.Click += new System.Web.UI.ImageClickEventHandler(this.Previous_Click);
こと
は、テンプレートのインスタンス化です。つまり、Layout.InstantiateIn(_container) を呼び出します。コンテナーは実際にはコントロールの一種であり、その使用法は他のコントロールと似ています。 InstantiateTemplate メソッドは、この機能を使用して 4 つのナビゲーション ボタンと、ページ番号を保持するために使用されるパネルを検索します。ナビゲーション ボタンは ID によって検索されます。これは、ページング コントロールに関する小さな制限です。ナビゲーション ボタンには、最初、前、次、最後という ID が指定されている必要があります。また、パネルの ID は Pager でなければなりません。見つかった。残念ながら、これは私たちが選択したプレゼンテーションメカニズムにとってより良いアプローチであるようですが、適切なドキュメントがあれば、この小さな制限が問題を引き起こさないことを願っています。もう 1 つの方法は、各ボタンを ImageButton クラスから継承させ、新しいタイプを定義することです。各ボタンは異なるタイプであるため、コンテナ内で再帰検索を実装して、さまざまな特定のボタンを見つけることができ、ボタンの ID を使用する必要がなくなります。属性。
4 つのボタンを見つけたら、適切なイベント ハンドラーをそれらにバインドします。ここでは、InstantiateTemplate をいつ呼び出すかという重要な決定を行う必要があります。通常、このタイプのメソッドは CreateChildControls メソッドで呼び出す必要があります。これは、CreateChildControls メソッドの主な目的は、子コントロールを作成するこのタイプのタスクであるためです。ページング コントロールはその子コントロールを変更しないため、何らかのイベントに基づいて表示状態を変更するために CreateChildControls によって提供される機能は必要ありません。子コントロールの表示は速いほど良いため、InstantiateTemplate メソッドを呼び出す理想的な場所は OnInit イベント内です。
protected オーバーライド void OnInit(EventArgs e)
{
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += 新しい EventHandler(BoundControl_DataBound);
InstantiateTemplate();
Controls.Add(_container);
Base.OnInit(e);
OnInit メソッドには、InstantiateTemplate メソッドの呼び出しに加えて、ページング コントロールにコンテナーを追加するという別の重要なタスクもあります
。
ページャーのコントロール コレクションにコンテナーを追加しない場合、Render メソッドが呼び出されないため、テンプレートは表示されません。
テンプレートは、Itemplate インターフェイスを実装することでプログラムで定義することもできます。柔軟性を高める手段であることに加えて、ユーザーが aspx ページを通じてテンプレートを提供しない場合に使用するデフォルトのテンプレートも提供できます。
パブリック クラス DefaultPagerLayout:ITemplate
{
プライベート ImageButton 次へ;
プライベート ImageButton First;
プライベート ImageButton 最後;
プライベート ImageButton 前へ;
プライベートパネルページャー;
public DefaultPagerLayout()
{
次 = 新しい ImageButton();
最初 = 新しい ImageButton();
最後 = 新しい ImageButton();
前 = 新しい ImageButton();
Pager = 新しいパネル();
Next.ID="次のページ"; Next.ImageUrl="play2.gif";
First.ID="最初"; First.AlternateText="ホーム";First.ImageUrl="play2L_dis.gif";
Last.ID = "最後の"; Last.AlternateText = "最後のページ";
Previous.ID="前"; Previous.AlternateText="前のページ"; Previous.ImageUrl="play2L.gif";
Pager.ID="ポケベル";
}
public void InstantiateIn(コントロールコントロール)
{
control.Controls.Clear();
テーブル table = new Table();
table.BorderWidth = Unit.Pixel(0);
テーブル.CellSpacing = 1;
テーブル.CellPadding =0;
TableRow 行 = 新しい TableRow();
row.VerticalAlign = 垂直位置合わせ.トップ;
table.Rows.Add(行);
TableCell セル = new TableCell();
cell.horizontalAlign = horizontalAlign.Right;
cell.VerticalAlign = VerticalAlign.Middle;
cell.Controls.Add(First);
cell.Controls.Add(前);
row.Cells.Add(セル);
セル = 新しい TableCell();
cell.horizontalAlign= horizontalAlign.Center;
cell.Controls.Add(ページャー);
row.Cells.Add(セル);
セル = 新しい TableCell();
cell.VerticalAlign = VerticalAlign.Middle;
cell.Controls.Add(Next);
cell.Controls.Add(最後);
row.Cells.Add(セル)
;
}
、
すべてのナビゲーション要素をプログラムで提供し、aspx ページに追加しますが、今回はナビゲーション要素は標準の HTML テーブルでフォーマットされます。今後は、ユーザーがプレゼンテーション テンプレートを提供しない場合、プログラムが自動的にデフォルトのテンプレートを提供します。
[TemplateContainer(typeof(LayoutContainer))]
パブリック Iテンプレートのレイアウト
{
get{return (_layout == null) 新しい DefaultPagerLayout():_layout;}
set{_layout =value;}
各ページ番号を生成するプロセスを見てみましょう
。
ページング コントロールは、最初にいくつかのプロパティ値を決定し、これらのプロパティ値を使用して、生成される異なるページ番号の数を決定する必要があります。
public int 現在のページ
{
得る
{
文字列 cur = (文字列)ViewState["現在のページ"];
return (cur == string.Empty || cur ==null)? 1 : int.Parse(cur);
}
セット
{
ViewState["CurrentPage"] = value.ToString();}
public
int PagersToShow
{
get{結果を返す;}
set{_results = 値;}
public
int ResultsToShow
{
get{return _resultsperpage;}
set{_resultsperpage = 値;}
は
実際に現在のページをページ番号の ViewState に保存します。PagersToShow メソッドで定義されたプロパティを使用すると、表示するページ数を指定できます。一方、ResultsToShow で定義されたプロパティを使用すると、表示するレコードの数を指定できます。各ページのデフォルト値は 10 です。
NumberofPagersToGenerate は、生成される必要がある現在のページ番号の数を返します。
private int PagerSequence
{
得る
{
Convert.ToInt32 を返す
(Math.Ceiling((double)CurrentPage/(double)PagersToShow));}
private
int NumberOfPagersToGenerate
{
get{return PagerSequence*PagersToShow;}
private
int TotalPagesToShow
{
get{return Convert.ToInt32(Math.Ceiling((double)TotalResults/(double)_resultsperpage));}
}
public int TotalResults
{
get{return _builder.Adapter.TotalCount;}
、
ユーザーの事前設定された ResultsToShow プロパティによって調整された、表示されるページの合計数を返します。
ASP.NET ではいくつかのデフォルト スタイルが定義されていますが、ページング コントロールのユーザーにとってはあまり実用的ではない可能性があります。ユーザーは、カスタム スタイルを通じてページング コントロールの外観を調整できます。
public Style UnSelectedPagerStyle {get {return UnselectedPager;}}
public Style SelectedPagerStyle {get {return SelectedPager;}}
UnSelectedPagerStyle はページ番号が選択されていない場合に使用されるスタイルを提供し、SelectedPagerStyle はページ番号が選択されている場合に使用されるスタイルを提供します。
private void GeneratePagers(WebControl コントロール)
{
control.Controls.Clear();
int pager = (PagerSequence-1)* PagersToShow +1;
for (;pager<=NumberOfPagersToGenerate && pager<=TotalPagesToShow;pager++)
{
LinkButton リンク = 新しい LinkButton();
link.Text = pager.ToString();
link.ID = pager.ToString();
link.Click += new EventHandler(this.Pager_Click);
if (link.ID.Equals(CurrentPage.ToString()))
link.MergeStyle(SelectedPagerStyle);
それ以外
link.MergeStyle(UnSelectedPagerStyle);
control.Controls.Add(リンク);
control.Controls.Add(new LiteralControl(" "));
}
プライベート
void GeneratePagers()
{
GeneratePagers(Holder);
}
GeneratePagers メソッドは、LinkButton タイプのボタンであるすべてのページ番号を動的に作成します。各ページ番号のラベルと ID 属性がループを通じて割り当てられ、同時にクリック イベントが適切なイベント ハンドラーにバインドされます。最後に、ページ番号がコンテナ コントロール (この場合はPanel オブジェクト) に追加されます。ボタン ID は、どのボタンがクリック イベントをトリガーしたかを識別するために役立ちます。イベント ハンドラーの定義は次のとおりです。
private void Pager_Click(object sender, System.EventArgs e)
{
LinkButton ボタン = (LinkButton) 送信者;
CurrentPage = int.Parse(button.ID);
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagesEventInvoker.Pager));
アップデート();
private
void Next_Click(オブジェクト送信者, System.Web.UI.ImageClickEventArgs e)
{
if (現在のページ<表示する合計ページ数)
現在のページ++;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagesEventInvoker.Next));
アップデート();
private
void Previous_Click(オブジェクト送信者, System.Web.UI.ImageClickEventArgs e)
{
if (現在のページ > 1)
現在のページ--;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagesEventInvoker.Previous));
アップデート();
}
private void First_Click(オブジェクト送信者、System.Web.UI.ImageClickEventArgs e)
{
現在のページ = 1;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagesEventInvoker.First));
アップデート();
private
void Last_Click(オブジェクト送信者, System.Web.UI.ImageClickEventArgs e)
{
現在のページ = TotalPagesToShow;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagesEventInvoker.Last));
アップデート();
、
最初にページング コントロールの現在のページを変更し、次にバインドされたコントロールを更新するという点で似ています。
private void Update()
{
if (!HasParentControlCalledDataBinding) が戻る;
applyDataSensitivityRules();
BindParent();
BoundControl.DataBind();
まず
、ページング コントロールは、HasParentControlCalledDataBinding メソッドを呼び出して、必要なアダプターが初期化されているかどうかを確認します。その場合は、データ表示条件に基づいてコントロールを自動的に調整する前述のルールを現在のコントロールに適用します。これらのルールにより、BoundControl 内のデータのさまざまな条件に基づいてページング コントロールが異なる動作をします。これらのルールはページング コントロールによって内部的に制御されますが、必要に応じて [GoF] 状態モードを使用してコントロールの外に簡単に移動できます。
public bool IsDataSensitive
{
get{return _isdatasensitive;}
set{_isdatasensitive = 値;}
プライベート
ブールIsPagerVisible
{
get{return (TotalPagesToShow != 1) && IsDataSensitive;}
ブール
IsPreviousVisible
{
得る
{
戻り値 (!IsDataSensitive)?
(現在のページ != 1);
}
ブール
IsNextVisible
{
得る
{
戻り値 (!IsDataSensitive)?
(CurrentPage != TotalPagesToShow);
}
プライベート
voidApplyDataSensitivityRules()
{
FirstButton.Visible = IsPreviousVisible;
PreviousButton.Visible = IsPreviousVisible;
LastButton.Visible = IsNextVisible;
NextButton.Visible = IsNextVisible;
if (IsPagerVisible) GeneratePagers();
、
IsPagerVisible、IsPreviousVisible、IsNextVisible などの事前定義されたルールを実装します。デフォルトでは、ページング コントロールではこれらのルールが有効になっていますが、ユーザーは IsDataSensitive プロパティを設定することでルールをオフにできます。
ここまでで、ページング コントロールの表示部分の基本的な設計が完了しました。最後に残っている仕上げ作業は、さまざまなページング制御イベントが発生したときにユーザーが必要な調整を行えるように、いくつかのイベント ハンドラーを提供することです。
public delegate void PageDelegate(object sender,PageChangedEventArgs e);
public enum PagedEventInvoker{Next,Previous,First,Last,Pager}
public class PageChangedEventArgs:EventArgs
{
プライベート int newpage;
プライベート Enum 呼び出し側;
パブリック PageChangedEventArgs(int newpage):base()
{
this.newpage = 新しいページ;
}
public PageChangedEventArgs(int newpage,PagesEventInvoker 呼び出し元)
{
this.newpage = 新しいページ;
this.invoker = 呼び出し者;
}
public int NewPage {get{新しいページを返す;}}
public Enum EventInvoker{get{呼び出し元を返す;}}
}
ページング コントロールはカスタム イベント パラメーターを返す必要があるため、専用の PageChangedEventArgs クラスを定義します。 PageChangedEventArgs クラスは、イベントをトリガーする可能性のあるコントロールの列挙子である PagedEventInvoker 型を返します。カスタム イベント パラメーターを処理するために、新しいデリゲート PageDelegate を定義します。イベントは次の形式で定義されます。
public event PageDelegate PageChanged;
public event EventHandler DataUpdate;
イベントに対応するイベント リスナーがない場合、ASP.NET は例外をスローします。ページング コントロールは、次の RaiseEvent メソッドを定義します。
private void RaiseEvent(EventHandler e,オブジェクト送信者)
{
this.RaiseEvent(e,this,null);
private void RaiseEvent(EventHandler e,object sender, PageChangedEventArgs args
)
{
if(e!=null)
{
e(送信者,引数);
}
}
private void RaiseEvent(PageDelegate e,オブジェクト送信者)
{
this.RaiseEvent(e,this,null);
private
void RaiseEvent(PageDelegate e,オブジェクト送信者, PageChangedEventArgs args)
{
if(e!=null)
{
e(送信者,引数);
}
}
イベントハンドラーは、個々のRaiseEventメソッドを呼び出すことにより、イベントをトリガーできるようになりました。
4。アプリケーションの例
この時点で、ページングコントロールの設計が完了しており、公式に使用できます。ページングコントロールを使用するには、プレゼンテーションコントロールにバインドするだけです。
<ASP:リピーターID = "リピーター" runat = "server">
<アイテムテンプレート>
列1:
<%#convert.toString(databinder.eval(container.dataitem、 "column1"))%>
<br>
列2:
<%#convert.toString(databinder.eval(container.dataitem、 "column2"))%>
<br>
列3:
<%#convert.toString(databinder.eval(container.dataitem、 "column3"))%>
<br>
<時間>
</アイテムテンプレート>
</ASP:リピーター>
<CC1:Pager ID = "Pager" resultStoshow = "2" runat = "server" bindtocontrol = "リピーター">
selectedpagertyle backcolor = "yellow" />
</cc1:ページャー
上記のASPXページは、ページコントロールをリピーターコントロールに結合し、各ページに表示されるレコードの数を2に設定します図1に示すように。以下は、図2に示すように、ページングコントロールをデータグリッドに結合する別の例です。
<asp:datagrid id = "grid" runat = "server" ></asp:datagrid>
<CC1:PAGER ID = "PagerGrid" resultStoshow = "2" runat = "server" bindtocontrol = "grid">
selectedpagertyle backcolor = "red" ></selectedpagertyle>
<レイアウト>
<ASP:ImageButton ID = "First" runat = "server" imageurl = "play2l_dis.gif" alternateText = "home"
<ASP:ImageButton ID = "前" runat = "server" imageurl = "play2l.gif" alternateText = "前ページ" ></ASP:ImageButton>
<asp:imagebutton id = "next" runat = "server" imageurl = "play2.gif" alternateText = "nextページ" ></asp:imagebutton>
<ASP:ImageButton ID = "last" runat = "server" imageurl = "play2_dis.gif" alterateText = "last page" ></asp:imagebutton>
<ASP:パネルID = "Pager" runat = "server" ></asp:パネル>
</レイアウト>
</CC1:ページャー
は、ページングコントロールが特定のデータソースを簡単に処理できることを示しています。完全な例。
カスタムWebコントロールを開発することは簡単なことではありませんが、このスキルを習得する利点は、ワークロードがわずかに増加しているため、通常のWebコントロールが多目的なコントロールを改善できますこの記事のページングコントロールは、既存および将来のパフォーマンスニーズを満たすための普遍的なコントロールを作成する一例にすぎません。
http://www.cnblogs.com/niit007/archive/2006/08/13/475501.html