I have I gridview in which the data source is a List<T>. When I try to remove an item from the gridview in my buttonRemove_Click() function another function which handles the RowDeleting event is invoked where I remove the item from the List<T> as well. The problem is that if I select to remove multiple items from the gridview the index of the gridview and that of my List<T> un-syncs. For example I have 10 items in my gridview and in my List and I try to remove the last two items. Here is how I do it in my buttonRemove_Click function
foreach (GridViewRow row in gridViewItems.Rows)
{
CheckBox cb = (CheckBox)row.FindControl("checkBox");
if (cb != null && cb.Checked)
{
gridViewItems.DeleteRow(row.DataItemIndex);
}
}
Then in the RowDeleting function, I'll first receive the event for the index 8, I removed it. Now when it comes to deleting the last item (index 9), then it'll throw exception because the index is out of range. How do I solve this problem?
I think the problem will be solved if I try removing the rows in reverse order i.e. starting from the highest index. Can anyone tell how can this be done?
GVGLCode1.DataSource = dt;
GVGLCode1.DataBind();
int iCount = GVGLCode1.Rows.Count;
for (int i = 0; i <= iCount; i++)
{
CheckBox cb = (CheckBox)GVGLCode1.rows[i].FindControl("checkBox");
if (cb != null && cb.Checked)
{
GVGLCode1.DeleteRow(i);
}
}
Please try with this.
May be it can help u.
Related
I have this code which works fine as long as as dt.Value is different to "int".
This is the line which errors:
(dt.Value.ToLower().Substring(0, 4).Equals("date"))
It works fine if dt.Value is varchar or datetime.
I provided my suggested solution at the end of this post.
// Edit
if (e.CommandName == "Edit")
{
// Get the item
RepeaterItem Item = ((RepeaterItem)((Button)e.CommandSource).NamingContainer);
// Get buttons and repeater
Button savebtn = (Button)(Item.FindControl("btnSave"));
Button editbtn = (Button)(Item.FindControl("btnEdit"));
Repeater rFields = (Repeater)(Item.FindControl("repFields"));
// Enable my fields
foreach (RepeaterItem RI in rFields.Items)
{
// Get data type
HiddenField dt = (HiddenField)(RI.FindControl("hdnDBDataType"));
// Set controls
if (RI.FindControl("chkSetting").Visible) ((CheckBox)RI.FindControl("chkSetting")).Enabled = true;
if (RI.FindControl("ddlSetting").Visible) ((DropDownList)RI.FindControl("ddlSetting")).Enabled = true;
if (RI.FindControl("txtSetting").Visible)
{
((TextBox)RI.FindControl("txtSetting")).Enabled = true;
// Check my data type
if (dt.Value.ToLower().Substring(0, 4).Equals("date")) ((CalendarExtender)RI.FindControl("extDateTime")).Enabled = true;
}
}
}
Is this a good fix ? TIA
if(dt.Value != "int" && dt.Value.ToLower().Substring(0, 4).Equals("date"))
Substring will throw an error if the second parameter is higher than the lenght of the string. What you need to do is check the length before doing the substring or use a method like #Igor suggested in the comments.
Your suggestion to check != "int" is not fullproof if let's say somehow the value is any string less than 4 characters.
(dt.Value.Length > 3 && dt.Value.ToLower().Substring(0, 4).Equals("date"))
I will also put #Igor suggestion here because it is also fullproof:
(dt.Value.StartsWith("date", StringComparison.OrdinalIgnoreCase)
I have gridview that contains check boxes in one of the columns, then there is a "Select ALl" button which when clicked has to check top 100 CBs on the list, the client specifically stated they do not want pagination, it much easier to do this with pagination and display only 100 records per page then when the select all button is clicked everything on the given page gets selected however this is not what the client wants
Here is my code:
foreach (GridViewRow row in dgridTransactions.Rows)
{
for (int x = 0; x <=100;x++ )
{
var oneTransaction = (CheckBox)row.FindControl("chkAssigned");
oneTransaction.Checked = true;
}
}
If you want to run first hundred rows you only need this loop
for(int x = 0; x < 100; x++)
{
GridViewRow row = dgridTransactions.Rows[x];
// then manage row properties
CheckBox cb = (CheckBox)row.FindControl("chkAssigned");
cb.Checked = true;
}
using RowIndex you can keep track of row number.
foreach (GridViewRow row in dgridTransactions.Rows)
{
if(row.RowIndex<100 )
{
var oneTransaction = (CheckBox)row.FindControl("chkAssigned");
oneTransaction.Checked = true;
}
else
break;
}
There is issue in your code
You can use the below code
int x=0;
foreach (GridViewRow row in dgridTransactions.Rows)
{
if(x<100 )
{
var oneTransaction = (CheckBox)row.FindControl("chkAssigned");
oneTransaction.Checked = true;
}
else
break;
x++;
}
The foreach (GridViewRow row in dgridTransactions.Rows) loop runs for each row in your grid.
and in that you are using for (int x = 0; x <=100;x++ ){ which runs 100 times for every row.
You can use jquery or javascript for this Here is a JSFiddle which can help you
How about:
foreach (GridViewRow row in dgridTransactions.Rows.Cast<GridViewRow>().Take(100)) {
CheckBox cb = row.FindControl("chkAssigned") as CheckBox;
if (cb != null)
cb.Checked = true;
}
This will give the first items up to 100, so if you only have 90, it will give 90.
The diferent way of casting will also give you an additional security measure in case it fails to find the control. A direct cast will just throw an exception, which is always heavier then checking if the castes object is not null...
If you dont care about the cast verification, you can just inline everything into this:
dgridTransactions.Rows.Cast<GridViewRow>().Take(100).ToList().ForEach(x => ((CheckBox)x.FindControl()).Checked = true);
protected void inderGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
//grdTotal = grdTotal + rowTotal;
grdTotal += rowTotal;
}
if (e.Row.RowType == DataControlRowType.Footer)
{
Label lbl = (Label)e.Row.FindControl("lblTotal");
e.Row.Cells[3].Text = grdTotal.ToString("c");
//lbl.Text = grdTotal.ToString("c");
}
}
from the above code i m getting total for every page in the grid view. Instead of getting total to every page i need all page total at the end of the grid view footer. Help Immediatly.
Thanks in advance
If you want the total of ALL pages, and for the footer to only appear on the last page, then you can't calculate the totals how you are doing.
At the moment your looping through every row on the gridview. If you are using paging the gridview won't be showing all the rows, so the total won't be correct.
Are you paging with a PagedDataSource or are you limiting the records returned from SQL etc? If you are using a DataSet and a PagedDataSource you'll be able to find the total from the DataSet (as this will contain all the records). Otherwise, you'll have to create a second query to calculate the total.
Then in terms of displaying the values in the footer, you'll have to add an IF statement to your ItemDataBound event to only display this if its the final page.
If you trying to display the record summery, please look this one about Displaying Summary Information in the GridView's Footer
What I do is setup the following in the code behind (This is just an example column):
int totalCallsTaken = 0;
public int CallsTaken(int value)
{
totalCallsTaken += value;
return value;
}
public int CallsTakenTotal()
{
return totalCallsTaken;
}
Then in the ASPX page I put the following template field in:
<asp:TemplateField HeaderText="Calls Taken" FooterStyle-Font-Bold="true">
<ItemTemplate>
<%#CallsTaken(Convert.ToInt32(Eval("CallsTakenCount").ToString())).ToString("N0")%>
</ItemTemplate>
<FooterTemplate>
<%#CallsTakenTotal().ToString("N0")%>
</FooterTemplate>
</asp:TemplateField>
I hope that helps, Ian.
Noddy but you can try one more check in the if condition.
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
//code here.
}
// Try this
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
for (int i=0; i< inderGrid.Rows.Count; i++)
{
var currentRowCellVal = Convert.ToDecimal(inderGrid.Rows[i].Cells[0].Text);
grdTotal += currentRowCellVal;
}
e.Row.Cells[3].Text = grdTotal.ToString("c");
}
Just to be certain I'm understanding, you're saying you have a grid with say 100 items, but only 25 are shown at any given time. Then you want the footer to only display the sum of those 25 items that are displayed on the page.
There's a couple of options that you can do here for this:
1) Use JavaScript to calculate the total after the page has been rendered.
2) use intelligent SQL to only return those particular rows that you're wanting to display on the grid--and then keep your grid the same
3) calculate the visible rows in your code, and only add them when you need them. Remember, you know in the code behind which Grid.PageIndex you're on as well as how many items each page has. With this knowledge, you should be able to determine via the row index if any given datarow will be rendered to the screen.
You need to generate all records total using the actual data.
If you are doing paging at the data-sire (database) side then you have total at the data-sore side - you may use the same SP that returns a page-full of records to return the total of all records. If you are retrieving all records and doing paging at the web server side then you may use the retrieve data-source to do the totaling.
From optimization perspective, you can compute the total once and store it in the view-state.
If you wish to show the footer on the last row then you can use ShowFooter - set it to true only on the last page.
All you need to do is check whether your row is in the current page and do the calculation.
For example, something like this:
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
if (e.Row.DataItemIndex >= inderGrid.PageIndex * inderGrid.PageSize
&& e.Row.DataItemIndex < inderGrid.PageIndex * inderGrid.PageSize + inderGrid.PageSize)
grdTotal += rowTotal;
}
Try this,
using System.Linq;
dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString();
you can use the code like this for get sum at the footer
gv.DataSource = dt;
gv.Columns[2].FooterText = dt.Rows.Count > 0 ? dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString() : "";
gv.DataBind();
protected void inderGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
//grdTotal = grdTotal + rowTotal;
grdTotal += rowTotal;
}
if (e.Row.RowType == DataControlRowType.Footer)
{
Label lbl = (Label)e.Row.FindControl("lblTotal");
e.Row.Cells[3].Text = grdTotal.ToString("c");
//lbl.Text = grdTotal.ToString("c");
}
}
from the above code i m getting total for every page in the grid view. Instead of getting total to every page i need all page total at the end of the grid view footer. Help Immediatly.
Thanks in advance
If you want the total of ALL pages, and for the footer to only appear on the last page, then you can't calculate the totals how you are doing.
At the moment your looping through every row on the gridview. If you are using paging the gridview won't be showing all the rows, so the total won't be correct.
Are you paging with a PagedDataSource or are you limiting the records returned from SQL etc? If you are using a DataSet and a PagedDataSource you'll be able to find the total from the DataSet (as this will contain all the records). Otherwise, you'll have to create a second query to calculate the total.
Then in terms of displaying the values in the footer, you'll have to add an IF statement to your ItemDataBound event to only display this if its the final page.
If you trying to display the record summery, please look this one about Displaying Summary Information in the GridView's Footer
What I do is setup the following in the code behind (This is just an example column):
int totalCallsTaken = 0;
public int CallsTaken(int value)
{
totalCallsTaken += value;
return value;
}
public int CallsTakenTotal()
{
return totalCallsTaken;
}
Then in the ASPX page I put the following template field in:
<asp:TemplateField HeaderText="Calls Taken" FooterStyle-Font-Bold="true">
<ItemTemplate>
<%#CallsTaken(Convert.ToInt32(Eval("CallsTakenCount").ToString())).ToString("N0")%>
</ItemTemplate>
<FooterTemplate>
<%#CallsTakenTotal().ToString("N0")%>
</FooterTemplate>
</asp:TemplateField>
I hope that helps, Ian.
Noddy but you can try one more check in the if condition.
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
//code here.
}
// Try this
if(e.Row.RowType == DataControlRowType.Footer && inderGrid.PageCount == inderGrid.PageIndex + 1)
{
for (int i=0; i< inderGrid.Rows.Count; i++)
{
var currentRowCellVal = Convert.ToDecimal(inderGrid.Rows[i].Cells[0].Text);
grdTotal += currentRowCellVal;
}
e.Row.Cells[3].Text = grdTotal.ToString("c");
}
Just to be certain I'm understanding, you're saying you have a grid with say 100 items, but only 25 are shown at any given time. Then you want the footer to only display the sum of those 25 items that are displayed on the page.
There's a couple of options that you can do here for this:
1) Use JavaScript to calculate the total after the page has been rendered.
2) use intelligent SQL to only return those particular rows that you're wanting to display on the grid--and then keep your grid the same
3) calculate the visible rows in your code, and only add them when you need them. Remember, you know in the code behind which Grid.PageIndex you're on as well as how many items each page has. With this knowledge, you should be able to determine via the row index if any given datarow will be rendered to the screen.
You need to generate all records total using the actual data.
If you are doing paging at the data-sire (database) side then you have total at the data-sore side - you may use the same SP that returns a page-full of records to return the total of all records. If you are retrieving all records and doing paging at the web server side then you may use the retrieve data-source to do the totaling.
From optimization perspective, you can compute the total once and store it in the view-state.
If you wish to show the footer on the last row then you can use ShowFooter - set it to true only on the last page.
All you need to do is check whether your row is in the current page and do the calculation.
For example, something like this:
if (e.Row.RowType == DataControlRowType.DataRow)
{
decimal rowTotal = Convert.ToDecimal
(DataBinder.Eval(e.Row.DataItem, "DC_No_Decimal"));
if (e.Row.DataItemIndex >= inderGrid.PageIndex * inderGrid.PageSize
&& e.Row.DataItemIndex < inderGrid.PageIndex * inderGrid.PageSize + inderGrid.PageSize)
grdTotal += rowTotal;
}
Try this,
using System.Linq;
dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString();
you can use the code like this for get sum at the footer
gv.DataSource = dt;
gv.Columns[2].FooterText = dt.Rows.Count > 0 ? dt.AsEnumerable().Select(x => x.Field<decimal>("DC_No_Decimal")).Sum().ToString() : "";
gv.DataBind();
I have a DataView that was already populated with data (Verified this to be true).
I then set the DataSource of my GridView to that DataView and called the .DataBind() Function.
Right after binding, I checked the column count of my GridView (grid.Columns.Count) and it shows 0. But it is showing the right output with 15 columns.
Also, accessing a column using its index will throw an exception.
How can I access the column then?
Thanks!
EDIT -- Additional Info:
I actually need to add a "glyph" (UP/DOWN arrow) in the column header to show what column are being sorted and its direction. The code below is what I am using. Problem is, the Columns.Count is always zero.
for (int i = 0; i < dgData.Columns.Count; i++)
{
string colExpr = dgData.Columns[i].SortExpression;
if (colExpr != "" && colExpr == dgData.SortExpression)
item.Cells[i].Controls.Add(glyph);
}
Edit
Try this, it's a little fugly as it relies on testing the linkbutton text against the GridView SortExpression. The Gridview ID is "test"
protected void test_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
foreach (TableCell tc in e.Row.Cells)
{
if(test.SortExpression.Contains( (tc.Controls[0] as LinkButton).Text ))
tc.Controls.Add( glyph )
}
}
}
I don't think the columns collection is set if you are auto generating the columns...
You could check the Row.Cells.Count or if you need column names, grab the HeaderRow, and iterate through the Cells & grab their .Text Value.
If the GridView is sortable (e.g. has clickable links in the header, then to get the column names you'll need to check
foreach(Row r in GridView.Rows)
{
if(r.RowType == HeaderRow)
{
r.Cells[0].Controls[0]; //Link Control is here.
}
}