We're in QA on a .Net project right now, and as QA cycles so often do, this one is flushing out some varying opinions on style. As much as we try to get people to specify this stuff early on, there's nothing like a running system to uncover the closet usability experts.
One of these bugs had to do with the content and style of the message we display when a grid has no data items. I was aware, of course, that the minute I changed it, someone was bound to jump up and ask for the style to be just a little different, so I wanted a solution I could use everywhere, and that would let me change the style when I wanted to.
We'd been using the EmptyDataTemplate in our Gridviews, which would've let me change the style, but wouldn?t let me change the message depending on why the grid had no rows. The EmptyDataTemplate looks something like this:
<EmptyDataTemplate> <asp:Label ID="lblNoData" runat="server">No data found.</asp:Label> </EmptyDataTemplate>
Why not use EmptyDataText? We probably could have made that one work if we?d hard-coded a red font style (bad), or hard-coded a div tag around the text (better, but still not great because we?d have to repeat that all over the place).
So I decided to use a custom template class. I'd never worked with ITemplate before, but I really like it. It reminds me a lot of the stuff that open-source CMS's like PostNuke and Drupal have been doing. I can definitely see using this more in the future. The code for the template class is below, in Listing 1.
To use the template class, set the template based on what's going on (ie, a search). You don't even have to check to see if you have any results - the grid will only display this when there are no rows.
grdSearchResults.EmptyDataTemplate =
new NoDataTemplate("No records match your criteria.");
There?s also a parameterless constructor that defaults the message to ?No matching records.?, and another that lets you specify a reason why the results are empty:
grdSearchResults.EmptyDataTemplate =
new NoDataTemplate(NoDataTemplateReason.NoResultsFound,
"No profiles match your criteria.");
Values for this enum are NoSearchMadeYet, NoResultsFound, and SystemError - default is NoResultsFound. You can mark up styles in your CSS corresponding to these reasons if you want to alter the appearance of any of them:
/* Search results messages when no data present */ .SearchResultsNoSearch { /* no style changes yet, but reserve this spot. */ } .SearchResultsNoData { /* no style changes yet, but reserve this spot. */ } .SearchResultsError { color: red; font-size: larger; font-style: italic; }
Listing 1: NoDataTemplate
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public enum NoDataTemplateReason
{
NoSearchMadeYet,
NoResultsFound,
SystemError
}
/// <summary>
/// Summary description for NoDataTemplate
/// </summary>
public class NoDataTemplate : ITemplate
{
private NoDataTemplateReason reason = NoDataTemplateReason.NoResultsFound;
private string message = "No matching records.";
/// <summary>
/// New template to display when no data present for grid, defaulting Reason to
/// NoResultsFound, and Message to 'No matching records.'
/// </summary>
public NoDataTemplate()
{
}
/// <summary>
/// New template to display when no data present for grid, defaulting Reason to
/// NoResultsFound.
/// </summary>
/// <param name="Message">Display this message in grid.</param>
public NoDataTemplate(string Message)
{
message = Message;
}
/// <summary>
/// New template to display when no data present for grid.
/// </summary>
/// <param name="Reason">What is the reason for no data?</param>
/// <param name="Message">Display this message in grid.</param>
public NoDataTemplate(NoDataTemplateReason Reason, string Message)
{
reason = Reason;
message = Message;
}
#region ITemplate Members
public void InstantiateIn(Control container)
{
string divText;
switch (reason)
{
case NoDataTemplateReason.NoSearchMadeYet: divText = "SearchResultsNoSearch"; break;
case NoDataTemplateReason.SystemError: divText = "SearchResultsError"; break;
default: divText = "SearchResultsNoData"; break;
}
Label l = new Label();
l.Text = "<div class='" + divText + "'>" + message + "</div>";
container.Controls.Add(l);
}
#endregion
}