I have a gridview that shows, for example, a baseball team's statistics. It's a standard sports stats grid - the rows show statistics for each player and the columns show the specific stat for the each player.
Easy enough so far. But what I would then like to do is style (highlight or bold) the Max or Min (the team leader) of each stat column. For example, Player A may only lead in one or two categories, so we cannot style the entire row. If Player A just leads the team in strikeouts, I just want to style the number of strikeouts he had (THAT cell only).
What's the best way to handle this? Make SQL Server do all the work and in effect, rank EVERY stat of each player, effectively doubling the number of columns (e.g. col: AB, col: ABRank). Or do I let the rowdatabound event of the gridview handle this?
If I chose the latter, I think I would get the Max of every statistical category from the datatable before binding (e.g. store them in a local variable) then on rowdatabound, if they match the value, apply the style.
You already gave the answer to your own question, which is by the way the answer I'd have given you.
Or do I let the rowdatabound event of
the gridview handle this?
If I chose the latter, I think I would
get the Max of every statistical
category from the datatable before
binding (e.g. store them in a local
variable) then on rowdatabound, if
they match the value, apply the style.
There is an option you didn't mention. You could use javascript clientside to do the highlighting. should be rather simple to run over a table am highlight the highest values in a column.
Depending on what you are doing you probably have a certain amount of columns you bind to.
I would use LINQ on your DataSource, before you bind it, for each type you want the max for example:
// create a global variable to hold the data
int _maxHomeRuns = 0;
// Then before you bind the datasource, find out the max of each stat
_maxHomeRuns = baseballStats.Max(i => i.HomeRuns); // get the max
// Then in your template columns Label control DataBinding method
if ((int)(Eval("HomeRuns")) == _maxHomeRuns)
{
// Assign the style you want
((Label)(sender)).CssClass = "MaxCellStyle";
}
I wouldn't use the RowDataBinding, do it at the control level's OnDataBinding so you are scoping the checks specifically to a control so you don't have to search for controls on a row.
Related
I try to add a new calculated column to sharepoint list that will show elapsed day. I enter name and write a formula like;
=ABS(ROUND(Today-Created;0))
The data type returned from this formula is: Single line of text
When I want to save I get an error like
Calculated columns cannot contain volatile functions like Today and
Me.
Calculated Column Values Only Recalculate As Needed
The values in SharePoint columns--even in calculated columns--are stored in SharePoint's underlying SQL Server database.
The calculations in calculated columns are not performed upon page load; rather, they are recalculated only whenever an item is changed (in which case the formula is recalculated just for that specific item), or whenever the column formula is changed (in which case the formula is recalculated for all items).
(As a side note, this is the reason why in SharePoint 2010 you cannot create or change a calculated column on a list that has more than the list view threshold of 5000 items; it would require a mass update of values in all those items, which could impact database performance.)
Thus, in order for calculated columns to accurately store "volatile" values like "Me" and "Today", SharePoint would need to somehow constantly recalculate those column values and continuously update the column values in the database. This simply isn't possible.
Alternatives to Calculated Columns
I suggest taking a different approach entirely instead of using a calculated column for this purpose.
Conditional Formatting: You can apply conditional formatting to highlight records that meet certain criteria. This can be done using SharePoint Designer or HTML/JavaScript.
Filtered List views: Since views of lists are queried and generated in real time, you can use volatile values in list view filters. You can set up a list view web part that only shows items where Created is equal to [Today]. Since you can place multiple list view web parts on one page, you could have one section for today's items, and another web part for all the other items, giving you a visual separation.
A workflow, timer job, or scheduled task: You can use a repeating process to set the value of a normal (non-calculated) column on a daily basis. You need to be careful with this approach to ensure good performance; you wouldn't want it to query for and update every item in the list if the list has surpassed the list view threshold, for example.
I found some conversations about this issue. Many people suggest to creating a new Date Time column, visible is false, default value is Today's Date and it will be named as Today. Then we can use this column in our formulas.
I tried this suggestion and yes error is gone and formula is accepted but calculated columns' values are wrong. I setted column Today is visible and checked, it was empty. Default value Today's Date was not working. When I looking for a solution for this issue I deleted column Today carelessly. Then I realized calculated columns' values are right.
Finally; I don't know what is trick but before using Today keyword in your formulas if you create a column named as Today and after your formula saving if you delete Today column, it is working.
UPDATE
After #Thriggle's answer I realized this approach doesn't work like a charm. Yes, formula doesn't cause an error when calculated column saving but it works correctly only first time, in the next day the calculated column shows old values, because its values are static as Thriggle explained.
I have an xPage which I have built with 3 combo boxes and 1 view control. I would like to use the 'Filter by column value' option within the view control to provide the options to filter the values, allowing the user to display any combination of the combo boxes. e.g. Only comboBox1, or comboBox1 and comboBox2, or comboBox3 only, or comboBox1 and comboBox2 and comboBox3.
I used the example in the 'xPages Demonstration Application' (http://www-10.lotus.com/ldd/ddwiki.nsf/dx/xpagesdemoapp.htm or http://xpagesblog.com/XPagesHome.nsf/Entry.xsp?documentId=AAC8E26599256FDC852578CB0066CC13) to do the multi-column filtering using a vector of non-categorized columns.
So, I have come across what appears to be a fairly major issue whereby the data needs to be sorted by date. Date is not one of the filters, but it needs to be the first column in order for the data to be sorted correctly. So my first column is a string, YYYYMMDD, to ensure the data is sorted correctly. I tried to use the sort option within the view control and that does not appear to work with the column filtering implemented in this manner.
So, as Date one of the criteria I am filtering by, I have passed that as an empty string - using the thought process that an empty string will select all (as in the url examples above).
The code I have used to do the filtering is:
var vtr:java.util.Vector = new java.util.Vector();
var t1 = sessionScope.Email;
var t2 = sessionScope.Own;
var t3 = sessionScope.Module;
vtr.addElement("");
#If(sessionScope.Own=="My calls",vtr.addElement(t1),vtr.addElement(""));
#If(sessionScope.Own=="My calls",vtr.addElement(""),vtr.addElement(t2));
#If(sessionScope.Status=="Open",vtr.addElement("Open"),vtr.addElement(""));
#If(sessionScope.Module=="All",vtr.addElement(""),vtr.addElement(t3));
return vtr;
What I have found is that not all data is being returned. I thought this might be due to the date field. So I removed it (changing the view and removing the first add element), and yet I still find that not all data is being returned. I suspect that this might be due to the empty strings being passed, or, that this does not actually work the way I had hoped.
Does anyone know if I can get this working the way I want it to, and if not, do you have any suggestion on how I can go about this?
Date is not needed as the first sortable column in the view. The first column does need to be sorted for the lookup to work just like the Notes view needs to be sorted for #DbColumn and #DbLookup to work. XPages uses the same underlining architecture. This example - http://dev.openntf.org/demos/demoapp.nsf/viewFilteringVector.xsp - works without the data being sorted by Date.
My guess as to why your example isn't working is down to how your Notes view sorted. Try creating a new view with column 1 (email) ascending sort, column 2 (own) ascending sort, and column 3 (module) again ascending sort. You should be able to get vector filtering working in this situation.
If all that doesn't work for you, you might consider multi-layer category filtering (new to 853). This filtering type in XPages is related to how categoryFilter works but allow you to filter a view by the sub-category (or sub-categories) too. This technique might suit your scenario better. Hope this helps.
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
I have a problem with the AdvancedDataGrid widget. When the dataProvider is an ArrayCollection (of arrays), the nth array (within the collection) is also the nth row within the grid, and I can jump and display the i-th row by scripting
adg.selectedIndex = i;
adg.scrollToIndex(i);
now, when I add a Grouping, the dataProvider ends up being a GroupingCollection2, and now the index in the dataprovider's source does not correspond to the index in the adg anymore (which is understandable, because it's being grouped).
How can I select and display a row in grouped data efficiently? Currently, I have to traverse the adg and compare each found item with its data attributes in order to find the correct index of the row within the adg, and jump to it like above. This process is very slow. Any thoughts?
edited later:
We already used a caching object as Shaun suggests, but it still didn't compensate for the search times. In order to fully construct a sorting of a list of things (which this problem equates to, as the list is completely reordered by the grouping), you always have to know the entire set. In the end we didn't solve that problem. The project is over now. I will accept Shaun's answer if no one knows a better way in three days.
Depending on what values your comparing against you can store the objects in a dictionary with the lookup using the property/properties that would be searched for, this way you have a constant time look-up for the object (no need to look at every single item). Say for example your using a property called id on an object then you can create an AS object like
var idLookup:Object = {};
for(myObject in objects)
idLookup[myObject.id] = myObject;
//Say you want multiple properties
//idLookup[myObject.id]={};
//idLookup[myObject.id][myObject.otherProp] = myObject;
now say the user types in an id you go into the idLookup object at that id property and retrieve the object:
var myObject:Object = idLookup[userInput.text];
myAdg.expandItem(myObject, true);
now when you want to get an object by id you can just do
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/AdvancedDataGrid.html#expandItem()
I haven't done any thorough testing of this directly, but use a similar concept for doing quick look-ups for advanced filtering. Let me know if this helps at all or is going in the wrong direction. Also if you could clarify a bit more in terms of what types/number of values you need to lookup and if there's the possibility for multiple matches etc. I may be able to provide a better answer.
Good luck,
Shaun
How Can I find all the rows that has been changed in gridview. I can not use Ajax in any form
First get the contents of your grid before it was changed (such as caching the results of the original gridview datasource binding). Then go through the dataset/datatable/however you want to store it, and compare the contents with the current rows of the gridview.
There's no real efficient way to do this, no method like GridView.GetAllChangedRows(). So, what you might do instead is keep a behind the scenes List that you add to each time a row is modified (use the RowUpdated method), then clear this list when needed.
It depends upon how many columns you want to edit in a row.
If you have only one editable column in a row then you can associate a javascript method with that control which you want to modify and in that method you can get a rowid which you can save in another hidden field and in server side you can get all rows whose ids are stored in hidden field.
If you have whole row editable in that case the best approach I think you should save the original data source somewhere and also set a javascript method with rowclick event to get rowid which user selects. Then when user clicks on submit button get all rows whose row ids are stored in hidden field then compare those with same rowid in datasource. This is the best approach from my point of you.
Let me give you an example, suppose there are 1000 rows in a grid and user clicks on only 180 rows. In that case we will compare only 180 rows and wont compare rest of the rows.
Please let me know if somebody has better idea then this.