« February 2008 | Main | July 2008 »

June 2008

Tuesday, June 03, 2008

It's the experience, stupid!

I just attended David Platt's brilliant presentation titled "Using WPF For Good And Not Evil". And I just loved it.

Ever since we saw the first demos of WPF after PDC 03 (almost five years ago) there's been a lot of discussion on how WPF will result in a lot of really nasty-looking applications, just because the technology gives us possibilities to do a lot of things we really shouldn't. Just like HTML did more than 10 years ago. It took a while before people stopped putting marquees and blink tags on their pages, just because they could. Do you remember that old IBM ad where two guys are looking at the Web, one of them keeps looking at the eye candy ("Oooh! Burning logo!), and the other one gets it that the Web can be used for improving their logistics process? We're still at the burning logo-stage with WPF, and need to learn how to use the possibilities the platform gives us for good, and not for evil. This is what Platt talked about.

During the presentation he gave a bunch of tips, some which I will repeat here:

  • Make Sure Content is Correct (Don't forget the functionality just because you can make a flashy UI.)
  • Involve a Good UX Pro, Early (This one rang true, I've had to deal with a lot of people who think that bad usability is something that the user interface fairy can fix by flying in at the end of the project and sprinkle UI-fairy dust on the application.)
  • Be Suspicious of 'Cool' (But I like cool! I have to admit that I'm one of the people who's put fancy animations and things in an application just because it was possible. But I'll stop now. Promise.)
  • Aim to be Unnoticed (Don't dominate the usage experience with flashy stuff.)
  • Always Think of UX, not just the UI (Thinking about the total user experience.)
  • And finally perhaps the most important one (which he actually started with): "Know thy user, for he is not thee". That's something we dev-types tend to forget. We're rarely making software for ourselves, but we still act as if we do.

One of my favorite quote from his presentation was "A chainsaw has no morals. It can be used for good or for evil". That pretty much sums it up.

During the talk I actually felt pretty sorry for the guys (Vertigo) who made Family.Show, because Platt used the showcase application as a showcase of gratuitous use of WPF features, and mostly of how they had been used just because it was possible.

 

Platt is actually one of my favorite speakers. I really enjoyed Platt's latest book, "Why Software Sucks". He's doing another talk at TechEd later this week based on that book. I saw that back at TechEd Europe in November, and it was great. So catch it if you have the opportunity.

Oh, and I've got to say that Platt's got balls. He even dared to pick on S. Somasegar's part of the keynote which included an application with a spinning logo (which was the target of Platt's scorn). Doing that at a Microsoft conference, yay!

Now I have to go and remove the color gradients from one of my apps. Darn.

Monday, June 02, 2008

Using the Google Chart API in a WPF application

If you haven't had a look at the Google Chart API I definitely recommend you do so. It can be a good, light alternative to investing in a more complete charting package. And honestly, most of the extra stuff offered by the 3rd party charting components out there is just eye candy that detracts from the information you chart should communicate.

So, with the Google Chart API you can easily put charts like this in your web application or page:

All you need to do is put an img on your page, and set it's src to a url that contains some Google Chart magic. The url for the chart above looks like this:

Granted, the query arguments are quite complex. But Google has some nice documentation for it, and in the end it's not so bad. Here's a simple example:

The url for this puppy is:

The way you talk to Google Chart is through a series of parameters, separated with an ampersand (&). The url above contains three parameters, as follows:

cht=lc Set the chart type to line chart.
chs=150x100 Set the size of the chart to a width of 150 and a height of 100.
chd=t:10,70,50,40,80,5,25,95 The data points for the chart, as comma-separated values.

So, as you can see, pretty simple stuff.

But what about using this in desktop applications, and WPF applications in particular? Since all Google Chart does is generates an image based on parameters you pass to it in the URL, it can be used in XAML through the Image control. Like this:

<Image Width="150" Height="100" Source="http://chart.apis.google.com/chart?cht=lc&amp;chs=150x100&amp;chd=t:10,70,50,40,80,5,25,95"/>

Note that the ampersands (&) had to be encoded as "&amp;" in the XAML.

Here's a screenshot of the XAML above being used in a little application:

image

Ok, so that works nicely. But dealing with the url, and in particular passing the data point for the chart to the API that way is a little bit ugly, and certainly feels very crude compared to how you usually do things in WPF. So what can be done to improve this? One thing that comes to mind is using a value converter to convert a list of values to the url-format that Google Chart wants. Here's an example of that:

[ValueConversion(typeof(IList), typeof(string))]
    public class ListToTextEncodingConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            IList valueList = (IList)value;
            string baseUrl = (string)parameter;
            if (valueList == null || baseUrl == null)
                return string.Empty;
 
            string valueString = "";
            CultureInfo usCulture = new CultureInfo("en-us");
 
            foreach (object item in valueList)
            {
                double? val = item as double?;
                if (val.HasValue)
                {
                    if (valueString.Length > 0)
                        valueString += ",";
                    valueString += val.Value.ToString(usCulture.NumberFormat);
                }
            }
 
            return baseUrl + "&chd=t:" + valueString;
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return Binding.DoNothing;
        }
    }

It accepts something that implements IList, and tries to find doubles in it, and constructs the url string from that. In addition it accepts the rest of the parameters for Google Chart as a parameter.

And here's a snippet of XAML that uses that value converter to display a chart:

<Window x:Class="WpfSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfSample"
    xmlns:converters="clr-namespace:WpfSample.ValueConverters.ChartDataEncodingConverters"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:SampleData x:Key="SampleData"/>
        <converters:ListToTextEncodingConverter x:Key="ListToTextEncodingConverter"/>
    </Window.Resources>
    <Grid>
        <Image Width="250" Height="150"
               Source="{Binding Source={StaticResource SampleData}, 
                                Converter={StaticResource ListToTextEncodingConverter},
                                ConverterParameter='http://chart.apis.google.com/chart?cht=lc&amp;chs=250x150&amp;chds=0,30'}"/>
    </Grid>
</Window>

Oh, and please not that the ConverterParameter seems to screw up the WPF designer in Visual Studio 2008, I haven't looked into whether anything can be done about that. But it compiles and runs fine.

SampleData is just a set of values, you could of course use whatever you want for your data source, perhaps pull something from a database and use Linq to project it into a list of double values. Here's the class that creates the sample data:

public class SampleData : List<double>
{
    public SampleData()
    {
        Add(10);
        Add(20);
        Add(15.2);
        Add(12);
        Add(21);
        Add(17);
        Add(11);
        Add(8);
        Add(12);
        Add(18);
    }
}

Here's what the application looks like:

image

Simple, but I guess you get the idea.

And finally, is it bad to use a web-based API for charting in a desktop application? Not really, in my opinion. Most desktop apps need to talk to servers anyway, and grabbing a few charts over the web is not going to be a significant performance issue.

Oh, one more thing. Of course this works great in Silverlight 2.0 as well.

WPF Image and "Value does not fall within the expected range"

I was having some problems with images in XAML, and what was happening was that code like this:

<Image Width="200" Height="200" Source="http://www.google.com/intl/fi_ALL/images/logo.gif"/>

would not show the image, and I would get an error in Visual Studio 2008 that said "Value does not fall within the expected range". This was very confusing, since I knew I'd used Images in XAML before, and it worked nicely.

After some googling it turned out this is related to Internet Explorer 8 Beta 1, which I of course have installed. There's a thread on this in the Channel 9 Forums, and also a post on LearnWPF.com.

Seems that the only cure right now is to uninstall IE8.