In a Sharepoint web part, I have a DataGrid with paging that I load with all of the data (not using custom paging - custom paging would require a significant overhaul in the current process and is probably one of the last options I can try). I was wondering if it was possible to have it page through the data without re-binding the data source to the grid in the page index changed event? If I remove my current calls to re-bind the data, it remains on the first page no matter what.
With a datagrid, I think you need to re-bind the grid whenever you want to go to a new page.
"A typical handler for the PageIndexChanged event sets the CurrentPageIndex property to the index of the page you want to display and then uses the DataBind method to bind the data to the DataGrid control."
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.datagrid.onpageindexchanged(VS.71).aspx
If you want to avoid querying/fetching the data over again from the source, then you'll need to "cache" the data between postbacks. There are various options here, each with it's own advantages and drawbacks.
If the size of the data is not too large and is not sensitive, you can simply put the data in viewstate on the first page load, and read it out again when the page index is changed. Another option might include using Session to "cache" the data, although this can get tricky if not done right, and of course there will be more load on the server side with this method (with varying amounts, depending on if the Session is In-Proc, State Server, or Database). There may be other methods to "cache" the data, but that is what you'd need to do in this case.
Related
ASP.net webforms here, if I set AllowPaging=true and implement my own paging mechanism where I am fetching say 25 records at a time. I'd like to be able to use the default gridview pager, but it seems to be having trouble setting the number of pages. Is this an internal calculation where the ENTIRE dataset has to be binded for it to determine this calculation?
For instance, assume a query has 1000 rows and I want to only fetch 25 of them at a time. Does the gridview pager need to execute the 1000 rows as its datasource in order to get the correct number of pages (buttons) to display. I cant find a property allowing me to specify the number of pages, they all seem to be read only (get methods).
I want to avoid building my own pager...
The Effective Paging with GridView Control in ASP.NET Article describes how to implement the pagination where your gridview requests the data only for the page that is visible.
Don't be put off by the fact that the database query is executed twice. Once for the total count and another to get the page's data. For applications with high traffic or a lot of data, this approach is still more efficient than getting everything, loading into a gridview (and the view state!), sending it to the end user, and the browser loading it on the screen :).
That's where virtual paging comes in.
Set AllowCustomPaging to true.
In PageIndexChanging event, set VirtualItemCount and PageIndex to the proper value.
Put only the 25 rows in the DataSource, do a DataBind as usual, you're done.
I am creating a custom control extending WebControl. This web control allows the consumer to define a collection of columns in markup, something like this:
<Custom:CustomGrid>
<Columns>
<Custom:DataColumn HeaderText="FirstName" />
<Custom:DataColumn HeaderText="LastName" />
</Columns>
and put an IEnumerable in a DataSource property and this is rendered out to a table.
This control also allows paging. The IEnumerable in DataSource is the full list, and I display a page of the list at a time. I am already saving the current page, number of rows per page, etc. to viewstate. Should I also put the full list in viewstate? Maybe session?
This list can become a bit hefty. Maybe save in session with a random key, which is saved in viewstate?
What is the best practice here?
Edit: I don't think it's right to impose that all types in the IEnumerable be serializable. Is that fair? So do I need to copy the data source to some other data structure for serialization?
Edit 2: Even if I do use a base control instead of implementing RenderChildControls I will need to implement CreateChildControls, but I will still need to persist the data somewhere, or did I miss the point of the base class?
Indeed, not all IEnumerable instances will be serializable.
If the query is cheap to run I wouldn't persist the whole data set but just run the query again for a different page or a change in the sort order.
If you put the data in viewstate you'll end up with huge pages. Session state might be acceptable if you don't have many users, but large data sets with lots of users won't scale well. What if I bind a million rows to your control? Or what if your control was used in a repeater and shown 100 times on a page?
Are you sure you need to persist the data? This isn't premature optimisation is it?
Remember that your control is a UI component. The viewstate should hold enough information to maintain the UI state as it is. A change in state (e.g.: switching to a different page of results) is something for which your control should pass responsibility to the data source.
Take a look at good old GridView. It displays what you give it and remembers that. If you're using paging then it raises an event to say "the user has changed page; give me page x of data". For me, that's the best practice for a UI control.
For implementing databound control it is better to use base class which was designed to perform such task. For example in ASP.NET exist CompositeDataboundControl which can be used as a base class to implement custom data bound controls. I can advice to review the following Dino Esposito article:
http://msdn.microsoft.com/en-us/library/aa479016.aspx.
Basically if you create control like ASP.NET gridview then it is store values in viewstate. To be more clear it is create number of the DataRow controls which saved assigned values in viewstate. During postback it recreates the same number of rows and values are restored from viewstate. If you will save only datasource for example in session without using viewstate then you will need to redatabind data to your grid during every postback. So, if you create Server control similar to gridview then approach described in the Dino Esposito post will be very helpful because it shows how to create control similar to ASP.NET Server GridView control.
I have a gridview on my page that gets bound to user search results. There can be many pages upto say 1000. Each page shows 50 records. I have the built in paging turned on for the grid. I want to disable the viewstate on the grid but then I have to bind the results on every page load. (bind twice on paging). The search takes a few seconds and I would not want to store the results in the session. So, how do I achieve turning off the viewstate for the grid or is it okay to have it enabled?
This must be a very common scenario. I hope there is a standard way of doing this.
Depending on how you bind the grid view you should implement server side paging so that your only bringing back the data from the server you need to display for one page.
What data access are you using i.e. are you using linq to sql?
Heres an article on how to do it with ObjectDataSource Custom paging and sorting
Avoid where ever possible putting large amounts of info into view state as it will bloat your page and effect performance.
i have a form that is generated dynamically.
the plan is to generate it, the user to enter data, and then to save all that lot away.
although a slight variation to this is if the form has previous data associated with it, and then it loads in all pre-populated. - the user may then change any previous selections.
and that is the rub really, i know if i call generateform regardless of postback the viewstate should take over and remember what the settings weer.. but as the generateform method as mentioned above populates the form if the form has previously been saved. which will win, the viewstate or the generateform method for the field populations.. ?
thanks
nat
If you dynamically generate any form controls that post data or cause a postback, you need to recreate them again on postback in order for them to be bound to their data, or their events, after the postback. Conceptually, this makes sense. If you don't have a control in your form after the postback, how could you look at its contents?
There are several ways you could approach this problem.
1) Call GenerateForm() no matter what. Since you said it pre-populates some of the data, you would need to change it so it can be called without doing that. ASP.NET will populate the controls with the data posted automatically on postback, which is what you want.
2) Keep a list of all your dynamically generated controls in a ViewState variable, so you can re-generate them upon postback. For most situations involving dynamically-created controls that aren't very simple (e.g., you may not know in advance exactly what controls are generated), this is the best solution. And often you will want to be able to access the data after a postback, but maybe you really don't want to recreate the whole form because you aren't using it any more.
As long as you recreate a control of the same type and ID on or before Page_Load(), it will be bound to the posted data. It does not need to be in exactly the same place on your form. And it does not need to be used or displayed, either - you can destroy it before the form is rendered, e.g., in Page_PreRender()
3) If you have no interest in any of this, you can always use Request.Form to look directly at the posted data, though this can also be tricky because the names will likely not match your form control IDs exactly. ASP.NET generates unique client-side IDs that depend on the container, and this is what you'll find in Request.Form. If you don't regenerate a control, you may not be able to easily determine the ID that you are looking for. Generally, you should not do this, but it's a way to look at the posted data and sometimes you need it.
I've a grid view, with IList as a datasource. I've thousands of records and so I've used pagination. The grid view will display only 10 records per page. My question is, how to avoid the grid view making DB calls again to the server when I click the 2nd page. Since I load all the data in a collection(IList), I need to iterate within the IList to bind data to the grid view when the next page is clicked. How can I accomplish this ? Help appreciated.
As you mentioned you have thousands of records I prefer you stay on database calls, you can reduce response time by bringing data in chunks like if you are showing 10 rows in grid view only bring 10 rows from the database. You can write a stored procedure where you can specify page size, start position, search criteria as parameters and change as per your need.
If you don't want to hit the database between postbacks during pagination, you need to store the list in memory somehow, perhaps using the Session property of the page, and then bind to that list. If the list can grow large (you mention thousands of records) I would recommend you to consider going via the database anyway, since that will preserve server memory.