I'm new to ASP and was hoping to get some guidance on how to make my literal accessible in my Code Behind and then change it to the text of a passed in parameter.
I have an resources.ascx file that displays a list of people (pulled from a database). That is working fine and it looks something like this:
Full name
T: (888-888-8888)
F: (888-888-8888)
The problem, however, is that I now want it conditionally say "Toll Free" instead of "F:" for one page.
In the people.aspx page, I'm passing in "Toll Free" to the resource:
<%# Register Src="~/UserControls/resources.ascx" TagName="Resources" TagPrefix="ucResources" %>
<ucResources:Resources ID="Resources1" FaxNumberAlias="Toll Free" runat="server" />
resources.ascx The repeater outputs all the people from the database to the page.
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<div class="sectioncontent">
<b><%#Eval("EmployeeFirstName")%> <%#Eval("EmployeeLastName)%></b>
T: <%#Eval("Phone")%>
<br>
<asp:Literal runat="server" ID="FaxNumberLabel">F:</asp:Literal> <%#Eval("Fax")%><br>
</div>
<br />
</ItemTemplate>
In the resources.ascx.vb file, I wanna do something like this but FaxNumberLabel (the literal I declared in resources.ascx) isn't accessible or hasn't been declared.
Public Property FaxNumberAlias() As String
Get
Return _FaxNumberAlias
End Get
Set(ByVal value As String)
_FaxNumberAlias = value
End Set
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not String.IsNullOrEmpty(_FaxNumberAlias) Then
FaxNumberLabel.Text = _FaxNumberAlias
End If
PopulateRepeater()
End Sub
What am I missing that connects the literal to the code behind?
The problem is that the Literal is inside a Repeater so you may potentially have lots of them. The best way is to access them inside the OnDataItemBound event of your repeaters:
Protected Sub Repeater1_OnDataItemBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs) Handles Repeater1.OnDataItemBound
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim litFaxNumberLabel As Literal = e.Item.FindControl("FaxNumberLabel")
litFaxNumberLabel.Text = _FaxNumberAlias
End If
End Sub
Note: Excuse any bad syntax, it's been over 4 years since I touched VB!
You can simply use like this -
protected void DataDisplay_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
LinkButton lit = (LinkButton)e.Item.FindControl("LinkButton2");
if (lit.Text == "0")
{
int a = Convert.ToInt32(lit.Text);
if (a == 0)
{
if (a == 0)
{
lit.Text = "Your Text";
}
}
}
}
}
In my case, I am using a button (btnRedirect) in each row.
RepeaterItem item = btnRedirect.NamingContainer as RepeaterItem;
var type = item.FindControl("IdUsed") as Literal;
var literalValue = type.Text;
Related
The ASPX that I have is a partial that has a a master page on it and I would like to replace a textbox with new text.
I have a listbox that is created from the data base in the ASCX. I have a text box in the default.aspx page which I would like to change the test if the selected index has changed. I keep getting the error to delcare class, the class definiton for the defualt.aspx.vb is got a definition is below.
Partial Class _Default
Inherits System.Web.UI.Page
Code that sits on default.aspx.vb
Public Sub test(ByVal val As String)
lbl1LoginPage.Text = val
End Sub
VB ascx code to get the value of the selected index
Protected Sub ListBox3_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles ListBox3.SelectedIndexChanged
Dim test As String = ListBox3.Text
Dim page As _Default = DirectCast(page, _Default)
page.test(test)
End Sub
You can create a Property in aspx page exposing the text box control say "TextBoxControl" then you can access it in you dropdownlist handler as shown below :
Protected Sub ListBox3_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles ListBox3.SelectedIndexChanged
Dim test As String = ListBox3.Text
Dim page As _Default = DirectCast(Me.Page, _Default)
page.TextBoxControl.Text = "Some Text"
End Sub
(I am not well versed with vb.net so syntax may be wrong at some places)
My suggestion is to use a bubble event:
Protected Sub ListBox3_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles ListBox3.SelectedIndexChanged
Dim test As String = ListBox3.Text
// this line is in C#. I don't know how it is in VB
RaiseBubbleEvent( this, new CommandEventArgs( "ListBoxText", test ) );
End Sub
this is all in C#!! here is your method in your aspx-page:
protected override bool OnBubbleEvent( object source, EventArgs args )
{
// you can check in addition whether the source is of type of your user control
if ( args is CommandEventArgs )
{
lbl1LoginPage.Text = ((CommandEventArgs)args ).CommandArgument.ToString();
return true;
}
return base.OnBubbleEvent( source, args );
}
UserControl should not call Parent page. It is not a good design.
Instead, you want to bubble up the event from UserControl to the Parent page.
Here is the example -
Child
<asp:ListBox runat="server" ID="ListBox3"
OnSelectedIndexChanged="ListBox3_SelectedIndexChanged"
AutoPostBack="True">
<asp:ListItem>Item 1</asp:ListItem>
<asp:ListItem>Item 2</asp:ListItem>
</asp:ListBox>
Public Partial Class Child
Inherits System.Web.UI.UserControl
Public Event ListBox3SelectedIndexChanged As EventHandler
Protected Sub ListBox3_SelectedIndexChanged(sender As Object, e As EventArgs)
RaiseEvent ListBox3SelectedIndexChanged(sender, e)
End Sub
End Class
Parent
<%# Register Src="~/Child.ascx" TagName="Child" TagPrefix="uc1" %>
...
<uc1:Child ID="Child1" runat="server"
OnListBox3SelectedIndexChanged="Child1_ListBox3SelectedIndexChanged" />
Protected Sub Child1_ListBox3SelectedIndexChanged(sender As Object,
e As EventArgs)
Dim listBox3 = TryCast(sender, ListBox)
If listBox3 IsNot Nothing Then
Dim selectedText As String = listBox3.SelectedItem.Text
End If
End Sub
I want to store the value of a databound repeat to a session state.
This is my code so far:
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1">
<ItemTemplate>
<h1 id="price" class="QPrice">$<%# Eval("Price")%></h1>
</ItemTemplate>
</asp:Repeater>
Code Behind"
Session("Qprice") = ?
How do I retrive the value of the h1 element or retrive a specific value of SqlDatasource1, from the codebehind?
Session("Qprice"+ID) = (decimal)drv.Row["Price"];
In the end you will have all prices in session, and you can access by the id's of the data that has bound to the list. But you are storing information that you have access.
In the repeater1 define the object DatakeyNames="Price" and specify the Item Data Bound event
then in code behind
protected void repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item
|| e.Item.ItemType == ListItemType.AlternatingItem)
{
Button b = e.Item.FindControl("myButton") as Button;
DataRowView drv = e.Item.DataItem as DataRowView;
Session("Qprice") = (decimal)drv.Row["Price"];
}
}
Here you can save the value or do whatever you want with price.
I would store it to strongly type List first and store it in Session
Protected Sub Repeater1_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
Dim repeaterItems As New List(Of Decimal)()
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
Dim b As Button = TryCast(e.Item.FindControl("myButton"), Button)
Dim drv As DataRowView = TryCast(e.Item.DataItem, DataRowView)
repeaterItems.Add(CDec(drv.Row("Price")))
End If
Session("Qprice") = repeaterItems
End Sub
So I can access it again later like
Dim repeaterItemsFromSession As List(Of Decimal) = DirectCast(Session("Qprice"), List(Of Decimal))
Trying to use data binding between a list of objects and a data list control. What I want to do are
create the list of objects
have them bound to the controls
change data in the UI
have the changes in the ui bound to the list of objects
on post back - have the list of objects with the new values from the ui
<body>
<form id="form1" runat="server">
<div>
<asp:DataList ID="DataList1" runat="server" DataKeyField="ClassID" ViewStateMode="Enabled">
<ItemTemplate>
<asp:TextBox ID="txtValue1" runat="server" Text='<%# Bind("Value1") %>'></asp:TextBox>
<asp:TextBox ID="txtValue2" runat="server" Text='<%# Bind("Value2") %>'></asp:TextBox>
<asp:TextBox ID="txtvalue3" runat="server" Text='<%# Bind("Value3") %>'></asp:TextBox>
</ItemTemplate>
</asp:DataList>
<asp:Button ID="btnDoPostBack" runat="server" Text="Do Post Back" />
</div>
</form>
</body>
Option Explicit On
Option Strict On
Imports System.Diagnostics
Partial Class _Default
Inherits System.Web.UI.Page
Dim Class1List As List(Of Class1)
Protected Sub Page_PreLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreLoad
Dim txtValue1 As TextBox
Dim txtValue2 As TextBox
Dim txtValue3 As TextBox
Dim ItemIndex As Integer = 0
If Page.IsPostBack Then
Class1List = CType(Session("Class1List"), List(Of Global.Class1))
'Class1List = CType(DataList1.DataSource, List(Of Global.Class1))
For Each myDataListItem As DataListItem In DataList1.Items
txtValue1 = CType(myDataListItem.FindControl("txtValue1"), TextBox)
Long.TryParse(txtValue1.Text, Class1List(ItemIndex).Value1)
txtValue2 = CType(myDataListItem.FindControl("txtValue2"), TextBox)
Integer.TryParse(txtValue2.Text, Class1List(ItemIndex).Value2)
txtValue3 = CType(myDataListItem.FindControl("txtValue3"), TextBox)
Class1List(ItemIndex).Value3 = txtValue3.Text
ItemIndex += 1
Next
End If
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim myClass1 As Class1
If Not Page.IsPostBack Then
Class1List = New List(Of Class1)
myClass1 = New Class1
Class1List.Add(myClass1)
BindData()
Else
'Class1List = CType(DataList1.DataSource, List(Of Global.Class1))
Debug.WriteLine("Page_Load, Value1 = " & Class1List(0).Value1.ToString())
Debug.WriteLine("Page_Load, Value2 = " & Class1List(0).Value2.ToString())
Debug.WriteLine("Page_Load, Value3 = " & Class1List(0).Value3)
End If
End Sub
Protected Sub Page_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Unload
Session("Class1List") = Class1List
End Sub
Sub BindData()
DataList1.DataSource = Class1List
DataList1.DataBind()
End Sub
Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) Handles DataList1.ItemDataBound
Dim myClass1 As Class1
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
myClass1 = CType(e.Item.DataItem, Class1)
Debug.WriteLine("DataList1_ItemDataBound, Value1 = " & myClass1.Value1.ToString())
Debug.WriteLine("DataList1_ItemDataBound, Value2 = " & myClass1.Value2.ToString())
Debug.WriteLine("DataList1_ItemDataBound, Value3 = " & myClass1.Value3)
End If
End Sub
Protected Sub btnDoPostBack_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDoPostBack.Click
Dim myRandom As New Random
Class1List(0).Value1 = myRandom.Next(100)
Class1List(0).Value2 = myRandom.Next(100)
Class1List(0).Value3 = myRandom.Next(100).ToString()
Debug.WriteLine("btnDoPostBack_Click, Value1 = " & Class1List(0).Value1.ToString())
Debug.WriteLine("btnDoPostBack_Click, Value2 = " & Class1List(0).Value2.ToString())
Debug.WriteLine("btnDoPostBack_Click, Value3 = " & Class1List(0).Value3)
BindData()
End Sub
End Class
The Class Class1 is trivial:
Option Explicit On
Option Strict On
Imports Microsoft.VisualBasic
Public Class Class1
Private _ClassID As Long
Private _Value1 As Long
Private _Value2 As Integer
Private _value3 As String = String.Empty
Public Property ClassID As Long
Get
Return _ClassID
End Get
Set(ByVal value As Long)
_ClassID = value
End Set
End Property
Public Property Value1 As Long
Get
Return _Value1
End Get
Set(ByVal value As Long)
_Value1 = value
End Set
End Property
Public Property Value2 As Integer
Get
Return _Value2
End Get
Set(ByVal value As Integer)
_Value2 = value
End Set
End Property
Public Property Value3 As String
Get
Return _value3
End Get
Set(ByVal value As String)
_value3 = value
End Set
End Property
End Class
Update: I got the code behind above to do what I want it to do - I was thinking there was a better way?
You didn't show your databinding "Load" phase (the code which binds the data from the list to the controls)--so I assume the part you are unhappy with is the "Save" phase (the code in Page_PreLoad which binds the modified values from the controls back to the list), i.e. #4 in your list:
have the changes in the ui bound to the list of objects
It sounds like you want "two-way Data Binding": you want .NET to update your model as easily as it reads from your model. This is a common complaint. One solution is to subclass WebControl, but that's a mess.
You are already using the <%# Bind("...") %> syntax, so you have the right idea. That approach should work out-of-the-box with <asp:SqlDataSource>, but you want to update a custom class, so you need to use <asp:ObjectDataSource> instead. Use the approach in this article, except with ObjectDataSource instead of SqlDataSource.
But first you have to make your model (i.e., Class1) compatible with ObjectDataSource by marking it with [System.ComponentModel.DataObject] and designating the appropriate update method like this:
[System.ComponentModel.DataObjectMethodAttribute(
System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateProduct(string productName, ...) {
...
}
This would allow you to use an ObjectDataSource on your webform and finally get nice 2-way databinding. Read the links to for full details.
Visual Studio offers various clunky ways of automating this, such as TableAdapters and the infamous Strongly-Typed DataSet (STD), but those don't help people like yourself who have their own object model. I don't recommend STDs anyway.
I was thinking there was a better way?
I don't think your current approach is bad. If you're worried about having tons of logic in your webforms, you would gain much more by using an MVC approach than worrying about binding sugar...
I am trying to access a control inside a Repeater. The control is inside the <ItemTemplate> tag. I am using FindControl but it's always coming out Null.
What am I doing wrong?
My guess is that FindControl can only be used in record-level events such as ItemDataBound:
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
(ControlTypeCast) e.Item.FindControl("myControl")).SomeProperty = "foo";
}
I'm guessing that you're trying to find a control at the wrong point in the page lifecycle. The ItemDataBound event is where you need to look for it.
This example is in vb.net, but I'm sure you get the idea.
Protected Sub rp_items_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rp_items.ItemDataBound
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
Dim someLiteral As Literal = e.Item.FindControl("someliteral")
End If
End Sub
In most cases, spelling the control name wrong :) It may also be that you are searching for a control that exists within another container. Can you post your code?
for (int i = 0; i <= repeater1.Items.Count - 1; i++)
{
Button delete = (Button)repeater1.Items[i].FindControl("btnDelete");
delete.Visible = true;
Button edit = (Button)repeater1.Items[i].FindControl("btnEdit");
edit.Visible = true;
}
Vb.net
For i As Integer = 0 To Repeater1.Items.Count - 1
Dim CmbTyp As DropDownList = DirectCast(Repeater1.Items(i).FindControl("DropDownList1"),DropDownList)
Dim SeatN As Label = DirectCast(Repeater1.Items(i).FindControl("label1"), Label)
styp = CmbTyp.SelectedItem.Text.Trim
sNo = SeatN.Text
Next
Try This
For vb.net
CType(e.Item.FindControl("myControl"), Literal).Text = "foo"
For c#
[Literal]e.item.FindControl["myControl"].Text="foo";
Classic scenario: Take user input, get a search-result and display it in pages to the user. I then need to display buttons for First, Next, Previous etc, and I maintain the users current page in viewstate. All is good, works fine.
Then I need to implement clickable page numbers, ie. 1-2-3-4-5-6 etc.
Rendering them is simple. I generate a linkbutton control at runtime, add commandargument with the page number and add a handler to it, so click are to be handled. Then I add it to a placeholder, and it is displayed as expected.
But then... If I did not already have a shaved head, I would be pulling out my hair getting the events to fire as expected every time.
How should I do this, so my events are always wired up and able to fire when the paging-linkbuttons are called?
Below is the important parts of the code, some pseudo to make it (hopefully) easier to understand, what I am doing.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Search()
End If
End Sub
Sub Search
'Misc databinding stuff, searches and displays results for the page specified in Me.CurrentPage
RenderPagingControls()
End Sub
Sub RenderPagingControls
'loop throug pagenumbers, Build a linkbutton control, add it to a placeholder
AddHandler lbn.Click, AddressOf lbnNumber_Click
lblPageNumbers.Controls.Add(lbn)
...
End Sub
Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim b As LinkButton = CType(sender, LinkButton)
Me.CurrentPage = CInt(b.CommandArgument)
Search()
End Sub
Public Property CurrentPage() As Integer
Get
Dim o As Object = Me.ViewState("CurrentPage")
If o Is Nothing Then
Return 1
Else
Return CType(o, Integer)
End If
End Get
Set(ByVal value As Integer)
Me.ViewState("CurrentPage") = value
End Set
End Property
Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim b As LinkButton = CType(sender, LinkButton)
Me.CurrentPage = CInt(b.CommandArgument)
Search()
End Sub
I'm going to recommend against a LinkButton and recommend Hyperlinks / QueryString parameters instead. For several reasons:
Your page will be much more efficient without the viewstate overhead of a link button.
If these are public facing pages, you'll get better indexing of all the pages if they can be accessed via hyperlinks (and indexed via search engines).
You'll find them much easier to implement. No event management, etc.
You would redefine your CurrentPage method as (hopefully this is correct, I'm better at C# than vb.net):
Public Property CurrentPage() As Integer
Get
Dim o As Object = Me.Request.QueryString("page")
If o Is Nothing Then
Return 1
Else
Return CType(o, Integer)
End If
End Get
End Property
Then just add hyperlinks for each page.
<a href='mypage.aspx?page=1'>1</a> - <a href='mypage.aspx?page=2'>2</a>
etc...
Alternative: If you want to use the LinkButton, you might want to consider putting a single LinkButton in a repeater. Then the only event you have to worry about is the OnItemCommand event. Then no dynamic controls or events. Something like this:
<asp:Repeater ID="rptPages" runat="server" OnItemCommand='doPaging'>
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" Text='<%# (Container.DataItem).ToString() %>'
CommandArgument='<%# (Container.DataItem).ToString() %>' />
</ItemTemplate>
<SeparatorTemplate>-</SeparatorTemplate>
</asp:Repeater>
Bind this control to an array (or list) of consecutive Integers (as many are there are pages). Then in your doPaging function (as I call it), check RepeaterCommandEventArgs.CommandArgument to get the page number.
Thanks for the answers, guys. I tried out Austins first, but I must be missing something, because I keep getting the same behavior of link buttons only working every second time... So I gave up on that, and saw the alternative solution with the repeater by Keltex! It is as brilliant as it is simple, and we don't have to worry about any page life-cycle bullshit.
It just really works! ;)
If somebody should need something similar in the future, here is the relevant code behind the scenes:
Sub Search()
...
RenderPagingControls()
End Sub
Sub RenderPagingControls()
Dim pages As New ArrayList
For i As Integer = 1 To Me.PageCount
pages.Add(i)
Next
repPageNumbersTop.DataSource = pages
repPageNumbersTop.DataBind()
repPageNumbersBottom.DataSource = pages
repPageNumbersBottom.DataBind()
End Sub
Public Property CurrentPage() As Integer
Get
Dim o As Object = Me.ViewState("CurrentPage")
If o Is Nothing Then
Return 1
Else
Return CType(o, Integer)
End If
End Get
Set(ByVal value As Integer)
Me.ViewState("CurrentPage") = value
End Set
End Property
Public Property PageCount() As Integer
Get
Dim o As Object = Me.ViewState("PageCount")
If o Is Nothing Then
Return 0
Else
Return CType(o, Integer)
End If
End Get
Set(ByVal value As Integer)
Me.ViewState("PageCount") = value
End Set
End Property
Protected Sub repPageNumbersTop_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles repPageNumbersTop.ItemCommand, repPageNumbersBottom.ItemCommand
Me.CurrentPage = CType(e.CommandArgument, Integer)
Search()
End Sub
Private Sub repPageNumbersTop_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles repPageNumbersTop.ItemDataBound, repPageNumbersBottom.ItemDataBound
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Dim lbn As LinkButton = CType(e.Item.FindControl("lbnPageNumber"), LinkButton)
If lbn.CommandArgument = Me.CurrentPage.ToString Then
lbn.Enabled = False
End If
End If
End Sub
This code works (sorry it's in C#):
protected void SearchButton_Click(object sender, EventArgs e)
{
//clear the collection!
pnlPageNumber.Controls.Clear();
//simulate search
System.Random rnd = new Random();
//create page buttons
for (int i = 0; i < rnd.Next(3, 15); i++)
{
LinkButton lb = new LinkButton();
pnlPageNumber.Controls.Add(lb);
lb.ID = "btn" + i;
lb.Text = i.ToString();
lb.CommandArgument = i.ToString();
lb.Command += new CommandEventHandler(linkbutton_Command);
//optional literal
pnlPageNumber.Controls.Add(new LiteralControl(" "));
}
ViewState["control#"] = Panel1.Controls.Count;
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
//Recreate link buttons
//This is necessary to ensure proper event binding
int count = 0;
if (ViewState["control#"] != null)
count = (int)ViewState["control#"];
for (int i = 0; i < count; i++)
{
LinkButton lb = new LinkButton();
pnlPageNumber.Controls.Add(lb);
lb.ID = "btn" + i; //make sure IDs are the same here and on Search
lb.Command += new CommandEventHandler(linkbutton_Command);
//this is not necessary, but if you do, make sure its in both places
pnlPageNumber.Controls.Add(new LiteralControl(" "));
}
}
}
void linkbutton_Command(object sender, CommandEventArgs e)
{
Response.Write(e.CommandArgument.ToString() + " CLICK<br />");
}
You could use the DataPager control -- the only limitation is you have to use it with the ListView control, but you should be able to represent your data using the ListView control fairly easily because it is very flexible. You can set the DataSource of the ListView control to the result of your data result, whether that be a DataSet, Collection, Array, etc.
To create the paging controls with "first", "last", and page numbers, set up the DataPager like this (where ListView1 is the ID of your ListView control):
<asp:DataPager ID="DataPager1" runat="server"
PagedControlID="ListView1" PageSize="25">
<Fields>
<asp:NextPreviousPagerField FirstPageText="first" ShowFirstPageButton="True"
ShowNextPageButton="False" ShowPreviousPageButton="False" />
<asp:NumericPagerField />
<asp:NextPreviousPagerField LastPageText="last" ShowLastPageButton="True"
ShowNextPageButton="False" ShowPreviousPageButton="False" />
</Fields>
</asp:DataPager>
By design, the DataPager uses the whole result set from the database, but you can improve the performance by caching the result and using that on the subsequent requests.
Hope this helps.
iirc... adding controls dynamically at runtime is a bit tricky. The control tree must be rebuilt during post back... but before viewstate is loaded (not sure when in the page life cycle... but way before page load). So... your problem is that by the time asp.net is trying to figure out your event the actual originating control has not yet been created.