Using ITemplate to build EmtpyDataTemplate on GridViews

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
}

Where’s the iBill?

I'm crossing over to the dark side. Behold my first iPhone post - but it's not about the phone, it's about the bill.

Justine Ezarik (aka iJustine) has stirred some attention by posting a video unboxing of her first month's iPhone bill from AT&T. It shipped, as she points out, "in ... a ... box." I'll let others handle the tree-hugging, chest-thumping, save-the-environment bit. Instead, I want to tell you a story.

It all started in 1994. A young, energetic, rock-star programmer (modest, too, as it turns out) had just joined a regional long-distance phone company. His charge? To write the next generation of electronic phone bill reporting software. This phone company, you see, sold mainly to businesses, and some of the phone bills got quite large. Cases of paper, large. The electronic call records were provided to the businesses mainly so they could charge LD back to business units and/or employees. Somebody else, apparently, was assigned the responsibility of handing out little lumps of coal to the poor employees.

So the young programmer built the new system, and it was good. It ran on Windows, and it was faster than all of the competing products (it flat smoked AT&T's product, incidentally), and it let users customize the reports. The totals totalled, and the numbers balanced back to the "real" invoice, and people started to ask questions.

"Here I have in my hand a shiny new CD in its easy-to-mail envelope," they began to say, "and there on the floor, in the large cardboard cases, is the invoice. What's up with that?"

So they marched into the conference room and they deliberated. They talked about legalities and customer service. They talked about cost savings and convenience, and they questioned whether anyone who ever received phone bills in cases ever really took the paper out to read any of it. Whiteboards rattled, papers shuffled, gestures were exchanged, and when the doors opened, there was A PLAN. It went something like this:

Customers would be offered the option to receive their invoice in summary form only (cutting the cases of paper down to a few pages), and their call detail electronically. They would introduce this as an option for their largest customers, and expand as it caught on. The stalwart tree-killers couldn't be completely squashed, for they would still mail a summary, but it was a hollow victory. The writing was on the wall, and the age of electronic phone bills was nearly upon them.

That was 1994, folks.

Where are we today? The default phone bill for AT&T is full-detail, printed on paper. There is an option for an electronic bill. That's fifteen years of progress.

I don't lay all of this on AT&T, or any of the other phone companies, for that matter (I happen to know that Sprint & Verizon aren't distinguishing themselves greatly in this area, either). An awful lot of this problem stems from the fact that technology adoption is just a hell of a lot slower than we'd like to think it is.

We live in the technology fast lane. We're always-on, wireless, and connected, but lots of other people aren't. Walk into a bar in St. Louis and ask the first guy you see if he twitters. When you wake up, you'll know what I mean. We take Web 2.0 for granted, but when we make design decisions that impact users, we need to make sure we're not excluding a big hunk of user base as a result.

Back to the iBill. Who really gets the blame for this? Apple. Ol' Steve & the Apple designers. Back in that old phone company, they understood that the most visible, tangible manifestation of "product" was the phone bill. Dialtone was taken for granted - that's what it means to be a utility. The phone bill, though, was the "user interface" for the phone company.

Steve Jobs rocked the UI on the iPhone. I'm not a fanboy, but there's no denying Apple's knack for reinventing the familiar and making us all ask why it wasn't that way in the first place. Sadly, they stopped with the phone and missed the rest of the user interface.

I'm afraid to imagine what we'll have in another fifteen years.

What do Scoble and Yahoo’s President have in common?

They both like Yahoo! stock right now. CNNMoney just reported that Susan Decker bought Yahoo! stock (YHOO) to the tune of about $1m. They note that this buy was "just the fourth by any Yahoo insider in more than four years; and, the largest by any Yahoo insider in more than four years."

Scoble? Well, he's not voting with his dollars like Decker, but he's noticed a change there that could be a sign of better times.

Personally, I wouldn't be surprised if something good happens there. Yahoo's been the subject of a lot of interesting speculation over the last few months. From takeover target to the next great thing in advertising, they're getting a lot of attention. Add to that the fact that they've had their stock beaten down to the point where any good news is going to lift them.

I'm no expert in insider trading law, but I think that if Decker is buying a bunch of stock right now, we can rule out a short-term takeover, so that leaves earning money the old-fashioned way, and that's ok with me. No matter what you think about Yahoo!, they still have a huge audience with an awful lot of page views. It's quite a launching pad for an underdog with a mission.

Thanks. I feel better now…

Here's one I've been meaning to get around to for a while. Marc Andreessen commented on some decisive action from the Governor of Minnesota following last week's tragic bridge collapse:

New York Times home page: The governor of Minnesota and officials from several other states have ordered all bridges to be inspected...

Sadly, this is Standard Operating Procedure whenever there's any sort of calamity on a scale that causes people not to be re-elected. Earlier this year, a whole lot of personal information suddenly went "missing" when a backup tape was stolen out of an intern's car. Yes, you read that right -- an agency of the Great State of Ohio was sending backup tapes home with an intern, and the intern parked his car somewhere with this tape in it, and the tape was stolen. Oops.

So, there's a whole lot of blame to go around on this one, isn't there?

There's the intern, of course. Lots of people have been pretty hard on him, in part because he was actually named pretty early in the unfolding of this debacle. I believe he's now been fired, in fact. Sure, he shouldn't have left this tape in his car.

But seriously, who really expects an intern to be setting and executing policy decisions for identity protection for a state agency? Go read some Dilbert strips with Asok the Intern, and you'll be in a better mindframe to appreciate how ridiculous this is. I've worked with interns before, and I never resorted to making them get me coffee or pick up my dry cleaning, but it wouldn't have been a huge stretch. Interns do what you tell them to do. That's what it means to be an intern.

Meanwhile, the Governor was springing into action, furiously covering his backside and simultaneously searching for someone to hang out to dry. Here's a bit from a press release he tossed out a couple days after this story broke:

The governor has ordered the cessation of this data management practice, a review of the events that led to the data being compromised, and will take appropriate disciplinary action when the facts are known.

The governor has directed by executive order that state information technology managers immediately review, and if necessary change, the procedures for handling back up information to ensure that information is secure at all times.

Whew. That was close. Good thing the Governor stepped up to tell everyone to cease and desist the intern backup rotation. Eerily similar to the Minnesota Governor's release, isn't it?

So am I blaming the Governor for the data theft? No, not really. Ted Strickland just took office in January, and considering the real problems he's got to deal with (like, get an economy), I really would have hoped that he could focus on the big stuff while someone whose business it was to manage data worried about whether backup tapes were sitting in the back seats of cars.

Sadly, the guys in the middle, one or more of whom really *are* responsible in this case, have remained largely anonymous. I've seen a couple articles where various middle administrators have shucked off blame and deflected responsibility, and this is where you find the heart of the problem: a successful career in government (no, not just politics) depends on one's ability to avoid and/or deny any real responsibility for anything, while managing to be involved in everything.

Sound familiar?

ScottGu – Outstanding Visual Studio Blog

If you work with Microsoft development tools and you haven't subscribed to Scott Guthrie's Blog, stop whatever you're doing right now and GO SUBSCRIBE!

This is hands-down, the single best source about upcoming Visual Studio features you're going to find. Scott intros the new tech, breaks it down, and shows how it works. His recent entries on VS 2008 are great material for composing the "why we should upgrade" memo you know you're going to have to write.

A tale of two LAMP virtual machines

I need a LAMP platform with PHP 5.1 or better to do some SalesForce.com integration testing. These should be a dime a dozen on VMWare's appliance directory, I thought, so I went hunting. After trying a SUSE distro and an Ubuntu distro that didn't quite fit the bill, I decided to try a smaller, dedicated LAMP distro.

I grabbed a VM from rPath first. I've used their SugarCRM appliance in the past, and I'd been pretty happy with that, so I thought they'd be a great place to start. But I couldn't quite get the thing to work. I could start it up, and there was a web site and even an admin site, but I couldn't get FTP to work. It looked like it had been configured for a user that the deamon couldn't find anymore. The VM also had SMB installed, but I couldn't get that to work either.

Obviously, I'm not a Linux guru, though I can find my way around to most of the config files, so I looked for things that were obviously messed up for the SMB and VSFTP services, but I came up empty.

Next download.

Attempt number two was a VM from VirtualAppliances.net (no longer available). Unzip, start it up, and while it boots, I read the docs and see that it's got SMB installed, too. One better, it indicates a user and password to use, and they've thoughtfully set up a share to the www directory already. So when the OS was booted, I open the SMB share, and it works - first time. I edit a little php file to run phpinfo(), save it, and run it - and it works like a charm.

I'm sure that by the time I'm done, I'll find something that I wish these guys had done better, but right now, I'm going to bask in the glow of a great out-of-the-box experience from VirtualAppliances.

Well done, gentlemen!

Web outage on AppDev

Yesterday, AppDev was down for about five hours. I'm afraid I don't know if this was related to the San Francisco power outage, because my web hosting provider can't (or won't) tell me what happened. Sorry for the outage, and if you're considering a web host, chalk this up as a less than ringing endorsement for their customer service.

(update)

More outages today. This time, it's the database server. So much for the power outage theory. This afternoon, I was notified of another outage (mon.itor.us), so I called customer service. "All lines are busy." Not a good sign. I finally got through to the automated attendant, which informed me that "call volume is high", and suggested cruising the FAQ's. Then it hung up on me.

So, needless to say, I'm looking for a new host.

Sigh.

Microsoft “7” — This can’t be for real, can it?

Microsoft is apparently calling their Vista successor "7", according to Techmeme and Engadget. Now, I know that Microsoft has a track record of picking some odd code names, but this one takes the cake.

I think if I were picking code names at Microsoft, I'd steer clear of Borg references. Then again, maybe we're seeing the first glimpses of their next ad campaign:

Microsoft "7"

Think sexy Borg:

... not Bill Borg:

Boy, did AT&T tick off the wrong person!

Today, Guy Kawasaki sounded off on his experience with AT&T customer service ("My iPhone Review"). It was the perfect zinger, coming in from left field when the entire media universe is just hours away from the iPhone love-fest crescendo.

A million other people have had this same conversation. Maybe not with AT&T. Maybe not in a chat window. Maybe they've been shafted by Windows Live OneCare. Maybe they bought a heat sink that squealed to an early death.

Everyone's been there. But not everyone has Guy Kawasaki's readership. You know this one is going to leave a mark. On behalf of everyone who's received lousy customer service, thank you.

This is an example of the sort of open information flow that has only been possible in the last few years. This is why you saw a mirror on Time's Person of the Year issue. Aside from the glee I take in seeing a faceless corporate automaton called out, I really marvel at Web 2.0's potential to radiate information into the common consciousness. I saw this particular story because I've subscribed to Guy's RSS feed, but this is a great post, and it's going to revererate across the blogosphere in a very short period of time.

Just in time for millions of i-groupies to storm Apple stores across the country, they have a little glimpse into their future. Hopefully, some of them will be a little wiser for it.

“We” is a Good Way to Get Nothing Done

IMG_3800I've noticed through the years that lots of people shoot themselves in the foot over and over again, and they never realize that they're doing it. It's the simplest thing in the world, yet it seems to constantly evade even seasoned managers. Paradoxically, it even seems to be a great way to reach out to people, empowering them to do great things, yet, it'll kill you every time.

So, what's the problem? Simple. If you make more than one person responsible for something, it's only by the greatest miracle that it'll get done at all. Doesn't seem to make sense, does it? After all, adding people to a task should make it move more quickly. Adding brains to a problem should boost creativity. Why does this break down? In short, if more than one person is responsible for a task, then nobody is responsible.

Here's what I'm talking about. If you've ever been in a meeting -- a hallway meeting or a board meeting -- and heard someone say, "I thought you were doing that!", then you've seen this phenomenon in action. As soon as there's any ambiguity about whose head is going to roll if there's a problem, you invite more problems. This isn't necessarily because people aren't trying hard, though this does provide a convenient avenue for scapegoating. No, it's really a problem of communicating and personal integrity, and thus, it scales up exponentially as the number of "responsible" parties grows.

Let's walk through an example. Let's say you're chairing a committee of peers, and you ask them collectively to achieve some objectives, you're very likely to see one or more of the following scenarios play out:

  • The committee members sit down and rationally divide the work, then each goes off and completes the work as intended. Riiiigghhttt..... While this does sometimes happen just like that, it's only when all three of the people are responsible, reliable, and free from political motivation. It can happen, but you can't rely on it in the average organization.
  • One member steps up and takes responsibility for the group. He monitors the division of work, and he checks to make sure that things get done. This is essentially a project manager role for that group of tasks. Note that since this is an informal organization, you still need the cooperation of the other members. Any one of them can intentionally or unintentionally torpedo his individual task, putting the whole project at risk
  • Political infighting erupts over division of work, credit for success, blame for failure, and so on. This might seem very likely, but I've rarely seen it, since this sort of bickering draws negative attention in a hurry.
  • Nothing gets done. Variations on this theme would be very little gets done, or something gets done very, very late, or something gets done that has no significant resemblance to the intended objective. This scenario is quite common, because it's the easiest, and the responsibility structure allows any of the users to "opt out" of the work, and then re-surface to point fingers when questions arise.

All of this sounds pretty pessimistic, as if I expect everybody in any given business environment to be lazy, politically-motivated, ruthless back-stabbers. This isn't the case, though I've certainly seen it to be true from time to time. No, in most cases, these are dedicated, honest, hard-working co-workers who are simply trying to do their jobs to the best of their abilities. The best and most successful of these people will, by nature, be the busiest. No good deed goes unpunished, after all. These busy people probably won't have time for anything else. In fact, if you ask them directly to do something for you, there's a good chance they'll tell you that they're too busy.

If you ask them as part of a group to collectively do something together, however, there's a good chance they won't tell you that they're too busy because they assume that someone else is going to pick up that task. And therein lies the rub. Asking a group of people to do something allows the no-goods to squirm out of responsibility on purpose, and it allows the go-getters to wrongly believe that someone else is going to step up to the plate and do the right thing. Either way, there's a good chance that they ball is going to get dropped.

So be direct. It's not rude or imposing - it's the only way to get something done. Make sure that when a task is given, it's given to one responsible person (even if other people are asked to "help"). Make sure that person realizes that an assignment happened. And then follow up to make sure it's done.

It sounds simple, but you'll be amazed how infrequently it happens when you start looking for it.