Calculated cells in Telerik RadGrid's GridGroupFooterItem - asp.net

I'm populating a Telerik RadGrid with data from a DataTable (System.Data.DataTable). As I'm supporting someone else's application, I can't use any other data source or display control.
In my grid I have three columns: let's say they are Widgets Produced (column A), Faulty Widgets (column B) and Faultiness Proportion (column C). The database query provides these for me and does the calculation C = B / A.
I have a totals row (a Telerik GridFooterItem) at the bottom of the grid. In columns A and B Telerik calculates the totals for those columns for me. We can't calculate the correct value for the 'total' of column C from column C alone: we have to populate it with (the sum of B) / (the sum of A).
I've managed to do this by handling the DataBound event of the RadGrid and manually populating the cells in the footer. (I had to catch the GridFooterItem in the ItemCreated event, then put values in it in the DataBound event, after it had automatically calculated the totals for A and B for me.) This feels pretty hacky - maybe there's a better way...?
Anyway, the important bit is this:
My grid is split into groups so I also need to populate column C in the GridGroupFooterItems. I can't get my hacky technique to work in this case: I'm finding the footer cell I want with myGridFooterItem["WidgetsProduced"], but I can't get the group footer cells with myGridGroupFooterItem["WidgetsProduced"] - it just isn't a dictionary.
I've tried using myGridGroupFooterItem.Cells[], but this TableCellCollection contains a couple more cells than I'd expect, so accessing them by integer index feels a tad ropey (especially as this is a user-defined report, so the columns may be in any order).
So: how do I populate these cells with my calculation?

your item databound event looks something like
grd_ItemDataBound(object sender,GridItemEventArgs e)
{
//catch the footer element
if(e.Item.ItemType==GridItemType.GroupFooter)
{
(e.Item.FindControl("yourTextBox") as TextBox).Text = your calculated value
}
}

I double-checked whether unique name indexer works with Q2 2009 and Q3 2009 version of RadGrid for ASP.NET AJAX and it worked on my machine. Check your version and ask for more help using the Telerik forums if needed.
Dick

Try this
In Aspx page:
<telerik:GridBoundColumn Aggregate="Sum" DataField="Price" DataFormatString="{0:C}" EmptyDataText="0" FooterText="Total :" HeaderText="Price" UniqueName="Price"> ...
(Or)
In Code behind page:
Private Sub RadGrid1_ItemDataBound(ByVal sender As Object, ByVal e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid1.ItemDataBound
Dim Item As GridDataItem
Dim value as Double
Select Case (e.Item.ItemType)
Case Telerik.Web.UI.GridItemType.AlternatingItem, Telerik.Web.UI.GridItemType.EditItem,Telerik.Web.UI.GridItemType.Item,Telerik.Web.UI.GridItemType.SelectedItem
Item = e.Item
'------ Calculate Total amount -----------
Item("TotalPayment").Text = CDbl(Item("TotalPayment").Text)
value += CDec(Item("TotalPayment").Text)
Case Telerik.Web.UI.GridItemType.Footer
'------ Display the total amount in Footer ------
Dim footerItem As GridFooterItem = e.Item
If Not RadGrid1.Items.Count = 0 Then footerItem("TotalPayment").Text = "Total :" + value
End Select
End Sub

Well, if you use custom formula to calculate results instead of standard aggregates like sum, average and so on, you probably have to rely on your own logic. The cells from the group footers should be indexable by unique name - I remember this was not supported with previous Telerik ASP.NET Grid versions but this was added in more recent versions - Q2 or Q3 2009.
Dick

Related

DropDownList populates based on First DropDown Metro Station Colors

I know how to do this pragmatically with using a OnSelectedIndexChange and a event on the first dropdown. I'm trying to figure out the best way to do this architecturally since in my case I'm dealing with Metro stations where a particular station will have more than one color.
e.g.
First Dropdown List with Color (i.e. Red, Green, Purple)
2nd Dropdown List with Stations
"1st Street - Red and Green"
"Bloom Ave - Green"
"Titan Station - Red Purple"
So if the user selects Red on the FIRST dropdown, the 2nd dropdown should populate with "1st Street" as well as Titan Station". If the user selects Green it should just display "Bloom Ave".
There are many stations with color overlap (more than one color).
The proper way in my mind to do this is create a table with station names and a column for each color with the datatype BIT. If a station has more than one color, those columns would be set to 1 or True. I would have a stored procedure that would fire, the procedure would perform a selection based on color and then show all applicable stations which would bind to the 2nd dropdown.
Is there another way to do this entirely pragmatically, by just the dropdowns itself. Example, you write this logic in the DropDownList control and it knows what's associated with what?
Well, you certainly don't want to start or introduce into your project some kind of bit row wise processing for what amounts to a rather simple and "class" relational model in database land for your solution.
I mean, if you have a customer, and they are to have many invoices, then we don't introduce some bit-wise processing here. (because sql server don't work that way).
So, if you have some customers, then if you need "many" invoices, then you create a invoice table.
If you have some Stations, and they can have 1 or 10 different colors, then you make a table called MyStationColors. This is how all data base operations work.
In fact, the only real question is do you want to store the color (as text name), or do we store the PK id of the color (from our table of colors).
I tend be it a customer, a color, or whatever? I store the PK id, and we are free to display some nice user friendly color description as we please.
so, we need:
Colors - a simple table of all the colors we are going to use
Station - a simple table of all the stations
MyStationColors - a table that lists out all the colors for a given station.
So, once we have the above, then this all becomes a rather simple SQL and database example.
So, we will have 3 tables. Say like this:
Now, I have not introduced any relationships between the color table. After all, it really is just a pick list, or our main list of colors. but, we can add a relationship to that table if we want (it would prevent us from deleting colors are are currently in use by a given station. But, lets keep this simple.
So, our first combo box will be driven (filled out) by a simple combo box, and we feed it the colors table.
And as noted, we went with "id", but a combo box is able to have TWO columns, usually the PK (for code behind), and 2nd color for display to your users.
So, drop in a combo box, say like this:
<asp:DropDownList ID="DropDownList1"
runat="server"
DataValueField="ID"
DataTextField="Color" Width="141px"
AutoPostBack="true" >
</asp:DropDownList>
(don't forget the auto post back in above!!!)
Note the "two" columns for the drop down (Value is hidden, Text is display).
And code to fill combo is this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadCombo()
End If
End Sub
Sub LoadCombo()
Dim cmdSQL As New SqlCommand("SELECT ID, Color FROM Colors ORDER BY Color")
DropDownList1.DataSource = MyrstP(cmdSQL)
DropDownList1.DataBind()
DropDownList1.Items.Insert(0, (New ListItem("Select Color", "0")))
End Sub
And now we see/get this:
And dropping the box, we see this:
So, now all we have to do is wire up the selected index change event.
but, before we do that, and I am VERY lazy, lets use sql studio, and create a view (a query) that will display the stations and their colors. We use that for the "display" of the results.
So, new view in sql server, and we get to do this via drag/drop and GUI (after all, who's going to write that sql by hand, right???).
So, we have this:
And when we run above, we get this:
As we can see, some stations have more then one color, so they show up more then one time. But, we let the query builder in SSMS build that sql above for us - all drag and drop so far.
Ok, save that view (Vstations).
Now, we need to display the results of our choice. So, lets drop in a grid view like this:
<asp:DropDownList ID="DropDownList1"
runat="server"
DataValueField="ID"
DataTextField="Color" Width="141px" >
</asp:DropDownList>
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
And now in property sheet for dropdown, we add the selected index event (double click here:)
And now the code for selecting the combo is this:
Protected Sub DropDownList1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles DropDownList1.SelectedIndexChanged
Dim strSQL As String =
"SELECT * FROM StationsV WHERE COLOR_ID = #COLOR"
Dim cmdSQL = New SqlCommand(strSQL)
cmdSQL.Parameters.Add("#COLOR", SqlDbType.Int).Value = DropDownList1.SelectedItem.Value
GridView1.DataSource = MyrstP(cmdSQL)
GridView1.DataBind()
End Sub
So, now when we select a color, all the stations with a given color will show like this:
Now, of course we should clean up the grid, remove the "ID" and also remove color_id from that grid. But that's just nuts and bolts.
and of course a extra bonus would be to say show all the colors for a given station in above. And we can do that. But, as you can see, these problems are best approached by using a correct data model to reflect the real world case of a station having many colors. And we don't thus mess or introduce some kind of complex bit wise processing. We most certainly did have to introduce a extra table (to keep track of colors for a given station), but other then this bit of extra work, once done, then we are free to add 1 or 5 colors to a station, and we don't have to change the design, or even say assume or add some bit color for a given color.
Be it customers and invoices, or a station with some colors - the relational data model approach tends to make such problems rather easy.
Last but not least, I do get tired of typing connection and loading of a data table over and over, so I also used and had this handy routine MyRstP to return a datatable.
Public Function MyrstP(sqlCmd As SqlCommand) As DataTable
Dim rstData As New DataTable
Using sqlCmd
sqlCmd.Connection = New SqlConnection(My.Settings.TEST5)
sqlCmd.Connection.Open()
rstData.Load(sqlCmd.ExecuteReader)
End Using
Return rstData
End Function

Set ASP DataGrid row color based on cell value

I have an ASP:DataGrid which I am displaying records in. The records are pulled from an SQL Server 2008 R2 database in to an SqlAdapter which in is used to fill a DataSet and that is bound to the ASP:DataGrid
The ASP:DataGrid can span multiple pages and is limited to 20 records per page.
One of the columns is a value for how many days are remaining for the entry to be dealt with. I want to highlight any which have a value 0 - 1 as red and any 2 - 5 as oracle. The method I have tried is to set a function call to the OnItemDataBound field of the ASP:DataGrid
Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemDataBound
If (e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem) Then
Select Case CType(e.Item.Cells(5).Text, Integer)
Case 0 To 1
e.Item.BackColor = Drawing.Color.Red
Case 2 To 5
e.Item.BackColor = Drawing.Color.Orange
End Select
End If
End Sub
This works perfectly when the page first loads. If there are more than one page of records and you try to move to the next page, no records load at all and in fact the ASP:DataGrid doesn't display at all. If I remove the OnItemDataBound then the ASP:DataGrid functions normally again (albeit without the highlights).
So it turned out that may code was actually correct. I put a Try block around the code with a section in the Catch part to log the details in a table in my database.
Straight away it showed the following coming from the Select Case
Conversion from string " " to type 'Integer' is not valid.
A simple change to ensure that the cell is only coloured when a valid value is present is all I needed.

ASP.NET ListView - total value (sum) for a column

I'm writing a reusable control - lets call it MyListView - inherited from standard ASP.NET ListView control. It's datasource is always set to a LinqDataSource and I need to calculate total value for a specific column (sum of all values for that column). Which way is the best to calculate a total value? I was thinking of OnItemDataBound event and computing total there using global variable, but I also need paging in MyListView (using standard Pager control) and this event is fired only for rows on currently visible page, not for all rows in the datasource. I also don't want to calculate total sum in code behind of ASPX page, I want to just specify a column name in aspx, and MyListView will automatically compute total value for the column.
Thank you for help!
IF you're using pagination it's not easy to have that result. I think you should consider to put the row used for totals outside the ListView (so you can use LINQ to compute totals too, I guess you don't want to enumerate all items to compute a total when it can be done quickly on SQL side).
Dim total As Integer
For Each Items As ListViewItem In lV_allItems.Items
Dim lbl As Label = CType(Items.FindControl("Quantitytxtbox"), Label)
total += lbl.Text
Next
Label1.Text = "TOTAL FRAME ADDED : " + total.ToString
I put this code in the page prerender and it works just fine, you have to make sure what is in the columns is an integer otherwise you need to convert.
If you want to get total value from database my suggession is to pass an output parameter with you query / linkq to the database and get the sum of all records from database in the same call in which you get data.
assume you use this query to bind you listview
var queryforBind= (from c in table).Skip(1).Take(10); //1 and 10 can be changed according to your requirement
and after bind your list view call this query to compute total.
var sum = queryforBind.Sum(x => x => x.Field); //Field can be according your requirement

Maintaining Row Selection in ASP.NET GridView Control

The Setup:
I currently have a page with a GridView control on it inside of an update panel, using a SqlDataSource. I have a timer setup to update the GridView every X amount of seconds. Typically for what I am testing every time the GridView updates about 4-5 new rows of data are added to the gridview, while the last 4-5 get tossed out. I am only displaying 15 results at a time and will have new results coming in every update.
The Problem:
I allow the user to select the rows, while the GridView is being updated. I am handling this by setting the SelectedIndex property. However, when I select a row and then the grid is updated the row the user selected gets pushed down about 4-5 rows and the data in the previous selected index is selected instead. So where they clicked is selected at this point, not what they clicked.
I need a way to determine, if possible from the SqlDataSource/Gridview, how many new rows have been added to the gridview. OR a way to maintain the selected data by the data in the row and not just the SelectedIndex.
Any help is appreciated, thanks.
RESOLVED:
Ok I went ahead and added a new invisible column to my grid, and am now keep track of the unique ID's selected from the DB. By setting an array before databinding, and comparing that to the new array I get after databinding I was able to use a simple Intersect to determine the number of rows that are the same. Then I used that to determine from the total how many are new this postback.
Just an idea:
I think you can use an invisible column (more specifically an ID column) to store the selected rows' IDs value in the Session object and then after the grid updates, you can retrieve this value(s) and select the row(s) again if they are still present.
If you have custom GridView OnRowUpdating event.
public void GridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
Session["CurrIndex"] = GridView.SelectedIndex;//index before insertion
Session["RowCount"] = GridView.Rows.Count;//row count before insertion
//Add new Rows
GridView.SelectedIndex = (Int32)(Session["CurrIndex"]) + ( GridView.Rows.Count - (Int32)(Session["RowCount"]);//update selected index
Session["CurrIndex"] = GridView.SelectedIndex;//restore the index into session
}

Apply an ID to a GridView

Before you say it, I'm perfectly aware that a data repeater could do it, but I'm looking for the solution using a GridView.
I'm implementing a jQuery feature and require unique ID's to be applied to individual rows in order to respond to click events in the correct manner. I can't see how you're supposed to apply values to an ID or a row.
Basically I'm looking at doing something along the lines of
$('tr').click(function() {
// get the ID of the tr and redirect the page based on that
});
EDIT: Oh, and I can do it for a row cell if that's the value I want to pass as the query string, however, I don't want to do that as it'd mean displaying a unique identifier which is something the user shouldn't be able to see.
Okay, I didn't expect to actually solve my own question. Just for reference, here it is:
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.ID = e.Row.DataItem("Issue_Key")
End If
which is placed in the RowDataBound event.

Resources