Index out of range, but why? - c#

I have a gridview, and I have a SelectedIndexChanged event on it...
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow Row = GridView1.SelectedRow;
//do some stuff
}
Then I get an error...
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
I do not understand why, the Gridview is being binded in pageload. but not in post back...
if (!IsPostBack)
{
GridView1.DataSource = UserAccounts;
GridView1.DataBind();
}

The asp.net DataSource controls handle this for you automatically but if you are manually binding your GridView, you will need to also bind it on PostBack. If you make changes to the data source based on filters, etc., you will need to rebind it.

The first thing: When post back to server, your GridView1 will re-initialize so that GridView1.DataSource will lost the previous data
if (!IsPostBack)
{
GridView1.DataSource = UserAccounts;
GridView1.DataBind();
}
The second thing: if you manually bind your GridView with your custom DataTable, List .... you must implement RowCommand with specific DataKey.
Please take a look at this article http://aspspirits.blogspot.com/2012/08/how-to-get-rowindex-of-aspnet-gridview.html

Related

How to add paging to GridView?

How do I add paging to this GridView?
C# code:
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
GridView1.DataBind();
}
Error
Specified argument was out of the range of valid values. Parameter name: index
You again you need to in page index changing event. Here you have not written that.
See the link
myGridView.DataSource = your datasource here;
myGridView.PageIndex = e.NewPageIndex;
myGridView.DataBind();
I think what I do is I write the page index code and then call the actrual bindmethod of the grid after that:
myGridView.PageIndex = e.NewPageIndex;
BindmyGridView();
where
private void BindmyGridView()
{
myGridView.DataSource = lst; //where lst is the datasource
myGridView.DataBind();
}
Also have you gone through these links:
Link 1
Link 2
Allow paging is very simple.Call PageIndexChanging event of grid view like
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
GridView1.DataSource = Your datasource here;
GridView1.DataBind();
}
Hope it works for you..
You need to use a pageable data source. The simplest way is to just use an SqlDataSource.
Also, note that PageIndex is zero-based.
If you're using a List or a Collection etc., it needs to be big enough, which is a nice waste of space. Basically, if you're doing manual paging, and you're using a List, you're going to have to create the List as big as the full record count of your result, and only fill in the proper page. Not very practical, and quite wasty, but it's simple enough.
Apart from creating your own pageable data source, there's also another, nicer way. You can use the AllowCustomPaging property to specify that you're already passing paged data. Just set VirtualItemCount to the record count, and pass just the one page in the DataSource and call DataBind as usual. That should do :)

GridView row values not changed after update

I want to update row in GridView with this code but after editing GridView not changes:
protected void res_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//Retrieve the table from the session object.
DataTable dt = (DataTable)Session["dt"];
GridViewRow row =res.Rows[e.RowIndex];
dt.Rows[row.DataItemIndex]["name"] = ((TextBox)(row.Cells[6].Controls[0])).Text;
dt.Rows[row.DataItemIndex]["dewey"] = ((TextBox)(row.Cells[5].Controls[0])).Text;
*dt.Rows[row.DataItemIndex]["subject"] = ((TextBox)(row.Cells[4].Controls[0])).Text;
Session["dt"] = dt;
res.EditIndex = -1;
res.DataSource = dt;
res.DataBind();
}
my Page_Load:
protected void Page_Load(object sender, EventArgs e)
{
DataTable dt;
if (!IsPostBack)
{
dt= Converter.ListBooks(new classes.Book().GetAll());
Session["dt"] = dt;
res.DataSource = dt;
res.DataBind();
}
else
{
dt=(DataTable)Session["dt"];
res.DataSource = dt;
res.DataBind();
}
}
for example I changed line that have * to this:
dt.Rows[row.DataItemIndex]["subject"] = "tx";
and after edit "subject" column changed to "tx", so I don't know why ((TextBox)(row.Cells[4].Controls[0])).Text return TextBox's text before edit?
Because you're calling DataBind(); method each time page refreshed (POST or GET), let me explain more if user put the new value in the TextBox and click on update button to trigger res_RowUpdating even Page_Load will fire and bind the Gird with database values which is the old values and neglect the user input value.
I think, you just need to rebind the grid
Remove the else part in your page_load.
Should do it for you.
You are binding the Grid every time there is a postback which is not required.
Maybe changes are done but the form is not being updated.
Try putting gridview control inside an Update Panel Control and call UpdatePanel.Update().
When you work with a web control, what you see can be different from what actually is because changes in data are not autoupdated in the presentation layer.
To solve this "problem" you can make a postback (retrieving everything) of the whole page, but this is like killing a fly with a bazooka because you do not need everything, just what has been updated, so for this purpose there are several tool that allow you to make partial updates, for example the AJAX control: UpdatePanel.
Hope it helps.
Update: Call the AcceptChanges() method on the DataTable and erase the else branch on the Page_Load after if(!PostBack)
Call the AcceptChanges() method of the DataTable and then bind the GridView.

Nesting Repeater in Gridview: Hiding gridview row and repeater header if data is not there in repeater

I have nested a repeater control in Gridview. Right now it is showing gridview rows and repeater header for every case(whether data is there or not for that particular grid view row in the repeater control). I want to hide the gridview row and repeater control header when there is no data present for that particular gridview row.
Thanks,
That case I handled at code level by filtering the resulted data table.
Now the another problem I am facing:
I have allowed the paging on the gridview i.e. pagesize 3.
When page loads it works fine, but when I go to page 2 then it generates following error:
Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index
Below is the code to fill the grid, paging and fill repeater on rowdatabound event of grid.
private void FillGrid()
{
clsCustomFunctions objShort = new clsCustomFunctions();
grd1.DataSource = objShort.GetAll();
}
protected void grd1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
try
{
FillGrid();
grd1.PageIndex = e.NewPageIndex;
grd1.DataBind();
}
catch (Exception ex)
{
lblMsg.Text = ex.Message;
}
}
protected void grd1_RowDataBound(object sender, GridViewRowEventArgs e)
{
clsCustomFunctions objShort = new clsCustomFunctions();
if (e.Row.RowType == DataControlRowType.DataRow)
{
((HtmlTable)e.Row.FindControl("gridTable")).BgColor = "#006699";
Repeater rpt = (Repeater)e.Row.FindControl("rpt1");
rpt.DataSource = objShort.GetResult(Convert.ToInt32(grd1.DataKeys[e.Row.DataItemIndex].Value));
rpt.DataBind();
}
}
grd1.DataKeys[e.Row.DataItemIndex].Value line is throwing error. How to handle this to pass values of page 2 only.
Try handling the OnRowDataBound event of the grid. This gives you a GridViewRowEventArgs object (say e).
You can then look at e.Row.DataItem to get the data it is binding to to check if you need to hide the header.
You can use e.Row.FindControl("RepeaterName") to get the repeater to manipulate as you want.

gridview paging using dataset

I have an ASP.NET web app (C#) where I get some information from a datasource and display it in the the gridview. I wanted to enable paging, but for some reason, paging doesn't work. I researched a little online, and I found that paging is done differently if a dataset is used. When I click on a page number, it refreshes, and says that there are no records to display. I call this function in the click function of a button:
bindGrid(cmd);
Here's my bind method:
private void bindGrid(OracleCommand comm)
{
OracleDataAdapter adapter = new OracleDataAdapter(comm);
DataSet ds = new DataSet();
ds.Tables.Add("Results");
adapter.Fill(ds.Tables["Results"]);
grd.DataSource = ds;
grd.DataBind();
}
Paging Method:
protected void grdResults_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
grd.PageIndex = e.NewPageIndex;
grd.DataBind();
}
How am I supposed to do paging with a dataset? Can someone help please?
You also need to fetch the data :)
So instead of this:
protected void grdResults_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
grd.PageIndex = e.NewPageIndex;
grd.DataBind();
}
you should use:
protected void grdResults_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
grd.PageIndex = e.NewPageIndex;
//Create command
bindGrid(comm);
}
Instead of grd.DataBind() in your paging method call bindGrid(). Or better use some built-in 'business objects' for data binding like ObjectDataSource
The simplest way to do paging is to set AllowPaging="yes" in your GridView, and don't do anything in the code-behind. The GridView will page through its dataset on its own. Do NOT rebind.
That's fine for small datasets, but not so good for a phone book. As Tadas said, ObjectDataSource is the way to go for handling paging yourself, on server side. With ObjectDataSource, you won't DataBind at all; the controls handle that. However, you do need to supply a Select method (usually static) on an object, and it needs to have parameters for first row and page size (set these as attributes on the ObjectDataSource). You will allso need to implement a Count method to return the full dataset size; otherwise paging won't work. Using an ObjectDataSource this way, you shift the burding of paging to your data layer, and the page will load much faster.

GridView paging inside an UpdatePanel or PlaceHolder components

I'm new to ASP.NET.
Im developing ASP.NET C# web form which creating GridView components dynamically and filling them using the data received from my webservice.
I'm creating these GridView components programmatically in server-side (cs file)- it has to be flexible - 1 GridView and sometimes 10 GridView components.
The problem occurs when I'm trying to add pagination - whenever the user clicks the "next" page, the whole page is getting refreshed because of a postBack and I'm loosing all my data and the page returns Blank/Empty.
I used PlaceHolder to hold the GridView components, while searching for a solution, I found UpdatePanel as a better alternative - as far as I understand the page can be partially refreshed - which means that only the UpdatePanel has to be refreshed...but it doesn't work.
The following code sample is my TEST, the UpdatePanel is the only component initiated in the client side (.aspx page), the rest initiated programmatically in .cs .
how can I solve the issue described above?
Why does the whole page is getting refreshed and I'm loosing my data?
can you recommend another way? can provide me with any code sample?
If I'm not rebuilding the GridView, it doesn't work...
Here is my Default.aspx.cs
public partial class TestAjaxForm : System.Web.UI.Page
{
DataTable table;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
bindGridView();
}
public void bindGridView()
{
GridView gridView1 = new GridView();
gridView1.AutoGenerateColumns = true;
gridView1.PageSize = 2;
gridView1.AllowPaging = true;
gridView1.PagerSettings.Mode = PagerButtons.Numeric;
gridView1.PagerSettings.Position = PagerPosition.Bottom;
gridView1.PagerSettings.PageButtonCount = 10;
gridView1.PageIndexChanging += new GridViewPageEventHandler(this.GridView1_PageIndexChanging);
table = new DataTable();
table.Columns.Add("FirstName");
table.Columns.Add("LastName");
DataRow row = table.NewRow();
row["FirstName"] = "John";
row["LastName"] = "Johnoson";
table.Rows.Add(row);
row = table.NewRow();
row["FirstName"] = "Johnny";
row["LastName"] = "Marley";
table.Rows.Add(row);
row = table.NewRow();
row["FirstName"] = "Kate";
row["LastName"] = "Li";
table.Rows.Add(row);
panel.ContentTemplateContainer.Controls.Add(gridView1);
gridView1.DataSource = table;
gridView1.DataBind();
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView gridView1 = (GridView)sender;
gridView1.PageIndex = e.NewPageIndex;
gridView1.DataSource = table;
gridView1.DataBind();
}
}
Thank you.
If you want a custom GridView approach to work, you have to recreate and rebind the grid on every page load... that's the problem with dynamic Grids... Dynamic controls don't retain their viewstate, but if you added the grid and dynamically generated the columns, that would work easier for you (because I think it may dynamically remember the columns, or you can set AutoGenerateColumns to true, and it brings in your data row column names).
HTH
You should create your GridView and add it to the control tree in the PreInit or Init event handler so that they have a chance to properly bind to ViewState, and it should be done whether or not there's a postback: if you don't add them in a postback, they obviously won't be there to display anything.
DataBinding can happen later in the page life cycle.
Paging only seems to work if you also use an ObjectDataSource; I've never been able to get it to work with a GridView by itself.
I think the easiest thing to do is have the gridview declared in the aspx page inside the place holder, while the place holder is also contained inside the update panel.
For what I can see, John is not doing anything that can't be declared in the markup itself so that shouldn't be a problem. If for some reason the gridview should not be displayed on the screen, it suffices to set the Visible property of the placeholder to false.
As far as paging is concerned, as RickNz correctly points out, it will only retain the state if you bind the gridview to either a LinqDatasource, SqlDatasource or ObjectDatasource but if you bind it to custom business objects, what you need to do is save the data in Session and rebind it again on PageIndexChanged.
In pseudo code, would be sometging like this.
Page_load
{
If (!IsPostBack)
Binddata();
}
private void Binddata()
{
var data = Getdata();
Gridview1.DataSource= data;
Gridview.DataBind();
Session["data"]=data; // cache the data
}
protected void Gridview1_indexchanged(object sender, GridviewPageEventArgs e)
{
var data= Session["data"];
Gridview1. DataSource=data;
Gridview1.DataBind();
GridView1.PageIndex=e.NewPageIndex;
}

Categories

Resources