Monday, April 26, 2010

formatting data in a gridview that's auto generating columns

What a long title! Anyway formatting the cell's onrowdatabound is quite well documented but all of the discussion tends to assume that you'll have specified columns, so you'll have BoundColumns and TemplateItems to work with. But I wanted to use short dates in a gridview where I was letting the gridview auto generate the columns (the default unless you set it to false in the gridview properties).

I only found this little reference to it - you need to scroll down to find the relevant code sample underneath Community Content (http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.autogeneratecolumns%28VS.80%29.aspx). I used a free code converter change it to C# but that code still needed work. The original converted code with original comments, and then mine added in below. This code is easily customized for a wide range of formatting output when your gridview is automatically generating columns.


protected void Gridview1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//use syntax to hide baddates
//maybe also do short date strings?

//http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.autogeneratecolumns%28VS.80%29.aspx
// Routine to display an unknown DateTime column
// as a short date at runtime
// By Ken Cox [Microsoft MVP]
// July 28/06
//
// Make sure this is a datarow being bound
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Create variables to hold values
DataRowView dtview = default(System.Data.DataRowView);
int intCounter = 0;
// Get the contents of the current row
// as a DataRowView
dtview = (DataRowView)e.Row.DataItem;
// Loop through the individual values in the
// DataRowView's ItemArray
for (intCounter = 0; intCounter <= dtview.Row.ItemArray.Length - 1; intCounter++)
{
// Check if the current value (item - Layla) is
// a System.DateTime type
if (dtview.Row[intCounter].GetType() == typeof(DateTime))
{
// If it is a DateTime, cast it as such
// into the variable

//Layla: cast item to DateTime
DateTime myNewDate = Convert.ToDateTime(dtview.Row[intCounter]);
//now test if that date is missing date, then hide it if so
if (myNewDate == myConstants.NOTCOMPLETE_DATETIME)
{
e.Row.Cells[intCounter].Text = "";
}
else
{
// Set the text of the current cell
// as the short date representation
// of the datetime
e.Row.Cells[intCounter].Text = myNewDate.ToShortDateString();
}
}
}
}
}


If you compare the original code you can see some small differences. Rather than create a DateTime variable holder to place the item into, I just create the variable IF NEEDED (if the item in the row being evaluated is of type DateTime) and populate it with the item cast as a DateTime. Very small, but I prefer that because I think it's easier to read/understand.

If anyone knows of any other ways to accomplish this - namely iterating through the items in a gridview row onrowdatabound, I'd love to compare it, so tell me about it in the comments!

Tuesday, April 13, 2010

.NET Validators

I have been working a lot with .NET validators recently. I found this article that explains about them quite in depth: http://msdn.microsoft.com/en-us/library/aa479045.aspx

There are two new tricks I took out from this:
1. You can fire an individual validator from javascript using this: ValidatorValidate(document.getElementById("yourValidatorId")). I found it useful in this situation: I have a field taking a temperature value and they wanted to enter either in Fahrenheit or in Celsius. I made two text fields, one for Fahrenheit and one for Celsius, and one validator to validate the range of the Celsius field. When one value is entered or changed, javascript calculate and populate the other value. I didn't want to use one validator for each field because there was no room. So if I entered a value in Fahrenheit that was out of range the Celsius validator wouldn't fire until I submit the form. Now I can call the validator right after I convert Fahrenheit to Celsius so the Celsius field gets validated immediately.

2. You can use ValidatorHookupControl(control, val) to link controls to validators. It's helpful when you have a customvalidator. Without the hookup the validator wouldn't fire immediately. For example, you submit a form and then find that some control is not valid. You fix the problem but the error message won't disappear right away. The built-in validators such as requiredvalidator fires when the control is changed. So users will get confused by this inconsistent behavior, they might think they didn't fix the problem correctly.