Wednesday, April 6, 2011

ASP.NET data presentation controls, like GridView, Repater, DataList, ListView, DetailsView or FormView, could be used to show data from database fast and easy, even without single line of ASP.NET server side code. But, sometimes raw data from database are not suitable for showing on web form directly. You could need additional formatting for date values, handle NULLs, change 0 and 1 to something more intuitive to your visitors, show warning if value is too high or just change styles like background color.

Conditional formatting of GridView rows and cells using RowDataBound event

Let's say you want to change color of GridView's cell depending of value. For example, if cell value is larger than 10 then background color should be red. Using GridView RowDataBound event this task is simple. Here is the code:

[ C# ]

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// Check if row is data row, not header, footer etc.
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Get value of third column. Index is zero based, to
// get text of third column we use Cells[2].Text
int CellValue = Convert.ToInt32(e.Row.Cells[2].Text);

// If value is greater of 10, change format
if (CellValue > 10)
{
// Use this syntax to change format of complete row
e.Row.BackColor = System.Drawing.Color.Yellow;
// Use this syntax to change format of single cell
e.Row.Cells[2].BackColor = System.Drawing.Color.Red;
}
}
}

[ VB.NET ]

Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
' Check if row is data row
If e.Row.RowType = DataControlRowType.DataRow Then
' Get value of third column. Index is zero based, to
' get text of third column we use Cells[2].Text
Dim CellValue As Integer = Convert.ToInt32(e.Row.Cells(2).Text)

' If value is greater of 10, change format
If CellValue > 10 Then
' Use this syntax to change format of complete row
e.Row.BackColor = System.Drawing.Color.Yellow
' Use this syntax to change format of single cell
e.Row.Cells(2).BackColor = System.Drawing.Color.Red
End If
End If
End Sub

Like BackColor, on the same way you can change other styles, like BorderColor, BorderWidth, ForeColor, Font etc., or simply change CssClass property to keep styles separated and avoid hard coding.


Formatting data binding output using RowDataBound event

Like changing styles, you can also change data in cells depending of specified condition. Common example for this could be if you have a column that shows "Yes" or "No". But, database architects rarely store these strings directly in database. Common approach is to have only 1 and 0 values in table. So, how to translate 1 and 0 to "Yes" and "No"? One of possible solutions is to employ RowDataBound event, like in previous example. Here is the code:

[ C# ]

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// Check if row is data row
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Get value of third column. Index is zero based, to
// get text of third column we use Cells[2].Text
int CellValue = Convert.ToInt32(e.Row.Cells[2].Text);

// If value is 1 then change to Yes, otherwise change to No
if (CellValue == 1)
{
e.Row.Cells[2].Text = "Yes";
}
else

{
e.Row.Cells[2].Text = "No";
}
}
}

[ VB.NET ]

Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
' Check if row is data row
If e.Row.RowType = DataControlRowType.DataRow Then
' Get value of third column. Index is zero based, to
' get text of third column we use Cells[2].Text
Dim CellValue As Integer = Convert.ToInt32(e.Row.Cells(2).Text)

' If value is 1 then change to Yes, otherwise change to No
If CellValue = 1 Then
e.Row.Cells(2).Text = "Yes"
Else

e.Row.Cells(2).Text = "No"
End If
End If
End Sub

Using RowDataBound event you can change not just text of the cell, but actually anything in the cell. One more common use of this method is if you have column with product images. Let say that some products have image and some not. If you simply bind GridView or Repeater to data source it will show ugly "Image not found" message where image is missing. A little better but not good enough solution is to specify Alt parameter to show some text if product is without image.

Very often, best solution is to place some default image if image is null. Another common use of this method is in discussion boards and social network sites. If use doesn't upload her avatar, then default image is used. You can achieve this using RowDataBound event. I already describe it how, just check Solving "Image Not Found" Problem In GridView tutorial.

Formatting data binding output using inline if condition

Sometime, it is easier to change data directly in markup code. Here is the syntax that changes 1 and 0 to "Yes" and "No" respectively:

[ C# ]

<asp:GridView ID="GridView1" runat="server">
 <Columns>
<asp:TemplateField>
<ItemTemplate>
<img src='<%# (Eval("ImageURL")==DBNull.Value ? "DefaultImage.jpg" : DataBinder.Eval(Container.DataItem, "ImageURL")) %>' />
ItemTemplate>
asp:TemplateField>
Columns>
asp:GridView>

[ VB.NET ]

<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<img src='<%#IIf(Convert.ToString(Eval("ImageURL")) = "", "Default.jpg", Eval("ImageURL"))%>' />
ItemTemplate>
asp:TemplateField>
Columns>
asp:GridView>

Notice that this way is not recommended if you manipulate with large data. Single property like image name or "Yes" and "No" are just short strings. If you need to manipulate with pile of HTML then it could be very confusing and certainly hard to maintain to keep it in single code line as literals. Unlike classic ASP, ASP.NET data controls don't allow syntax like:

<% If Eval("SomeValue") = 1 Then %>

Some HTML

<% Else %>

Some other HTML

<% End If %>

Instead of this, you could for example place two Panel controls and manipulate their Visible property with condition like shown in previous example.

Formatting data binding output using protected function

One more way to format data output is by using protected function. Let say we have a problem like above and want to show default image if NULL is returned. In server side code, we need a protected function, like this:

[ C# ]

protected string getImageURL(object OriginalImage)
{
// In protected function do needed processing to format or change
// output as needed
if(OriginalImage == null)
{
return "DefaultImage.jpg";
}
else
{
return (string)OriginalImage;
}
}

[ VB.NET ]

Protected Function getImageURL(ByVal OriginalImage As Object) As String
' In protected function do needed processing to format or change
' output as needed
If OriginalImage Is Nothing Then
Return "DefaultImage.jpg"
Else
Return OriginalImage
End If
End Function

Then, call this function from markup code, like this:

<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<img src='<%# getImageURL(Eval("ImageURL")) %>' />
ItemTemplate>
asp:TemplateField>
Columns>
asp:GridView>

Formatting data binding output using SQL

Another level where you can manipulate data is your SQL query to database. Instead of calling ItemDataBound event or coding inside markup, do what you need in SQL either in ad hoc query or stored procedure. We can do this using CASE keyword. T-SQL query that process value from table and returns changed or formatted value executes on SQL Server. In ASP.NET application we do simple data binding. For example, let say we want to list all customer's name, phones and faxes. But, since not every customer has a fax, we want to show message "No Fax" instead of NULLs. T-SQL would look like this:

SELECT
ContactName,
Phone,
CASE
WHEN [Fax] IS NULL THEN
'No Fax'
ELSE
Fax
END
FROM Customers

Formatting output in dependence of row position

Sometimes you want to add advertisement in the middle of list, or some other content to specific position. In this case, formatting of data binding output does not depend of data, but only of their position in row collection. You can solve this problem with RowDataBound event, with code like this:

[ C# ]

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// Check if current row is data row
if(e.Row.RowType = DataControlRowType.DataRow)
{
// Check position of the row in grid
if (e.Row.RowIndex == 4)
{
// Show advertisement only in single row
pnlAdvertisement.Visible = true;
}
}
}

[ VB.NET ]

Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
' Check if current row is data row
If e.Row.RowType = DataControlRowType.DataRow Then

' Check position of the row in grid
If e.Row.RowIndex = 4 Then
' Show advertisement only in single row
pnlAdvertisement.Visible = True
End If
End If
End Sub

Remarks

Whenever format data, try to avoid hard coding as much as possible. For example, method with T-SQL query is suitable for very small data, but it is not recommended to put large HTML chunks in SQL query. That makes application harder to test and maintain. In case that formatting demands big changes consider placing this code in two Panel controls and then manipulate only their Visible property. DataList and Repeater don't have RowDataBound event, but they have ItemDataBound which can be used on similar way

see more: http://www.beansoftware.com/ASP.NET-Tutorials/Conditional-Values-Styles-GridView.aspx

0 Comments:

Post a Comment