Why doesn't asp.net make pagination efficiently on gridview controls? - asp.net

I have a site with thousands of records and every time I make an action the gridview send around 300kb by ajax.
I try to make a custom pagination maintaining the ajax functionality, sorting, but it is so complicated.
I search for a hack to this but I don't find anything.
Links about:
http://www.nikhedonia.com/notebook/entry/efficient-paging-for-gridview/
http://kpumuk.info/asp-net/gridview-with-custom-digg-like-pager/
#mellamokb, this is the way I databind the gridview
CODE:
Dim res = From r In dc.Reservas _
From u In dc.UsuariosData Where r.usr_Id = u.usr_Id _
From c In dc.Campings Where c.camp_Id = r.camp_Id And r.sta_Id <> 2 _
From rec In dc.OrdenesRegistros Where rec.rec_Id = r.rec_Id _
From o In dc.Ordenes Where o.ord_Id = rec.ord_Id _
From p In dc.Pagos Where p.pay_Id = o.pay_Id _
From z In dc.Zonas Where z.zon_Id = r.zon_Id _
Select New With {.res_Id = r.res_Id, _
.usr_NickName = u.usr_NickName, .usr_Name = u.usr_Name, _
.usr_LastName = u.usr_LastName, .usr_Email = u.usr_Email, _
.usr_Cel = u.usr_Cel, .camp_Name = c.camp_Name, _
.res_CreationDate = r.res_CreationDate, _
.pay_Name = p.pay_Name, _
.sta_Id = r.sta_Id, .camp_Id = c.camp_Id, .res_StartDate = r.res_StartDate, _
.res_EndDate = r.res_EndDate, .zon_Id = z.zon_Id}
Session("datosGridView") = res
GridView_ZC.DataSource = Session("datosGridView")
GridView_ZC.DataBind()

The pagination should be handled by the data source control. If you are using a LinqDataSource control, then it should do the pagination with AutoPage="true" AFAIK.
Edit
Your data source has no pagination, so all of the data has to flow to the GridView before the GridView can paginate it. Your LINQ-to-SQL query returns all records.
You want to use a "smart" data source, like a LinqDataSource control. The easiest way is to declare a LinqDataSource, bind the GridView to the data source in the markup, and then override the Selecting event of the LinqDataSource to specify your custom data retrieval logic:
<asp:LinqDataSource ID="MyDataSource" runat="server"
OnSelecting="MyDataSource_Selecting" AutoPage="true" AutoSort="true">
</asp:LinqDataSource>
<asp:GridView ID="MyGridView" DataSourceID="MyDataSource" ... >
The code-behind:
Protected Sub MyDataSource_Selecting(sender As Object, _
e As LinqDataSourceSelectingEventArgs)
Dim dataContext As New MyDataContext
e.Result = ' Put LINQ-to-SQL code here
End Sub

Check this : http://www.seila.gov.kh/eang/ASPNET2.0/Web_2.0_With_ASP_NET_3.5.pdf
There a few chapters about optimization and perfomance, I recall reading something about gridview controls.

Related

VB ASP.NET - Add code to a control that is created by code behind

I'm using VB ASP.NET and would like to know how to add code to a control that is created by code behind?
For example in my Main.aspx.vb file I have the following code:
Connection.Open()
spRetrieveAlbums.ExecuteNonQuery()
ReturnValue = spRetrieveAlbums.Parameters("#ReturnValue").Value
Connection.Close()
For I = 1 To ReturnValue
Dim myAlbum = New ImageButton
myAlbum.Visible = True
myAlbum.Width = 150
myAlbum.Height = 150
myAlbum.BorderStyle = BorderStyle.Solid
myAlbum.BorderColor = Drawing.Color.WhiteSmoke
myAlbum.BorderWidth = 1
AlbumsPanel.Controls.Add(myAlbum)
Next I
ReturnValue stores the number of albums a person has (Using SQL Server stored procedure ##ROWCOUNT) and displays the same amount of ImageButtons within the 'AlbumsPanel' Panel on the web page.
I would like to use response.redirect("Albums.aspx") on a click event on any of the ImageButtons but not sure how I can achieve this. Any suggestions?
you have created dynamically and you can use a delegate for min.VB10 and like that,
AddHandler myAlbum.Click, _
Sub(sender As Object, e As EventArgs)
//To Do for Response
End Sub

Changing DropDown Selected Item Based on Selected Value (ASP.NET)

I have a dropdown list on my page (ddlProgram) which is populated via a database query like so:
Using dbContext as IRFEntities = New IRFEntities
Dim getPrograms = (From p in dbContext.IRF_Program _
Order By p.name _
Select p)
ddlProgram.DataSource = getPrograms
ddlProgram.DataTextField = "name"
ddlProgram.DataValueField = "id"
ddl.Program.DataBind()
End Using
So, for example, one might have a DataTextField of "Education" and an ID of "221".
Now, I prepopulate the form with information about the individual visiting the site (if available) - including the dropdown list like so:
If getProspect IsNot Nothing Then
If getProspect.user_id Is Nothing Then
ddlProgram.SelectedValue = getProspect.Program
End If
End If
The Program property contains a number that matches the ID of a Program. So, for example, this individual might have a Program of "221" which would match the "221" of Education mentioned above.
Currently the application successfully sets the SelectedValue to "221" for the DropDownList (ddlProgram), but the SelectedItem of the DDL remains the same (e.g., if it is initially "History" with an ID of "1" after the prepopulation it is "History" with an ID of "221").
What I'm trying to make happen is that the SelectedItem is updated to item which corresponds with the SelectedValue. So, in the end, if the individual has "221" for "Education" selected when the form is prepopulated they would see Education as the selected item and the selected value would be set correctly, whereas right now the form is showing the wrong SelectedItem but has the right SelectedValue behind the scenes.
Here is a more complete idea of the code flow from the Page_Load event:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack = False Then
' If prospect is coming from unique url
Dim prospect_url As String = Page.RouteData.Values("value")
' Save prospect_url into session variable
Session("prospect_url") = prospect_url
Using dbContext As IRFEntities = New IRFEntities
' Prepopulate the programs dropdown.
Dim getPrograms = (From p In dbContext.IRF_Program _
Order By p.name _
Select p)
ddlProgram.DataSource = getPrograms
ddlProgram.DataTextField = "name"
ddlProgram.DataValueField = "id"
ddlProgram.DataBind()
End Using
Using dbContext As IRFEntities = New IRFEntities
' Prepopulate the states dropdown.
Dim getStates = (From p In dbContext.IRF_States _
Order By p.name _
Select p)
ddlState.DataSource = getStates
ddlState.DataTextField = "name"
ddlState.DataValueField = "id"
ddlState.DataBind()
End Using
Using dbContext As IRFEntities = New IRFEntities
' Grab info. about prospect based on unique url.
Dim getProspect = (From p In dbContext.IRF_Prospects _
Where p.url = prospect_url _
Select p).FirstOrDefault
' If they have a record...
If getProspect IsNot Nothing Then
If getProspect.user_id Is Nothing Then
' Prepopulate the form with their information.
' These must have a value, so we need to make sure that no column is null in the database.
ddlProgram.SelectedValue = getProspect.program
txtFirst.Text = getProspect.first_name
txtLast.Text = getProspect.last_name
txtAddress.Text = getProspect.address
txtCity.Text = getProspect.city
ddlState.SelectedValue = getProspect.state
txtZip.Text = getProspect.zip
txtPhone.Text = getProspect.phone
txtEmail.Text = getProspect.email_address
txtYearEnrolling.Text = getProspect.enrolling_in
Else
' Redirect them to login.
Response.Redirect("login.aspx")
End If
End If
End Using
End If
End Sub
What you're doing looks like it should work. If you put a breakpoint after the setting of the value and check the SelectedItem text and value, do they appear as expected or mismatched?
Use the Immediate Window to check:
ddlProgram.SelectedItem.Text
ddlProgram.SelectedItem.Value
If they appear the same then I would presume the binding code is being refired and the list is being regenerated with the first item being selected.
To check this put a break point on the binding code and see if it is fired more than once and correct the order of the methods appropriately.
ADDED:
If it works on your local environment it should work when published, if the code is the same? Looking at your code, I'd start by seperating out some of the databinding code into seperate methods rather than have everything in Page_Load, one becuase it's good practice and two because it will make debugging easier. Further than that I'm not sure what else to suggest.

ASP CascadingDropDown Control Causes IE Script timeout

Before a page is loaded, I use a subroutine to link DropDownList controls together:
Private Sub CreateCascadingDropDown(ByVal category As String, ByRef parentDDL As DropDownList, ByRef targetDDL As DropDownList)
Dim CDDL As New CascadingDropDown
With CDDL
.Category = category
If Not parentDDL Is Nothing Then
parentDDL.Items.Clear()
.ParentControlID = parentDDL.ID
End If
targetDDL.Items.Clear()
.TargetControlID = targetDDL.ID
.PromptText = SharedWeb.GC_SELECTONE
.PromptValue = "-1"
.LoadingText = "Please wait..."
.ServicePath = "/ajax/InvestmentProcess.asmx"
.ServiceMethod = "GetTaxo"
End With
'Page.ClientScript.RegisterForEventValidation(CDDL.UniqueID)
targetDDL.Parent.Controls.Add(CDDL)
End Sub
When the web service method is called, it executes the following code. Based on the category, it gets the appropriate data from the adapter.
<WebMethod()> _
Public Function GetTaxo(ByVal knownCategoryValues As String, ByVal category As String) As CascadingDropDownNameValue()
Dim log As ILog = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)
log.Debug("GetSegmentTaxonomy(" + category + ") -> {" + knownCategoryValues + "}")
Dim kv As StringDictionary = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues)
Dim adapter As New SegmentTaxonomyTableAdapters.SEGMENT_ARCHITECTURE_TableAdapter
Dim rows As DataRowCollection
Select Case category
Case InvestmentEdit.ST_SEG_ARCH
rows = New SegmentTaxonomyTableAdapters.SEGMENT_ARCHITECTURE_TableAdapter().GetData().Rows
Case InvestmentEdit.ST_LOB
If kv.ContainsKey(InvestmentEdit.ST_SEG_ARCH) Then
log.Debug("found seg architecture - > " + kv(InvestmentEdit.ST_SEG_ARCH))
rows = New SegmentTaxonomyTableAdapters.LINE_OF_BUSINESSTableAdapter().GetData(kv(InvestmentEdit.ST_SEG_ARCH)).Rows
End If
End Select
If Not rows Is Nothing Then
Dim results As New List(Of CascadingDropDownNameValue)
For Each row As DataRow In rows
log.Debug("ROW >>>> " + row("lov_label").ToString() + " : " + row("lov_cd").ToString())
results.Add(New CascadingDropDownNameValue(row("lov_label"), row("lov_cd")))
Next
Return results.ToArray
End If
Return Nothing
End Function
There are about 5 drop downs I need to link together. The top-level drop down control (myDDL) loads fine if it is the only one linked like so:
CreateCascadingDropDown("MyCat",Nothing,myDDL)
But when I link a second drop down control, Internet Explorer gives a script timeout. If I keep allowing the script to run, it just keeps giving me the prompt. If elect to discontinue running the script, I get a Method Error 12031 or Error 500 (and yes, I have the ScriptService() declaration in my web service file). Any ideas on what's causing this?
It turns out I just needed to add the following control from the Ajax Control Toolkit:
<ajax:ToolkitScriptManager ID="tsm" runat="server" />
Instead of .TargetControlID = targetDDL.ID I needed to use:
.TargetControlID = targetDDL.UniqueId

Is it possible to do a linq query on a GridView (ASP.NET)?

Basically I have a datakey that I'd like to query from my GridView instead of looping through all the rows and comparing the key of each row. So I was wondering if it was possible to just do a linq query on the gridview (not datatable) and filter with the datakey.
Not sure how to use DataKeyNames directly, because Column doesn't have any information about data field name it's coming from. In the example below, I use SortExpression to get column index which is used for filtering.
EDIT: The most important part here is the casting, which enables you to use all the fancy extension methods designed for IEnumerable<T>.
int idColumnIndex = MyGrid.Columns.Cast<DataControlField>().Where(e => e.SortExpression == "ID").Select(e => MyGrid.Columns.IndexOf(e)).FirstOrDefault();
var row = MyGrid.Rows.Cast<GridViewRow>().Where(e => e.Cells[idColumnIndex].Text == "421").FirstOrDefault();
Everything is possible!
Gridview in itself is nothing. It's just a UI, the data is in its source be it a datatable or dataset and you can use linq to query them.
As far as I understand the theory of LINQ, it can be performed on any list. As a datasource in a gridview is in essence a list, you should be able to use LINQ on that datasource of the gridview.
Try this example:
http://weblogs.asp.net/scottgu/archive/2006/05/14/Using-LINQ-with-ASP.NET-_2800_Part-1_2900_.aspx
I did something similar to this with a repeater, and maybe it will help... or you can just disregard it if it doesn't. In my situation I databound the repeater and allowed users to modify the data before exporting it to XML. The following LINQ loops through each row in the repeater, uses findcontrol to grab the control from the datarow and then uses Linq to XML, but this could be used to generate objects using LINQ to Objects. rp is the repeater, cbIgnore is a checkbox which if the users checks it the row is not expored.
Dim doc As New XDocument( _
New XDeclaration("1.0", "ISO-8859-1", "true"), _
New XElement("Schedule_Import", _
From c As RepeaterItem In rp.Items _
Where (c.ItemType = ListItemType.Item Or c.ItemType = ListItemType.AlternatingItem) _
AndAlso DirectCast(c.FindControl("cbIgnore"), HtmlInputCheckBox).Checked = False _
Select New XElement("activity", _
New XElement("code", DirectCast(c.FindControl("txtAC"), TextBox).Text), _
New XElement("starttime", DirectCast(c.FindControl("dtfStart"), DateTimeField).SelectedDateTime), _
New XElement("endtime", DirectCast(c.FindControl("dtfEnd"), DateTimeField).SelectedDateTime), _
New XElement("description", DirectCast(c.FindControl("txtTitle"), TextBox).Text))))

How can I remove nodes from a SiteMapNodeCollection?

I've got a Repeater that lists all the web.sitemap child pages on an ASP.NET page. Its DataSource is a SiteMapNodeCollection. But, I don't want my registration form page to show up there.
Dim Children As SiteMapNodeCollection = SiteMap.CurrentNode.ChildNodes
'remove registration page from collection
For Each n As SiteMapNode In SiteMap.CurrentNode.ChildNodes
If n.Url = "/Registration.aspx" Then
Children.Remove(n)
End If
Next
RepeaterSubordinatePages.DataSource = Children
The SiteMapNodeCollection.Remove() method throws a
NotSupportedException: "Collection is read-only".
How can I remove the node from the collection before DataBinding the Repeater?
Your shouldn't need CType
Dim children = _
From n In SiteMap.CurrentNode.ChildNodes.Cast(Of SiteMapNode)() _
Where n.Url <> "/Registration.aspx" _
Select n
Using Linq and .Net 3.5:
//this will now be an enumeration, rather than a read only collection
Dim children = SiteMap.CurrentNode.ChildNodes.Where( _
Function (x) x.Url <> "/Registration.aspx" )
RepeaterSubordinatePages.DataSource = children
Without Linq, but using .Net 2:
Function IsShown( n as SiteMapNode ) as Boolean
Return n.Url <> "/Registration.aspx"
End Function
...
//get a generic list
Dim children as List(Of SiteMapNode) = _
New List(Of SiteMapNode) ( SiteMap.CurrentNode.ChildNodes )
//use the generic list's FindAll method
RepeaterSubordinatePages.DataSource = children.FindAll( IsShown )
Avoid removing items from collections as that's always slow. Unless you're going to be looping through multiple times you're better off filtering.
I got it to work with code below:
Dim children = From n In SiteMap.CurrentNode.ChildNodes _
Where CType(n, SiteMapNode).Url <> "/Registration.aspx" _
Select n
RepeaterSubordinatePages.DataSource = children
Is there a better way where I don't have to use the CType()?
Also, this sets children to a System.Collections.Generic.IEnumerable(Of Object). Is there a good way to get back something more strongly typed like a System.Collections.Generic.IEnumerable(Of System.Web.SiteMapNode) or even better a System.Web.SiteMapNodeCollection?

Resources