gridview with footer row total in the final page of the grid - asp.net

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();

Related

Depending source for drop down list

I have one drop down list in my pages that its source comes of below code. Now I like to put 1 text box adjusted on my drop down list and when I type on that, source of drop down list (DocumentNo) depend on what I type in the text box and when text box is null drop downs list shows all the (DocumentNo) , please help how I have to change my code,
protected void ddlProjectDocument_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var query = from p in _DataContext.tblDocuments
orderby p.DocumentNo
select p;
int maxs = 0;
foreach (tblDocument v in query)
{
if (v.DocumentNo.Length > maxs)
maxs = v.DocumentNo.Length;
}
foreach (tblDocument vv in query)
{
string doctitle = vv.DocumentNo;
for (int i = vv.DocumentNo.Length; i < maxs; i++)
{
doctitle += " ";
}
doctitle += " | ";
doctitle += vv.TITLE;
// Use HtmlDecode to correctly show the spaces
doctitle = HttpUtility.HtmlDecode(doctitle);
ddlProjectDocument.Items.Add(new ListItem(doctitle, vv.DocId.ToString()));
}
}
First, I would highly recommend storing the result of that query at the beginning of the method into something like a session variable so that you don't have to continually query the database every time you hit this page.
Second, you should use the OnTextChanged event in ASP.NET to solve this problem. Put in the OnTextChanged attribute to point to a method in your code behind that will grab the query result values (now found in your session variable) and will reset what is contained in ddlProjectDocument.Items to anything that matched what was being written by using String.StartsWith():
var newListOfThings = queryResults.Where(q => q.DocumentNo.StartsWith(MyTextBox.Value));
At this point all you need to do is do that same loop that you did at the end of the method above to introduce the correct formatting.

grid View footer total in asp.net [duplicate]

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();

Insert a control before another control inside a ItemDataBound event

I tried to Solution suggested here, but it didn't work in my case. using Page.Controls.IndexOf() for any of the elements on my page, when called in the ItemDataBound event method, returns -1.
I need to insert a linebreak based on certain conditions for stuff generated by my Data repeater. Here is the method:
private String lastCharacter = "";
public void users_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
HyperLink link = (HyperLink)e.Item.FindControl("micrositeLink");
Tuple<String, String> user = (Tuple<String, String>)e.Item.DataItem;
link.NavigateUrl = "/" + user.Item1;
link.Text = user.Item2;
// makes a break in the data when going from one bunch of data to another.
if (user.Item1.Length >= 2)
{
if (lastCharacter == "")
lastCharacter = user.Item1[1].ToString().ToLower();
else if (lastCharacter != user.Item1[1].ToString().ToLower())
{
HtmlGenericControl lineBreak = new HtmlGenericControl("br");
if (Page.Controls.IndexOf(link) >= 0)
Page.Controls.AddAt(Page.Controls.IndexOf(link), lineBreak);
lastCharacter = user.Item1[1].ToString().ToLower();
}
}
}
The bound data is a list of users in my system with names beginning with a particular letter. My goal is to further sub-divide this data with a line break between groups of data that have the same second letter. For instance:
AaPerson Aarad AaStuff
Aathing
AbItem AbStuff
Acan Achandle
To me, inserting a line break before the elements where the second letter changes is the obvious solution, but other suggestions are also appreciated.
Try using e.Item.Controls.IndexOf instead:
if (e.Item.Controls.IndexOf(link) >= 0)
e.Item.Controls.AddAt(e.Item.Controls.IndexOf(link), lineBreak);

Gridview remove items

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.

GridView no column present even after 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.
}
}

Resources