Iterate over rows/checkboxes in a RadGrid - asp.net

I have a Telerik RadGrid with a GridTemplateColumn that contains a checkbox, as follows:
<telerik:GridTemplateColumn HeaderText="MINE" UniqueName="MyTemplateColumn">
<ItemTemplate>
<asp:CheckBox id="MyCheckBox" runat="server"></asp:CheckBox>
</ItemTemplate>
</telerik:GridTemplateColumn>
I want to set the box to be "checked" based on a value read from the database. I could handle the ItemDataBound event and read the database when each row is bound, but that results in n lookups. Instead, I want to handle DataBound, and then set all the values at once. So, in that method, I want code like this:
// read all values from database first, then...
foreach(var chkbox in MyRadGrid.MasterTableView.Columns.FindByUniqueName("MyTemplateColumn").FindControl("MyCheckBox")) {
chkbox.Checked = oneValue;
}
That doesn't work, because FindControl isn't a method of GridColumn, and it won't generate an iterable list of the checkboxes. What is the correct way to iterate through the checkboxes in the template column? Thanks!

Telerik got back to me on their forums with the answer, as follows:
foreach (GridDataItem item in MyRadGrid.MasterTableView.Items)
{
CheckBox chk = (CheckBox)item.FindControl("MyCheckBox");
// Set the value here
}
Hope this is useful for someone!

I am having the same issue.. this was how I did it..
'Created a local hashtable to use now and otherwise
Private _GroupMembers As New Hashtable
'Loaded it up on page load
Private Function GetMembers() As Boolean
Try
Dim da As New DataAccess
Dim ht As New Hashtable
Dim i As Int16 = 0
ht.Add("CAC", Session("cac"))
ht.Add("GroupID", _GroupID)
If da.GetData("rap_spGetGroupMemberList", ht) = True Then
If da.SQLDataRows.HasRows Then
While da.SQLDataRows.Read()
i = i + 1
_GroupMembers.Add(i, da.SQLDataRows("UserID"))
End While
End If
da.SQLDataRows.Dispose()
End If
da = Nothing
Catch ex As Exception
Console.Write(ex.Message)
End Try
End Function
'Check for contains
Protected Sub RadGrid2_ItemDataBound(ByVal sender As Object, ByVal e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid2.ItemDataBound
Try
If e.Item.IsDataBound Then
If Not e.Item.DataItem("UserID") Is Nothing Then
If Not IsDBNull(e.Item.DataItem("UserID")) Then
Dim UserID As Long = e.Item.DataItem("UserID")
If _GroupMembers.ContainsValue(UserID) Then
e.Item.Selected = True
End If
End If
End If
End If
Catch ex As Exception
Console.Write(ex.Message)
End Try
End Sub

Related

Check Checkboxes in a gridview based on a non-boolean value from a stored procedure

I am trying to check checkboxes on certain rows of a gridview based off of a selection from a dropdown. I have a gridview where the first column is a checkbox (cb_pain), and the second column is an ID (DrugID). The user makes a selection from the dropdown list, this fires a stored procedure. The stored procedure returns all of the DrugID's that need to be checked. I'm able to pull the DrugID from the data like this: dt.Rows(0)("pain1").ToString() That tells me DrugID for a row that needs to be checked.
Basically I would like to check the checkbox on the row where DrugID = dt.Rows(0)("pain1").ToString()
I think this needs to be done on the selectedindexchange of the dropdown.
My gridview looks like this: (sorry for the dot's, I couldn't figure out how to tab)
cb_pain........DrugID...............Field1
x.................3...................other data
x.................23.................other data
x.................24.................other data
x.................37.................other data
How can I use this to check the checkbox on the row that has the right DrugID?
I've tried a couple of different DirectCast things, but no success. Can anyone point me in the right direction?
Thanks
Another option that I tend to prefer is to make use of the RowDataBound event of the GridView. As each row gets data bound to it, this event gets called. What you would do is find the DrugID control and check its value. If it is what you want, do something.
First, let your GridView know of the event.
<asp:GridView ID="gvDrugs" runat="server" OnRowDataBound="gvDrugs_RowDataBound">
</asp:GridView>
Then handle the event. If the DrugID is 23, find the CheckBox and check it.
Protected Sub gvDrugs_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim lblDrugID As Label = e.Row.FindControl("lblDrugID")
If lblDrugID.Text = "23" Then
Dim cbPain As CheckBox = e.Row.FindControl("cbPain")
cbPain.Checked = True
End If
End If
End Sub
**Note here that I am assuming the types of controls to be labels and checkboxes. You have not shown your markup, so this is the best I can do.
After your edit, I would probably agree with you. This is something that could be done in the SelectedIndexChanged event of the DropDownList. Get the list of DrugIDs that need to be checked and iterate each row of your GridView, checking those that match.
Protected Sub dropdown_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim uniqueDrugIDs As HashSet(Of String) = New HashSet(Of String)()
' Here we assume dt is some sort of global variable as your question above implies
For Each dr As DataRow In dt.Rows
uniqueDrugIDs.Add(dr("drugID").ToString())
Next
For Each gvRow As GridViewRow In gvDrugs.Rows
Dim lblDrugID As Label = gvRow.FindControl("lblDrugID")
If (uniqueDrugIDs.contains(lblDrugID.Text)) Then
Dim cbPain As CheckBox = gvRow.FindControl("cbPain")
cbPain.Checked = True
End If
Next
End Sub
You can go for that kind of loop that will go through all your rows :
for (int x = 0; x < NameOfYourGrid.Rows.Count; x++)
{
GridViewRow row = (GridViewRow)NameOfYourGrid.Rows[x];
if(row("pain1").ToString() == "23")
CheckBox chk = (CheckBox)row.Cells[0].FindControl("The_Name_Of_The_Control");
}
Or, if you wich to do it on the binding ;
In the .aspx file put an explicit property on your check box :
<asp:CheckBox ID="chkInside" runat="server" Checked='<%# CheckForChecked(Container.DataItem as Whatever_the_object_is) %>' ></asp:CheckBox>
And link that event in the code behind :
protected bool CheckForChecked(Whatever_the_object_is OBJ)
{
try
{
return (bool) OBJ.Boolean_value;
// here you are supposed to have a compete Object
// OBJ.ID is suposed to be the rigth id
}
catch
{
return false;
}
}
Then the checkBox will be checked if the value is true on the gridview binding. You won't need the ID if your binding is done correctly.
I took j-f's response and got it to work when place in the right spot. At the end of filling the dataset I added this code:
Dim row As GridViewRow
For Each row In gv_pain.Rows
If row.RowType = DataControlRowType.DataRow Then
Dim lblDrugID As Label = row.FindControl("lbl_DrugID")
If lblDrugID.Text = dt.Rows(0)("pain1").ToString() Then
Dim cbPain As CheckBox = row.FindControl("CheckBoxPain")
cbPain.Checked = True
End If
End If
Next
This goes through my rows and check the correct ones.

Filling the dropdown from sql bug

Good afternoon people have been trying to fill a dropdown using a sql command, until so good, when I click on the dropdown it shows all the items, but when I try to click on an item in the dropdown it always returns the first item in the dropdown .... follows the codes, what i want to do is get the selected value and item from the dropdown and save it on a label for future use.
I appreciate all the support possible,
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
utilizador.Text = Me.Context.User.Identity.Name
If (Not Page.IsPostBack) Then
escolhePerfil()
End If
'DropDownPerfil.DataBind()
lbperfil2.Text = DropDownPerfil.SelectedItem.Text
lbnome.Text = DropDownPerfil.SelectedValue
End Sub
Function escolhePerfil() As Boolean
Dim connstring As String = "Data Source=10.2.24.17;Persist Security Info=True;User ID=sa;Password=Pr0dUn1C0$qL;database=ePrimavera"
Dim SQLData As New System.Data.SqlClient.SqlConnection(connstring)
Dim cmdSelect As New System.Data.SqlClient.SqlCommand("SELECT u.WindowsUser,u.Email ,g.Description, u.Login FROM [ePrimavera].[dbo].[PLT_Users] as u,[ePrimavera].[dbo].[PLT_UserGroups] as ug, [ePrimavera].[dbo].[PLT_Groups] as g where u.ID = ug.UserID And ug.GroupID = g.ID and u.WindowsUser like 'bancounico\" & utilizador.Text & "'", SQLData)
SQLData.Open()
Dim dtrReader As System.Data.SqlClient.SqlDataReader = cmdSelect.ExecuteReader()
If dtrReader.HasRows Then
DropDownPerfil.DataValueField = "Login"
DropDownPerfil.DataTextField = "Description"
DropDownPerfil.DataSource = dtrReader
DropDownPerfil.DataBind()
End If
SQLData.Close()
Return True
End Function
.aspx
<asp:DropDownList ID="DropDownPerfil" runat="server"
Height="16px" Width="202px" CssClass="DropBorderColor">
</asp:DropDownList>
try the following code:
Protected Sub DropDownPerfil_SelectedIndexChanged(sender As Object, e As EventArgs)
lbperfil2.Text = DropDownPerfil.SelectedItem.Text
lbnome.Text = DropDownPerfil.SelectedValue
End Sub
The problem is that you are trying to get the value "too early". The value is not valid in the Page_Load, since the control's OnLoad event fired after the Page's OnLoad (Page_Load) event.
The way, what the others wrote the correct, since the Event handlig section (inclueding control's onchanged event) will process after the Load section.
For more details check the offical ASP.NET life cycle site in the MSDN
The likely reason is that some (if not all) the values you are assigning to the DropDownList for Login are occur more than once.
When you then select an item in the DDL, if the value of that item occurs more than once, the selected index will highlight the first instance. To test this, comment out DropDownPerfil.DataValueField = "Login"
I am sure upon selection, it will highlight the correct item you intended on selecting.

get value of label when button clicked in nested repeater asp.net vb

I have nested repeaters, each item in the nested repeater has a label and a button on it, i want to beable to access the label.text when the button is clicked, I think i'm nearly there as I can return the index of the repeater and nested repeater that is clicked, i'm just having some trouble finding the label itself.
You might be able to help me without me posting the repeater code. Here is my code behind for when the button is clicked.
Protected Sub btnEditUser_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim btnEditUser As Button = DirectCast(sender, Button)
Dim reClient As RepeaterItem = DirectCast(btnEditUser.NamingContainer.Parent.Parent, RepeaterItem)
Dim reUser As RepeaterItem = DirectCast(btnEditUser.NamingContainer, RepeaterItem)
Dim selectedClient As Integer = reClient.ItemIndex
Dim selectedUser As Integer = reUser.ItemIndex
Dim UserId As Label = DirectCast(reClients.Items(selectedClient).FindControl("lUserName"), Label)
Response.Write(selectedClient & " " & selectedUser & " " & UserId.Text)
End Sub
I'm currently getting this error 'Object reference not set to an instance of an object.' when trying to write the value of UserId.Text so i think i've got it slightly wrong in this line:
Dim UserId As Label = DirectCast(reClients.Items(selectedClient).FindControl("lUserName"), Label)
This is just a guess, but sometimes you get errors like this when not all rows contain the control you're looking for. Often the code loops through the rows in order, hits a header row first that doesn't contain the relevant control, and fails.
Here is a good MSDN article - Locating a Control Inside a Hierarchy of Naming containers.
Private Function FindControlRecursive(
ByVal rootControl As Control, ByVal controlID As String) As Control
If rootControl.ID = controlID Then
Return rootControl
End If
For Each controlToSearch As Control In rootControl.Controls
Dim controlToReturn As Control =
FindControlRecursive(controlToSearch, controlID)
If controlToReturn IsNot Nothing Then
Return controlToReturn
End If
Next
Return Nothing
End Function
Try it,
Dim UserId As Label =DirectCast(FindControlRecursive(repClient,"lUserName"),Label)

ASP.Net dropdownlist within a detailsview not being set in codebehind

I have the following code in my codebehind Page_Load function that sets the default selected value of a dropdownlist in detailsview based on the name of a record returned from a sql data query.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.Page.Title = "Editing record"
'Perform dropdown list population operations
Dim myDDL As DropDownList = DetailsView1.FindControl("reqCategoryDropDown")
If Page.IsPostBack = False Then
Dim ticket_ID As String = getDataKey(DetailsView1)
'Fetch Category ID
Dim sqlText As String = "SELECT TS_REQCATEGORY FROM USR_ITFAC WHERE (TS_ID = " + ticket_ID + ") "
Dim reqDataReader As SqlDataReader = GetDataReader(sqlText)
reqDataReader.Read()
Dim category_ID As String = reqDataReader(0)
'Fetch Category name and set as selected value in dropdown list
sqlText = "SELECT TS_NAME FROM TS_SELECTIONS WHERE (TS_ID = " + category_ID + ") "
reqDataReader = GetDataReader(sqlText)
reqDataReader.Read()
category_Name = reqDataReader(0)
'myDDL.DataBind()
myDDL.SelectedValue = category_Name
End If
End Sub
My problem is that when the page loads for the first time, even though I set the selected value for the dropdownlist it will not display and instead simply displays the default first name in my dropdownlist. I tried Binding my dropdownlist before and after I set the selectedvalue, it is commented out in the sample code above, but that didn't seem to do anything.
UPDATE:
I'm setting the data source in the webform as follows:
Dropdownlist:
<asp:DropDownList DataSourceID="ReqCategoryData" DataTextField="ReqCategory" DataValueField="ReqCategory"
ID="reqCategoryDropDown" runat="server" AppendDataBoundItems="true" AutoPostBack="true">
</asp:DropDownList>
Connects to data source a few lines down:
<asp:SqlDataSource ID="ReqCategoryData" runat="server" ConnectionString="<%$ ConnectionStrings:TTPRODReportsQuery %>"
SelectCommand="SELECT TS_NAME AS ReqCategory FROM dbo.TS_SELECTIONS WHERE (TS_FLDID = 5299 AND TS_STATUS = 0) ORDER BY TS_NAME">
</asp:SqlDataSource>
UPDATE_2:
Ok, so I implemented he SQLDataSource programmatically in the code-behind under the Page_Init function as follows:
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
DetailsView1.DefaultMode = DetailsViewMode.Edit
''Setup DropDownList SqlDataSource
ddlDataSource.ID = "ReqCategoryData"
Page.Controls.Add(ddlDataSource)
ddlDataSource.ConnectionString = ConfigurationManager.ConnectionStrings("TTPRODReportsQuery").ConnectionString
ddlDataSource.SelectCommand = "SELECT TS_NAME AS ReqCategory FROM dbo.TS_SELECTIONS WHERE (TS_FLDID = 5299 AND TS_STATUS = 0) ORDER BY TS_NAME"
Dim args As New DataSourceSelectArguments
ddlDataSource.Select(args)
ddlDataSource.DataBind()
End Sub
After which I set attempt to set the selected value of the dropdownlist as above. The page is still not setting the selected value.
Perhaps check these items:
ensure you're calling myDDL.DataSource = reqDataReader or some other form of setting the DataSource of your dropdownlist.
ensure the dropdownlist has its DataTextField and DataTextField set properly. This could be in code-behind or in markup.
The 0'th index of reqDataReader -- are you sure that's the intended ordinal for the DataValueField?
Perhaps something like this:
With myDDL
.DataTextField = "CategoryName"
.DataValueField = "CategoryID" ' or perhaps CategoryName as your value.
.DataSource = reqDataReader
.DataBind()
.SelectedValue = category_Name ' Name or ID; depends on what was set as DataValueField
End With
DataBinding - Code-Behind vs. Markup DataSources
Consider choosing one style of binding your dropdownlist - in code-behind or with a markup SqlDataSource. Having both generates confusion on which bind wins - the code-behind or the datasource. I think it's the SqlDataSource in this case.
Consider removing the SqlDataSource from out of the markup, and create a method in code-behind whose sole purpose is to create the data binding. This is the only place where the binding should happen. If you ever need to track down a defect or enhance your logic, it's the only one place to visit.
Private Sub BindMyDropDown(Optional ByVal selectedValue as String)
With myDDL
.DataTextField = "CategoryName"
.DataValueField = "CategoryID" ' or perhaps CategoryName as your value.
.DataSource = LoadTicketReqCategory(TicketID)
.DataBind()
.SelectedValue = selectedValue ' Name or ID; depends on what was set as DataValueField
End With
End Sub
From your Page_Load(), check for IsPostBack() and call this method when you aren't posting back.
myDDL.ClearSelection
item = myDDL.Items.FindByValue(category_Name)
item.selected = true
--
You could also try setting the SelectedIndex to 2, for example, to check it that way.
The problem might be that you are assigning the myDDL variable outside of the postback check.
Dim myDDL As DropDownList = DetailsView1.FindControl("reqCategoryDropDown")
If Page.IsPostBack = False Then
Should be
If Page.IsPostBack = False Then
Dim myDDL As DropDownList = DetailsView1.FindControl("reqCategoryDropDown")

Implementing clickable page numbers in search result

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.

Resources