Repeater with Paging Control and Entity Framework
2 min read
In ASP.NET the only native control that support paging is the GridView. This one renders the all stuff creating a table that is obviously not flexible for all the layouts.
Using the Entity Framework and an EntityDataSource you can easily create a control that pages your data indeed.
In this example we have chosen a set of LinkButton to navigate through pages. You are of course free to use the control that you prefer.
Basically the first thing to do with the chosen control is to link the DataSource with. Here it is:
[csharp]
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// Get the EntityDataSource
DataSource = (EntityDataSource)Page.FindControl(DataSourceID);
// Get the control to paginate
TargetControl = Page.FindControl(TargetID);
if (DataSource != null)
{
DataSource.Selecting += new EventHandler(Paging);
DataSource.Selected += new EventHandler(HandleResult);
for (int i = 0; i < 50; i++)
{
LinkButton lb = new LinkButton();
lb.ID = this.ID + "_LinkButton_" + i.ToString();
lb.Text = (i + 1).ToString() + " ";
lb.CommandArgument = i.ToString();
lb.Click += new EventHandler(ChangePage);
linkList.Add(lb);
this.Controls.Add(lb);
}
}
}
[/csharp]
In this case we have generated the list of LinkButton pre-emptively to avoid problems with the click event handling.
Now we take care of the DataSource select/selecting event for paging the data.
[csharp]
void HandleResult(object sender, EntityDataSourceSelectedEventArgs e)
{
_totalCount = e.TotalRowCount;
}
void Paging(object sender, EntityDataSourceSelectingEventArgs e)
{
e.SelectArguments.RetrieveTotalRowCount = true;
e.SelectArguments.MaximumRows = PageSize;
e.SelectArguments.StartRowIndex = (PageSize * PageIndex);
}
[/csharp]
and handle the change of the current page
[csharp]
void ChangePage(object sender, EventArgs e)
{
LinkButton lb = (LinkButton)sender;
int index = Convert.ToInt32(lb.CommandArgument);
this.PageIndex = index;
if (this.ViewState[this.ID + vS_Index] == null)
{
this.ViewState.Add(this.ID + vS_Index, index);
}
else
{
this.ViewState[this.ID + vS_Index] = index;
}
if (TargetControl != null)
TargetControl.DataBind();
}
[/csharp]
We clearly save the current page index within the ViewState and we go through defining our control.
[csharp]
protected override void OnPreRender(EventArgs e)
{
if (this.ViewState[this.ID + viewStateName] == null)
{
PageIndex = 0;
}
else
{
PageIndex = Convert.ToInt32(this.ViewState[this.ID + vS_Index]);
}
int pageNumber = _totalCount / PageSize;
if ((pageNumber * PageSize) < _totalCount)
pageNumber++;
int index = 0;
foreach (LinkButton lb in linkList)
{
int linkIndex = this.Controls.IndexOf(lb);
if (index == PageIndex)
{
// Current page
Label label = new Label();
label.Text = lb.Text;
label.CssClass = CssDisabledLink;
Panel pan = new Panel();
pan.CssClass = ItemCss;
pan.Controls.Add(label);
this.Controls.Remove(lb);
this.Controls.AddAt(linkIndex, pan);
if (index < pageNumber -1)
{
Panel sep = new Panel();
sep.CssClass = SeparatorCss;
this.Controls.AddAt(linkIndex + 1, sep);
}
}
else
if (index >= pageNumber)
{
// Unused page
this.Controls.Remove(lb);
}
else
{
// Active page
Panel pan = new Panel();
pan.Controls.Add(lb);
pan.CssClass = ItemCss;
this.Controls.Remove(lb);
this.Controls.AddAt(linkIndex, pan);
if (index < pageNumber - 1)
{
Panel sep = new Panel();
sep.CssClass = SeparatorCss;
this.Controls.AddAt(linkIndex + 1, sep);
}
}
index++;
}
base.OnPreRender(e);
}
[/csharp]
We then added divs and panels around LinkButtons and replaced the "selected" one with a Label. Appearance always matter.
Bye Marco.
Using the Entity Framework and an EntityDataSource you can easily create a control that pages your data indeed.
In this example we have chosen a set of LinkButton to navigate through pages. You are of course free to use the control that you prefer.
Basically the first thing to do with the chosen control is to link the DataSource with. Here it is:
[csharp]
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// Get the EntityDataSource
DataSource = (EntityDataSource)Page.FindControl(DataSourceID);
// Get the control to paginate
TargetControl = Page.FindControl(TargetID);
if (DataSource != null)
{
DataSource.Selecting += new EventHandler(Paging);
DataSource.Selected += new EventHandler(HandleResult);
for (int i = 0; i < 50; i++)
{
LinkButton lb = new LinkButton();
lb.ID = this.ID + "_LinkButton_" + i.ToString();
lb.Text = (i + 1).ToString() + " ";
lb.CommandArgument = i.ToString();
lb.Click += new EventHandler(ChangePage);
linkList.Add(lb);
this.Controls.Add(lb);
}
}
}
[/csharp]
In this case we have generated the list of LinkButton pre-emptively to avoid problems with the click event handling.
Now we take care of the DataSource select/selecting event for paging the data.
[csharp]
void HandleResult(object sender, EntityDataSourceSelectedEventArgs e)
{
_totalCount = e.TotalRowCount;
}
void Paging(object sender, EntityDataSourceSelectingEventArgs e)
{
e.SelectArguments.RetrieveTotalRowCount = true;
e.SelectArguments.MaximumRows = PageSize;
e.SelectArguments.StartRowIndex = (PageSize * PageIndex);
}
[/csharp]
and handle the change of the current page
[csharp]
void ChangePage(object sender, EventArgs e)
{
LinkButton lb = (LinkButton)sender;
int index = Convert.ToInt32(lb.CommandArgument);
this.PageIndex = index;
if (this.ViewState[this.ID + vS_Index] == null)
{
this.ViewState.Add(this.ID + vS_Index, index);
}
else
{
this.ViewState[this.ID + vS_Index] = index;
}
if (TargetControl != null)
TargetControl.DataBind();
}
[/csharp]
We clearly save the current page index within the ViewState and we go through defining our control.
[csharp]
protected override void OnPreRender(EventArgs e)
{
if (this.ViewState[this.ID + viewStateName] == null)
{
PageIndex = 0;
}
else
{
PageIndex = Convert.ToInt32(this.ViewState[this.ID + vS_Index]);
}
int pageNumber = _totalCount / PageSize;
if ((pageNumber * PageSize) < _totalCount)
pageNumber++;
int index = 0;
foreach (LinkButton lb in linkList)
{
int linkIndex = this.Controls.IndexOf(lb);
if (index == PageIndex)
{
// Current page
Label label = new Label();
label.Text = lb.Text;
label.CssClass = CssDisabledLink;
Panel pan = new Panel();
pan.CssClass = ItemCss;
pan.Controls.Add(label);
this.Controls.Remove(lb);
this.Controls.AddAt(linkIndex, pan);
if (index < pageNumber -1)
{
Panel sep = new Panel();
sep.CssClass = SeparatorCss;
this.Controls.AddAt(linkIndex + 1, sep);
}
}
else
if (index >= pageNumber)
{
// Unused page
this.Controls.Remove(lb);
}
else
{
// Active page
Panel pan = new Panel();
pan.Controls.Add(lb);
pan.CssClass = ItemCss;
this.Controls.Remove(lb);
this.Controls.AddAt(linkIndex, pan);
if (index < pageNumber - 1)
{
Panel sep = new Panel();
sep.CssClass = SeparatorCss;
this.Controls.AddAt(linkIndex + 1, sep);
}
}
index++;
}
base.OnPreRender(e);
}
[/csharp]
We then added divs and panels around LinkButtons and replaced the "selected" one with a Label. Appearance always matter.
Bye Marco.