BabySmash IV: ItemsControl and Data-bound UIs

For background on what BabySmash is, read Scott Hanselman’s post here.

This post was inspired by Ian Griffiths’s logged issue in the BabySmash issue tracker, titled "Application Logic Does Not Belong in Code Behind." My gut reaction was that that was overkill for such a simple application. BabySmash has almost no logic to it; it basically take what’s pressed and shows it on screen. I was still going to write a post about the technique because of its relevance to any app that displays data; I think databound list controls should be the most common WPF idiom, it’s so important. But, something still rankled about going so far for such a simple concept. So, I went through with the refactoring, and I gotta tell you: Ian was absolutely right.

You should read Ian’s description one of the problems with the BabySmash code. He also describes a solution, but if you aren’t familiar with the ItemsControl, most of it will go right over your head (hopefully not after this post though). I think it’s best if we describe BabySmash in a way that will help us move to Ian’s solution. Databinding in WPF, especially list-bound data, is where WPF diverges from the UI technologies that inspired it. It’s not immediately obvious with BabySmash’s raison d’etre that we can make it data-bound; I’ve found, however, that once you know about WPF’s databinding, you want to model your domain classes to take advantage of it. That’s how I approached changing BabySmash this time. Mike Hillberg has a good post on writing the domain model with WPF.

One more thing before I begin. Modelling any domain problem is subject to opinion. Software design is a matter of trade offs. You may prioritize different parts of the problem than I. Talking about ItemsControl requires a data model. I’ll talk about the model I chose. Hopefully, if you disagree with my object model, the technique of using an ItemsControl I show here can still applied to your model. I’m also not going to dwell too long on all the whys of my object model, although that’s an interesting topic as well. I welcome feedback or those why questions in the comments.

Where’s the data?

Allow me to distill BabySmash down to requirements language:

When a user presses a key in BabySmash, then, depending on the key pressed, a shape, letter or number will be pressed:

  • if the key is a letter key (A through Z), then that letter is displayed on screen in a random position with a random colour;
  • if the key is a number, the behaviour is the same as for letters; and
  • if the key is anything else, a shape is chosen at random and displayed on screen in a random position with a random colour

The shapes drawn are currently square, circle, triangle and star.

Depending on a user setting, as each key is pressed, either laughter or speech is heard. If speech is chosen, then the shape or letter put on screen is announced.

How’s that?

I’ve written it down that way so we can "see where the classes are." Good domain design is all about getting the class model right. Looking at the above description, I can see a few good candidate classes for the essential BabySmash: shape (including square, circle, triangle and star), letter, number, position, colour and sound.

We can break these down further into two categories: display and data. The colour, sound and position have to do with display. The "data" is what shape to draw: the letter, number, or shape dictated by the key press. I’d say the essence of BabySmash is the data category. Below is the class definition that I came up with for that concept:

public abstract class Figure
{
   private UIElement shape;
   private readonly string name;
   
   protected Figure(Brush fill, string name)
   {
      this.name = name;
   }

   public UIElement Shape
   {
      get { return shape; }
      protected set { shape = value; }
   }

   public string Name
   {
      get { return name; }
   }
}

My abstract Figure class has a Shape, typed to UIElement, associated with it and a name. In the constructor, I pass the Brush that will fill the shape. This allows me to create arbitrarily complex shapes to display; here are a couple Figure classes that inherit from Figure:

public class LetterFigure : Figure
{
  public LetterFigure(Brush fill, string name)
     : base(fill, name)
  {
     string nameToDisplay;
     if (Properties.Settings.Default.ForceUppercase)
     {
        nameToDisplay = name;
     }
     else
     {
        if (Utils.GetRandomBoolean())
           nameToDisplay = name;
        else
           nameToDisplay = name.ToLowerInvariant();
     }
     Shape = Utils.DrawCharacter(400, nameToDisplay, fill);
  }
}

public class SquareFigure : Figure
{
  public SquareFigure(Brush fill)
     : base(fill, "square")
  {
     Shape = new Rectangle()
     {
        Fill = fill,
        Height = 380,
        Width = 380,
        StrokeThickness = 5,
        Stroke = Brushes.Black,
     };
  }
}

Basically, I took the code from Window1.xaml.cs in the BabySmash solution that creates the shapes and broke it out into classes. There are also CircleFigure, StarFigure and TriangleFigure that are similar to SquareFigure above. I probably could move the Utils.DrawCharacter() code into the LetterFigure constructor as a further refactoring.

We also need a way to create Figures based on input from the user. That class is below:

public class FigureGenerator 
{
  private int clearAfter;
  private readonly ObservableCollection<Figure> figures = new ObservableCollection<Figure>();
  
  public int ClearAfter
  {
     get { return clearAfter; }
     set { clearAfter = value; }
  }

  public ObservableCollection<Figure> Figures
  {
     get { return figures; }
  }

  public void Generate(string letter)
  {
     if (figures.Count == clearAfter)
        figures.Clear();

     figures.Add(GenerateFigure(letter));
  }

  private Figure GenerateFigure(string letter)
  {
     //TODO: Should this be in XAML? Would that make it better?
     Brush fill = Utils.GetRandomColoredBrush();
     if (letter.Length == 1 && Char.IsLetterOrDigit(letter[0]))
     {
        return new LetterFigure(fill, letter);
     }
     else
     {
        int shape = Utils.RandomBetweenTwoNumbers(0, 3);
        //TODO: Should I change the height, width and stroke to be relative to the screen size?
        //TODO: I think I need a shapefactory?
        switch (shape)
        {
           case 0:
              return new SquareFigure(fill);
           case 1:
              return new CircleFigure(fill);
           case 2:
              return new TriangleFigure(fill);
           case 3:
              return new StarFigure(fill);
        }
     }
     return null;
  }
}

Again, you can see by the TODOs, I just took Scott’s code and moved it around. The FigureGenerator class holds onto the Figures collection that will be used in the UI as the data source. The Figures collection is typed to ObservableCollection<Figure>. This is one of those magic classes offered by WPF that can track changes, so adding a figure to the collection adds an element on screen. FigureGenerator also takes input from the Window class through the Generate() method.

Consuming the Data

OK, we’ve got our data model. Now we want to display it. I’m taking Ian’s recommendations, namely using an ItemsControl,. I’ll break this down into steps.

The first thing is to add the ItemsControl to the Window. We’ll do that in XAML. At the same time I’ll declare my FigureGenerator that will generate the figures. Here’s the XAML first:

<Window>
    <Window.Resources>
        <local:FigureGenerator x:Key="figureGenerator"/>
    </Window.Resources>
    <Grid Name="grid">
        <ItemsControl Name="figures" 
                      ItemsSource="{Binding Source={StaticResource figureGenerator},Path=Figures}">            
        </ItemsControl>
    </Grid>
</Window>

I spoke about StaticResources before. Essentially, what I’m doing here is adding a FigureGenerator instance to the Window’s resources. Then, I’m binding the ItemsControl to the Figures property on the FigureGenerator. There is one more thing I have to do in the code-behind. When a key is pressed, I have to tell the FigureGenerator instance about it. Here are the relevant bits from the code behind:

private FigureGenerator figureGenerator;
public Window1()
{
    objSpeech = new SpVoice();
    InitializeComponent();
   figureGenerator = (FigureGenerator) this.Resources["figureGenerator"];
   figureGenerator.ClearAfter = Properties.Settings.Default.ClearAfter;   
}

private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
    PlayLaughter();

    string s = e.Key.ToString();
    if (s.Length == 2 && s[0] == 'D') s = s[1].ToString(); //HACK: WTF? Numbers start with a "D?"
    figureGenerator.Generate(s);
}

You can run BabySmash now, but what you’ll see isn’t that entertaining:

BabySmash with an unstyled ItemsControl

What’s happening here? We’re using an ItemsControl with the default templates, which just shows each item in the collection using it’s ToString() method; the items are contained in a StackPanel. In Figure’s case, since we didn’t override it, uses Object.ToString(), which prints the type name. Let’s fix that.

The ItemsControl is an important control. It’s the basis for all of the collection controls: TreeView, ListView, ListBox, TabControl, even ComboBox and Menu. All those classes use the behaviour inherited from ItemsControl to display themselves in obviously different ways; i.e. they’re all special cases of the basic ItemsControl (to a first approximation anyway, I’m glossing over some important details). We’re going to show how to customize the look of an ItemsControl in the same way that the above controls do it.

In the XAML above, we told the ItemsControl where our data is, but we haven’t told the ItemsControl how to display it. We do that with Templates. Every control in WPF has a Template that dictates the look of the control. WPF introduces the concept of a lookless control; a control whose appearance is independent from behaviour. The best example of the lookless control is the button. What shape the button takes is independent of what makes a button a button, namely that you can click it. It’s roughly analogous to how CSS affects elements’ appearance in HTML. Typically, a control’s appearance can be modified by replacing it’s ControlTemplate via the Template property. ItemsControl is a little bit different though.

With ItemsControls, we can manipulate independent parts of ItemsControls with different templates. The template you’ll use most often in your apps is the ItemTemplate. The ItemTemplate property is typed to DataTemplate, which as the name suggests can be used to template your data, which can be of any type. This is a very powerful concept. It allows us to display any old type with the same ItemsControl, something pretty much impossible with Windows Forms or Win32 or anything else. We get infinite custom controls.

Let’s make an ItemTemplate for BabySmash. Most of it is already done for us. Scott made the basic shapes, I just moved them into different classes. The thing we want to display can be accessed by the Shape property on the Figure class. Now we want to tell WPF to display that. We do that with the magic ContentPresenter. The ContentPresenter presents whatever you give it the best way it can. Pass it a Button, it’ll display that button. Pass it a string, it’ll print a TextBlock with the string as Text; pass it an object, it’ll print a TextBlock with the string from its ToString() as Text. That’s right, we’ve been using a ContentPresenter all along. We have the shape we just have to point to it.

<ItemsControl Name="figures" 
              ItemsSource="{Binding Source={StaticResource figureGenerator},Path=Figures}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding Path=Shape}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Let’s run it again:

items2

Looking better.

Now we want those letters to show up all over the screen. To do that requires two changes. The first, we have to change the underlying Panel that our ItemsControl uses to layout its Items. I mentioned above that ItemsControl uses a StackPanel by default. We’re concerned with position, therefore we only have one choice: Canvas. We do this by setting the ItemsPanel property to an ItemsPanelTemplate object that contains a Canvas:

<ItemsControl Name="figures" ItemsSource="{Binding Source={StaticResource figureGenerator},Path=Figures}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding Path=Shape}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

If you ran it now, you wouldn’t see anything different. That’s because we’re not setting the Canvas.Left and Canvas.Top attached properties on the shapes yet. You may think we should do that on the ItemTemplate above; I know I did when I was figuring this out a few weeks ago (I tried this same trick of using an ItemsControl for a line graph, a subject for a future post). Well, you’d be wrong.

There’s a third aspect of the ItemsControl: the item container. The item container is responsible for selection management of that item in the collection. There is no specific class hierarchy for it, but if you look around in Reflector, you’ll see that each ItemsControl child (like ListBox, ComboBox, etc) has an override for the GetContainerItemOverride() and returns its item container class (whose name follows from the control with which its associated: ListBoxItem for ListBox and so on). If you inspect the Visual Tree, you’ll see that the actual items in the ItemsControl are the associated item container. It’s this container that we want to manipulate to place the item. We do that with the ItemContainerStyle property on the ItemsControl. Incidently, ItemsControl uses FrameworkElement as it’s container.

<ItemsControl Name="figures" 
              ItemsSource="{Binding Source={StaticResource figureGenerator},Path=Figures}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding Path=Shape}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Canvas.Left" 
                    Value="{Binding RelativeSource={RelativeSource FindAncestor, 
                            AncestorType={x:Type local:Window1}},Path=ShapeLeft}"/>
            <Setter Property="Canvas.Top" 
                    Value="{Binding RelativeSource={RelativeSource FindAncestor, 
                            AncestorType={x:Type local:Window1}},Path=ShapeTop}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

This is the entire ItemsControl. Note there are many ways that occurred to me to create the random numbers for Top and Left. I thought the simplest would be to add two properties on the Window1 class, and then bind to them using a syntax you probably haven’t seen before. This method traverses the XAML (more technically, the visual or logical tree) directly to get to the data source. I’m telling WPF to find the first Window1 class instance in the tree, then bind to either ShapeLeft or ShapeTop properties. Those properties generate random doubles and consist of Scott’s code cut and pasted.

One more thing to add back and we’re done.

If the user chooses Speech as the option for sound, a computer voice is supposed to speak the letter or shape that was just shown. We got rid of that when I rewrote the Window_KeyUp method above. Let’s add it back.

When you set the ItemsSource property on an ItemsControl, the ItemsControl does one more indirection on you. It wraps the source in an ICollectionView. The ICollectionView monitors the collection for changes and handles currency for the ItemsControl. The ListBox, or any other ItemsControl, is completely ignorant of the currently selected item, and so is the source collection (which is typed to IEnumerable<T>). This separation allows for synchronizing multiple controls on the same collection, so that if the selection changes all controls are updated. The ICollectionView is associated with the source, not the targets. The cool thing is, we can access it directly; filtering, grouping and sorting are all accomplished with the collection view (something I use to make an autocomplete text box in WPF). So, we’ll use that to be notified of any collection additions and play the appropriate speech based on the item.

public Window1()
{
    objSpeech = new SpVoice();
    InitializeComponent();
   figureGenerator = (FigureGenerator) this.Resources["figureGenerator"];
   figureGenerator.ClearAfter = Properties.Settings.Default.ClearAfter;
   ICollectionView collectionView = CollectionViewSource.GetDefaultView(figureGenerator.Figures);
   collectionView.CollectionChanged += FiguresCollectionChanged;
}

private void FiguresCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
  if (e.Action == NotifyCollectionChangedAction.Add)
  {
     Figure f = (Figure) e.NewItems[0];
     SpeakString(f.Name);
  }
}

Hit F5. BabySmash is back in all its glory!

So was this worth it?

Before I did this, Window1.xaml.cs weighed in at about 230 lines. Now it’s a svelte 125 lines, but I added about 180 lines with that Figure stuff! I’m not even including the XAML either.

Still, I think I reduced the cognitive load of the app. By putting the display logic in XAML, I noticed that I could concentrate more on what the app was doing. Before, it was all code, so you didn’t really know where to look.

Now, we only need concern ourselves with one idea, Figure, when we’re thinking about BabySmash in general. With a little more work, we can add other shapes as the kids get older like dodecahedron; or animal shapes or pictures of family. Score one for extensibility.

We’ve also somewhat separated the appearance of the shapes from the shapes themselves. Score one for encapsulation.

We can also test the FigureGenerator and Figure classes without a UI. Score one for automated testing.

Hopefully, I’ve shown how the ItemsControl provides huge benefits for displaying your domain here. If you want to play around some more, I suggest using ListBox with a custom ItemTemplate to get a feel for how it works.

Using Commands in BabySmash

For background, you should read the first post by Scott Hanselman on his BabySmash project. I’ve already written one post on how to to do configuration better. In this post, I’ll cover another aspect of WPF that Microsoft got right: commands.

I’ve written about commands before. In that post, I was describing a way to implement Commands in Windows Forms. They are completely missing in Windows Forms, but in WPF, they got first class treatment.

Why Commands?

In my WinForms article, I didn’t really discuss what Commands were. Oh well. I’ve always told myself to proof read, but I never seem to listen.

Consider an operation like opening a text file. Suppose you were writing a notepad clone. That would be an important operation to support. Notepad has a menu with a menu item that shows the system’s OpenFileDialog, lets you pick a file and open it, display it, etc. Now suppose you wanted to do one better than Notepad and you wanted a right-click menu with a menu item that does the same thing. You’d handle the Click event for your new context menu item, and do the same thing as in your notepad clone’s main menu item. A little later in the dev cycle, you decide you’re going to have a Toolbar with a button that lets you open a file too. Then you decide that your notepad clone is so important that you’re going to have a icon in the system tray with a context menu that lets you open a file from one of the menu items. I could go on and on with, say, keyboard shortcuts and the like, but I think I’ve gone far enough.

What does your code look like now? If you were smart, you’d have one method in your Window class that would handle opening a file and call that method from all the click handlers. If you were really smart, you’d hook up all the Click events you were handling to the same method. But you probably handle each one separately and copy the code each time. That’s what I’d do when I was just starting out.

This is probably fine for a notepad clone; it’s fairly straightforward, there’s one window that doesn’t do much. If you started out with the write once/paste anywhere coding style, you could refactor to a more streamlined approach like the other two above. But consider how Visual Studio would look like if it took this approach. A operation can be called from just about anywhere in VS. If it were coded like my theoretical notepad clone, the main window must be millions of lines long: there are tons of operations in VS. Of course, VS is not coded like that. They use commands.

What if we wanted to make our open operation in the notepad clone a little more permanent? We’d probably want to take the code and move it into it’s own class that could be re-used across our whole app, independent of the window. You’ve essentially just made a command: separated the logic of the operation from the UI that invokes that operation. There would likely be more than one operation too, and if we did that to every operation, we’d probably see a lot of duplication in those classes. Duplication that can be removed by formalizing the reoccurring pattern. This idea really takes off when it’s built right in to your UI framework; the controls you use could know about commands, there could be a set of built-in commands that are common enough that they are worth implementing by the framework. Fortunately, Microsoft has done with WPF.

For complete background on commands in WPF, you should check out Jelle Druyts’s article. He explains it really well, and there’s basically nothing I can add that doesn’t repeat what Jelle already says.

Instead what I’ll do is show you what I did in BabySmash to reduce some of the code that Scott wrote, and that you’d have to write in your apps, and let the system to it for us. I’ll explain just enough about how commands work in WPF, but you should really read Jelle’s article. It’s ok, I’ll wait for you.

BabySmash lets a baby, or anyone, repeatedly mash the keyboard which makes fun things happen. That’s the main part of the app, but there are some ancillary things that all apps need, like settings and setting those settings, which I’ve covered already. We also need a way to open the dialog to set the settings. To open the options window, one has to press Ctrl-Shift-Alt-O. Scott sniffs for that in the "main loop" of his app, the KeyUp event handler. Perfectly fine really, there’s only one operation right now, but he may want to add more, then that KeyUp handler method will started getting hairy….er. Also, I’m a firm believer in methods doing one thing. Right now the KeyUp handler is doing many things.

private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
    //HACK: Why did I find the Windows Forms modifier keys classes to be so much more accurate?
    bool Alt = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Alt) != 0;
    bool Control = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Control) != 0;
    bool Shift = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Shift) != 0;


    if (Alt && Control && Shift && e.Key == Key.O)
    {
        e.Handled = true;
        Options o = new Options();
        o.ShowDialog();
        return;
    }

    numberOfShapes++;
    if (numberOfShapes > Properties.Settings.Default.ClearAfter)
    {
        numberOfShapes = 1;
        MainCanvas.Children.Clear();
    }

    PlayLaughter();
    ...
}

So let’s separate out the Options window opening code. To do that, as Jelle explains, we need to declare a command binding. We could do that in code, but let’s do it in XAML.

<Window x:Class="BabySmash.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Baby Smash by Scott Hanselman - http://www.hanselman.com/babysmash"
        Height="386" Width="601"  WindowStyle="None"
         Topmost="True" Activated="Window_Activated" Closing="Window_Closing"    
        
    AccessKeyManager.AccessKeyPressed="Window_AccessKeyPressed"
       KeyUp="Window_KeyUp" KeyDown="Window_KeyDown"
       Loaded="Window_Loaded"
        >
    <Window.CommandBindings>
        <CommandBinding Command="Properties" Executed="Properties_Executed"/>
    </Window.CommandBindings>
    <Grid>
        <Canvas x:Name="MainCanvas">
            
        </Canvas>
    </Grid>
</Window>

Here’s the Window1.xaml from BabySmash with a CommandBinding declared. I’m using the built-in command, ApplicationCommands.Properties. Technically, not semantically correct, but close enough for our purposes. The CommandBinding is basically saying when someone invokes the Properties command for this window, handle it in the Properties_Executed handler, shown below.

private void Properties_Executed(object sender, ExecutedRoutedEventArgs e)
{
   Options o = new Options();
   o.ShowDialog();
}

We’re almost ready to delete some of Scott’s code. Now we have to hook up a way to invoke the command. If there were buttons or menu items in BabySmash, we could just set the Command property on them and WPF takes care of it all. It doesn’t, so we have to do a little more. We have to create an InputBinding for the Ctrl-Shift+Alt+O shortcut key, known in WPF as an InputGesture.

<Window>
    <Window.CommandBindings>
        <CommandBinding Command="Properties" Executed="Properties_Executed"/>
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Gesture="CTRL+ALT+SHIFT+O" 
                    Command="{x:Static ApplicationCommands.Properties}" />
    </Window.InputBindings>
    <Grid>
        <Canvas x:Name="MainCanvas">
            
        </Canvas>
    </Grid>
</Window>

Note the two ways in XAML to declare the command. The first one, in the CommandBinding element is allowed because it’s a built-in command. The second way will work for your custom commands as well. That’s it.

Now the KeyUp handler can be simplified by deleting code; as Scott pointed out, always a good thing.

private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
    numberOfShapes++;
    if (numberOfShapes > clearAfter)
    {
        numberOfShapes = 1;
        MainCanvas.Children.Clear();
    }

    PlayLaughter();
    ...
}

I’ll leave it as an exercise for you following at home to add the close command and an InputBinding for ALT-F4. I didn’t test thoroughly but this can handle the problem that Scott noticed with multiple monitors.

StaticResource does not mean static

My post about BabySmash got hanselmanned. There are some questions in the comments on that post that are worth addressing in another couple posts, so here’s the first. For background, we have Scott’s follow up post, describing how he changed the code because of my post.

In Scott’s post, Configuration with DataBinding, he wrote the following:

Next, we tell the Grid that’s laying out the controls that we have some static data we’ll be using and we call it "settings" because that’s the class name.

<Grid DataContext="{StaticResource settings}">

There are a few misunderstandings in this statement that I’d like to clarify, since this is a learning experience and all.

There are two big WPF concepts here, DataContext and StaticResource. I’ll tackle StaticResource here. Consider the XAML below:

   1: <Window x:Class="WpfApplication1.Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:System="clr-namespace:System;assembly=mscorlib"
   5:     SizeToContent="WidthAndHeight">
   6:     <Window.Resources>
   7:         <System:String x:Key="s">Hello</System:String>
   8:         <System:String x:Key="i">42</System:String>
   9:     </Window.Resources>
  10:     <StackPanel>
  11:         <TextBlock Text="{StaticResource s}" />
  12:         <TextBlock Text="{DynamicResource i}" />
  13:     </StackPanel>
  14: </Window>

This is the world’s tiniest window. I have two TextBlocks – think of TextBlock as a simple label, for now – one below the other, whose text is set to some string values. I’ve declared the strings in the window’s ResourceDictionary, through the Window.Resources property. The Resources property is declared on FrameworkElement, from which all controls in WPF inherit, so it’s on every WPF control. The StackPanel has a ResourceDictionary, the two TextBlock’s do, the App object (not shown) does, and the system does too.

A ResourceDictionary is basically a giant hashtable. You can store any .NET object you want, like I did above. You can do this from code as well, which perhaps may be more appropriate (since XAML tends to obscure things; remember: anything in XAML can be done in [way more verbose] code):

   1: public class Window2 : Window
   2: {
   3:   public Window2()
   4:   {
   5:      //declaring the same resources in code
   6:      this.Resources.Add("s", "Hello");
   7:      this.Resources.Add("i", "42");
   8:   }
   9: }

I have two strings sitting in a ResourceDictionary. Now, I want to access them. Let’s do that in code first. In the code below, I create my StackPanel, add my TextBlocks to it, and set the values on them. Here’s the not-quite-equivalent code version of the XAML declared at the beginning.

   1: public Window2()
   2: {
   3:    //declaring the same resources in code
   4:    this.Resources.Add("s", "Hello");
   5:    this.Resources.Add("i", "42");
   6:  
   7:    StackPanel stackPanel = new StackPanel();
   8:    //setting the textblocks' text property to resources 
   9:    TextBlock textBlock1 = new TextBlock();
  10:    textBlock1.Text = (string) this.Resources["s"];
  11:    
  12:    TextBlock textBlock2 = new TextBlock();
  13:    textBlock2.Text = (string) this.Resources["i"];
  14:  
  15:    stackPanel.Children.Add(textBlock1);
  16:    stackPanel.Children.Add(textBlock2);
  17:  
  18:    this.SizeToContent = System.Windows.SizeToContent.WidthAndHeight;
  19:    this.Content = stackPanel;
  20: }

I say not quite equivalent because the XAML is doing something slightly different. In the code version, I access the resource directly. In XAML, I’m telling WPF that the values I want for the Text properties are resources, one static and one dynamic (which I’ll get to in a moment). WPF will then move up the control hierarchy (I’m not sure exactly, but I think it moves up the logical tree) and check each ResourceDictionary for the key given. So it’ll check the StackPanel’s resources, then the Window’s. If it wasn’t in the Window’s resources, it would move up to the App resources, and finally to System resources. Resources are really important in WPF; it is where things like Brushes, Colours, Styles and Templates are put. If you were making a skinnable app, you’d make heavy use of resources.

Now, let’s clear up what the StaticResource does. Here’s the relevant XAML again:

<TextBlock Text="{StaticResource s}" />
<TextBlock Text="{DynamicResource i}" />

The curly braces means this is a MarkupExtension, a XAML-only concept that allows us as developers to be slightly more expressive than plain old XML allows. The meaning of static in this case may be clearer when juxtaposed with it’s brother, they DynamicResource. There is a class behind these two, StaticResourceExtension and DynamicResourceExtension. You could try writing the equivalent code; I did, and it didn’t work, but in the docs there is the ominous warning that this is used by the XAML subsystem and shouldn’t be called by humans.

The difference between StaticResource and DynamicResource is how they are accessed by WPF. The semantics of StaticResource are "just read this value once, and don’t check for changes." It’s static as in not moving, not as it is in C#. Note that the two objects in the window’s resources are plain old string instances.  StaticResources are good for things that don’t change, like Brushes or Styles, or read-only data. It’s unfortunate from a learning perspective that the data in BabySmash was static in the C# sense as well, but it’s just a coincidence, honest.

DynamicResource on the other hand is a little more intensive for WPF, because it will track changes to the ResourceDictionary. So if the value of a DynamicResource changes, WPF knows about it and updates the control accordingly. This is good for data that changes, obviously.

Let’s expand the XAML just a bit, and add a button with a click handler. In the click handler, let’s update the value keyed with "i". Run the code, click the button and watch as 42 becomes world. And you don’t have to write anything to make this happen.

<StackPanel>
    <TextBlock Text="{StaticResource s}" />
    <TextBlock Text="{DynamicResource i}" />
    <Button Click="Button_Click">Click me</Button>
</StackPanel>
 
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.Resources["i"] = "world";
}
 

Redoing the Options Dialog in BabySmash

Scott Hanselman introduced us to BabySmash today. It’s an app for his kids that he developed using his arcane Win32 knowledge in a WPF app. He did it on purpose, mind you, to teach himself WPF, with us watching.

I think this is a fantastic idea. When I was writing the AutoComplete TextBox series, I thought it would be a cool idea for all the major WPF book authors (Adam Nathan, Chris Sells & Ian Griffiths, Charles Petzold and Chris Anderson) to write their implementations of the same problem. They’re all very good at explaining, they’d all come up with different solutions and we could all figure out the best way to do things in WPF, as Scott alludes to in his post on BabySmash.

I’ve taken a look at the code and, boy, it needs work. I saw immediately something I’ve experienced pain with before, which I’ll talk about in this post: custom settings. In .NET 2.0, one of the cool The default Settings.settings file.unsung heroes is the settings code in System.Configuration. Note that it’s not tied to WPF or WinForms. With it, you’re able to have user- or app-scoped settings. They can be local or roamable. The framework takes care of storage, although it’s extensible. Visual Studio assists with code-gen so you can access your settings with code.

By default, VS will create a Settings class that inherits from ApplicationSettingsBase in the YourProjectNamespace.Properties namespace. The settings you create in the Settings designer get properties generated for them. The Settings class also has a static instance accessed through the Default property. Scott actually created this file, but then didn’t use it. I haven’t used ClickOnce, but I just can’t see Microsoft not supporting the settings file automagically in ClickOnce.

Pictured below is BabySmash’s settings with Scott’s intended properties filled in.

The settings Scott already used in BabySmash filled in the settings file

So, like I said, this is independent of UI framework. How do we use it in WPF? Databinding! By far the best thing of WPF, even though you have to put some time in to learn it.

Before I show the code to databind to the application settings, allow me to show you the XAML for the Options page in BabySmash.

<Window x:Class="BabySmash.Options"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Baby Smash! - Options" Unloaded="Window_Unloaded" Loaded="Window_Loaded" Height="188" Width="268" ShowInTaskbar="False" Topmost="True" WindowStartupLocation="CenterScreen" WindowStyle="ThreeDBorderWindow" ResizeMode="NoResize">
    <Grid>
        <Button Height="23" Name="OK" VerticalAlignment="Bottom" Click="OK_Click" IsDefault="True" Margin="64,0,102,9">OK</Button>
        <Button Height="23" Margin="0,0,8,9" Name="Cancel" VerticalAlignment="Bottom" IsCancel="True" HorizontalAlignment="Right" Width="80" Click="Cancel_Click">Cancel</Button>
        <Label Height="28" Margin="14,19,0,0" Name="lblClearAfter" VerticalAlignment="Top" HorizontalAlignment="Left" Width="120">Clear After x Shapes</Label>
        <TextBox Height="23" Margin="0,19,8,0" Name="txtClearAfter" VerticalAlignment="Top" HorizontalAlignment="Right" Width="101"></TextBox>
        <CheckBox Margin="0,81,0,0" Name="chkForceUppercase" Height="16" HorizontalAlignment="Right" VerticalAlignment="Top" Width="109" >Force Uppercase</CheckBox>
        <ComboBox Margin="0,48,8,0" Name="cmbSound" Height="23" HorizontalAlignment="Right" VerticalAlignment="Top" Width="101" IsDropDownOpen="False">
            <ComboBoxItem>None</ComboBoxItem>
            <ComboBoxItem>Speech</ComboBoxItem>
            <ComboBoxItem>Laughter</ComboBoxItem>
        </ComboBox>
        <Label Height="28" Margin="14,43,112,0" Name="label1" VerticalAlignment="Top">Sounds</Label>
    </Grid>
</Window>

If you know XAML and how the WPF grid works, then you know that this is really bad code. This is probably the most egregious thing about WPF, IMO: the visual designer. Scott didn’t write this code. Visual Studio did.

Petzold has a great transcript/paper of a talk he gave to a New York user group in 2005 titled, Does Visual Studio Rot the Mind? In it he talks about the evolution of visual programming and Visual Studio. It’s written in 2005, before WPF even got its name, but while he was writing his book, Applications = Code + Markup. But the points he raises are still valid. WPF is, by default, laid out without reference to pixels. The intention of its designers was that with WPF, you say what you want, the WPF figures out how to make it so. Most of the new frameworks from Microsoft have that in their design: "tell me what, I’ll figure out how."

In WPF’s case, it’s completely undermined by the visual designer in Visual Studio. Note above the code snippet from Scott’s Options page: see all those Margin attributes? That’s like hard-coding the same string value in more than one place. This is a dialog box, but humour me. Suppose we allowed this dialog to be resized by the user. What would happen? Chaos.

 The visual chaos of visual studio defaults.

This is what Visual Studio gives you out of the box. Shameful. And if you want to use databinding, forget it, you have to write the XAML by hand. I am dimly aware of Expression Blend; I’ve used it a few times and I think I remember it being a little smarter than Visual Studio. I think that shows how Microsoft is a little out of touch with developers outside of Microsoft. In theory, I like the idea that developers can work on the app doing something, while designers work on the app’s appearance. Really good idea, in theory. In my experience, the developer is the designer the majority of the time. In this scenario, Visual Studio needs a lot more work.

Anyway, let’s stop ranting. I also think it’s a developer’s responsibility to learn either how technology is used if it’s well-established, in the case, of, say, PHP or ASP.NET; or how its designers intended it to be used in the case of WPF. That’s what I’ve done, and what I’m still doing now. So let’s make an Options window that binds to the app settings. Scott’s was laid out, as he intended it, as the following:

The BabySmash Options dialog

There are plenty of ways to do this with the default panel types in WPF. I’ll use the Grid since it’s the most powerful, the default choice and hence the most popular. I’ll preserve as much of what Scott had, and try to make it pixel perfect.

OK, I’m back. Did you miss me? Here’s what I have:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1.Properties"
        xmlns:l="clr-namespace:WpfApplication1"
        Title="Baby Smash! - Options" 
        Height="188" Width="268"
        ShowInTaskbar="False" 
        Topmost="True" 
        WindowStartupLocation="CenterScreen" 
        WindowStyle="ThreeDBorderWindow" 
        ResizeMode="NoResize">
    <Window.Resources>
        <local:Settings x:Key="settings" />
    </Window.Resources>
    <Grid DataContext="{StaticResource settings}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Label Height="23" Margin="10,20,0,0" Grid.ColumnSpan="2">Clear after x Shape</Label>
        <TextBox Text="{Binding Path=Default.ClearAfter}" 
                 Height="23"  Grid.Column="1"
                 Margin="15,20,0,0"/>
        <Label Height="23" Grid.Row="1" Margin="10">Sounds</Label>
        <ComboBox Grid.Column="1" Grid.Row="1" Height="23" Margin="15,0,0,0">
            <ComboBoxItem >None</ComboBoxItem>
            <ComboBoxItem >Laughter</ComboBoxItem>
            <ComboBoxItem >Speech</ComboBoxItem>
        </ComboBox>
        <CheckBox Grid.Row="2" Grid.Column="1" Margin="15,0,0,0"
                  IsChecked="{Binding Path=Default.ForceUppercase,Mode=TwoWay}" >
            Force Uppercase
        </CheckBox>
        <StackPanel Orientation="Horizontal" Grid.Row="3" Grid.ColumnSpan="2" 
                    HorizontalAlignment="Right">
            <Button Name="okButton" IsDefault="True" 
                    Margin="0,7,10,7" 
                    Padding="30,0,30,0" Click="okButton_Click">OK</Button>
            <Button IsCancel="True" 
                    Margin="5,7,7,7" 
                    Padding="15,0,15,0">Cancel</Button>
        </StackPanel>
    </Grid>
</Window>

It looks more verbose for sure, but I think that’s more because of editing by hand and using the ENTER key. Let’s pull out unnecessary stuff and show the code that binds to the application settings

<Window x:Class="WpfApplication1.Window1"
        xmlns:local="clr-namespace:WpfApplication1.Properties"
        xmlns:l="clr-namespace:WpfApplication1"
        >
    <Window.Resources>
        <local:Settings x:Key="settings" />
    </Window.Resources>
    <Grid DataContext="{StaticResource settings}">        
        <TextBox Text="{Binding Path=Default.ClearAfter}" />
        <CheckBox IsChecked="{Binding Path=Default.ForceUppercase}" >
            Force Uppercase
        </CheckBox>
        <StackPanel >
            <Button Name="okButton" IsDefault="True" 
                    Margin="0,7,10,7" 
                    Padding="30,0,30,0" Click="okButton_Click">OK</Button>
            ...
        </StackPanel>
    </Grid>
</Window>

There are some concepts you’ll see over and over again WPF: the use of ResourceDictionaries (Window.Resources in the XAML), DataContext, and DataBindings. I won’t explain all of it in detail (this post is long as is), but I’ll briefly explain it and bold terms that you can search the internets for more info.

Most of the XAML should be familiar even if you’ve never seen it before. It’s fairly close to ASP.NET code, if memory serves, and the XML hierarchy is a good fit for a model that represents a window as a nested tree of controls. The Windows.Resources element adds a Settings object to the window’s ResourceDictionary. All resource dictionary items must have a key to refer to. We set the DataContext on the Grid to the settings object declared in the resources. It’s a StaticResource which means that WPF loads it once and stops listening to updates to that resource. The DataContext is essentially associating the Settings object with the Grid. The  Binding on the TextBox’s Text property is BindingExpression whose Path points to the Default.ClearAfter property of the Settings object. That’s a little advanced, but hey, it’s "real world." And that’s all you have to do to get the settings to show up in the right controls. Notice there is no procedural code.

There’s one more thing to talk about before I quit. The Settings object’s properties change when you change the values in the controls (set the TextBox to 32, and ClearAfter is set to 32), but we have to tell the Settings object that we want to keep those values. We do that in okButton’s handler:

private void okButton_Click(object sender, RoutedEventArgs e)
{
   Properties.Settings.Default.Save();
   this.Close();
}

Too easy, eh?

There are some caveats because I didn’t test thoroughly: databinding by default updates the source after focus changes so if you set the TextBox to 32, then click OK, it may not update the property properly as you’d expect. I explicitly left the third property in settings to be set by you if you want to take up the challenge. I added the settings in BabySmash but they weren’t showing up properly. I don’t know why and I didn’t pursue.

So there you have it. I didn’t show Scott’s Option dialog code, but I’ve significantly reduced it. My Options Dialog window XAML code may be a little longer but I get some layout benefits by using the Grid to its potential. Of course, you may do something different, and it may be better, but that’s the whole point of the Scott’s app. There are some treats in the solution below. I got tired of writing this post before I covered everything that I noticed. I’m going to play video games now.

The Missing .NET #4: Cue Banner in WPF (I mean, Watermark in WPF)

The .NET framework is huge, but not so huge that it does everything for everyone; there are things that they in Redmond miss or don’t do for whatever reason but is still generally applicable to many developers. So, dear reader, I present to you a series of posts on stuff I find missing in .NET, typically where even the Google fails to find the answer. It could be a useful class, a technique, a good practice or documentation that should be in the framework but isn’t.


A regular reader would know I’m quite enamoured with the Cue Banner as UI tool. Once again, in WPF, Microsoft missed something fairly obvious for inclusion; and really easy to implement, as we’ll see. We’ve been through 2 revs of WPF since its release, and the number of new controls or new features on old controls is disappointing. In case you missed it, .NET 3.5 SP1 Beta was released a few weeks ago. The grand total of new controls in WPF? One; admittedly, a useful one – a WebBrowser control.

When I showed how to use the Cue Banner in Windows Forms, I mentioned that the Cue Banner is no app saver. It’s no laser show, fireworks or smoke machine. But it does add significantly to the usability of the app. Since we’re seeing it more frequently on the web now as well, I’d say the effectiveness of the Cue Banner is obvious.  When I mention usability, I mean the ease with which a human can use a tool, like software, not "it looks cool." I notice that people often confuse usability with prettiness in the software realm. But you’re smarter than that aren’t you, dear reader?

There are already two implementations of Cue Banners that I’ve seen in WPF, both have some cool features, but both inherit from TextBox which I find so limiting that I can’t really recommend them. The coolest one is the InfoTextBox in Kevin Moore‘s WPF Bag-O-Tricks which has been around since before WPF got its horrible name. The InfoTextBox is actually a great example of extending a Control in WPF. There is almost no code, except for the declared Cue Banner property, called, rather yuckily, TextBoxInfo. It truly shines in the overriding style (in generic\InfoTextBox.generic.xaml). It’s a collection of triggers and ControlTemplate; I still don’t understand how it’s working completely. If you want to see some WPF code written by someone who knows what they are doing, you should download the source and have a look. Anyway, the cool thing about the InfoTextBox is the effect Kevin created when you focus on the TextBox, but before you enter some text. You have to see it to believe it, so go download it!

The second implementation is not from WPF but from its younger, more attractive sibling, Silverlight 2. Poor WPF will probably be the Charlie to Silverlight’s Eddie Murphy, because of the Web’s ubiquity and importance. Silverlight 2 is still in beta, but it has had in its controls collection since the start, the unfortunately named WatermarkedTextBox.

My first Computer Science class was a mandatory class for my first degree in Physics. I’m not going to lie to you: I didn’t like it. Why I didn’t like it is for another blog post and it’s not why I brought it up. I have on occasion gone back to the code I wrote for my assignments and saw with amusement that all my variables were called x. Amusing, because I’m quite adamant on properly naming the classes, components, methods, variables, parameters in my code now, and have been since I started liking this whole computer thing. It’s too important for clarity. I’ve gone through the SomethingManager naming scheme phase, I pay attention to what FxCop says about naming when I create new classes and none of my variables are now named x. I’m fairly literate, so I know the meaning of the words that I use. The WPF team, on the other hand, doesn’t.

If Wikipedia is any authority, then a watermark, either digital, or …real, is for  permanently marking something with a mark to distinguish where the somethingIndiana Jones wants a little hint about your email textbox. came from. That little logo on the bottom corners of TV shows now? The ones that wreck plasma TVs because they never go away? Those are watermarks. They are always there. The whole point of a cue banner, on the other hand, is to provide just a little hint of what should go there. Once text is entered, then it goes away.

Here’s a couple more reasons WatermarkedTextBox sucks: Google knows about cue banners. It also knows about watermarks, but the real watermarks. The Silverlight controls has both a WatermarkedTextBox and TextBox. Um, why? Just make Watermark a property on TextBox. If it’s null, it doesn’t show up.

The cool thing about WatermarkedTextBox? Actually, cool is the wrong word for it but I hadn’t thought of it until seeing the WatermarkedTextBox demo page: using images or text as the cue banner. I extrapolated: why not anything as the cue banner?

Then I answered my own question.

Cue banners are useful on ComboBoxes and TextBoxes, so that eliminates the possibility of inheritance if I want to maintain this code and keep my sanity (ComboBox and TextBox don’t share enough code in WPF, namely, their Text properties are different). What else could I use? I know! Attached properties! I love those things.

The code for declaring attached properties, like all dependency properties, is pretty much all boilerplate:

public static class CueBannerService
{
  //there is absolutely no way to write this statement out
  //to look pretty
  public static readonly DependencyProperty CueBannerProperty = DependencyProperty.RegisterAttached(
                                "CueBanner", 
                                typeof (object), typeof (CueBannerService), 
                                new FrameworkPropertyMetadata(null, CueBannerPropertyChanged));

  public static object GetCueBanner(Control control)
  {
     return control.GetValue(CueBannerProperty);
  }

  public static void SetCueBanner(Control control, object value)
  {
     control.SetValue(CueBannerProperty, value);
  }

  private static void CueBannerPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
    ...     
  }
}

This code declares CueBanner as DependencyProperty of type object, owned by the CueBannerService, and whose default value is null. The Get/Set methods are there by convention for the programmer who likes to declare stuff in code, and for the XAML engine to set things at design time. You can’t leave it out, even though it won’t be called at runtime if you set these properties in XAML. This is all standard stuff; the difference between this attached property and the rest, other than the name, is what happens in the PropertyChanged event handler. For a good intro to Dependency Properties, you check out Drew Marsh’s Introduction to DependencyProperties post.

She needs a tiny hint about your herbal remedy It’s Cue Banner’s nature to be set once. The Cue Banner’s only purpose is to provide a small hint to the user about the control with which it’s associated. So the property changed handler assumes that the value is only going to be set once. However, the control may show the cue banner multiple times during the lifetime of the app. We’ll start simply here and implement it only for TextBox and ComboBox. The behaviour of the Cue Banner for these two controls is to show itself if the Text value of the control is the default value (the empty string for these two controls) and to remove itself if the user focuses on the control. In my property changed handler, I basically want to get a reference to the control instance and listen for some of its events:

private static void CueBannerPropertyChanged(DependencyObject d, 
                                             DependencyPropertyChangedEventArgs e)
{
 Control control = (Control)d;
 control.Loaded += control_Loaded;
 if (d is ComboBox || d is TextBox)
 {
    control.GotFocus += control_GotFocus;
    control.LostFocus += control_Loaded;
 } 
}

There’s more coming in this method, hence the type check. My first implementation of this, when I just limited it to TextBox, was to set the TextProperty if the TextProperty was the empty string. Once the user focused on the control, I’d check to see if the TextProperty value was the CueBanner value, then set the TextProperty back to the empty string. This had the undesirable side effect of raising the TextChanged event on the TextBox. Since I can’t control when that gets raised, any handler that is listening to that event would have to check the cue banner value as well as the empty value. That’s not pretty at all. For most of the low-level input events there is a PreviewXxxChanged event that can be used to cancel the XxxChanged event, but TextChanged doesn’t have one.

So I needed another way. I could have tweaked styles like I did with the AutoComplete WPF implementation, but it didn’t really seem appropriate. Plus, it’s a proven method that I’ve already found; that’s just downright boring. The whole point of implementing these things is to learn different aspects of WPF. Basically what I needed was a way to display something on the screen in the same spot as the TextBox, but I couldn’t use the Text property for fear of messing with the developer’s expectations of an unobtrusive, useful addition to WPF.

It usually happens that when I’m trying to solve a problem where the solution isn’t obvious, the solution comes all at once and at the oddest moment. In this case, it came when I was bombing around Beatriz Costa’s excellent WPF blog, reading this post on Drag and Drop, after reading Chris Sells and Ian Griffiths’ WPF book, Programming WPF, Chapter 18 to be precise. If you don’t own that book – well, you should – Chapter 18 deals with custom controls. After reading those two articles, I had enough stuff bouncing around in my brain to come up with the answer to my problem: the adorner layer.

I have no doubt that you’ve seen the adorner layer in action: the underwhelming WPF visual designer in Visual Studio uses it to show the size values changing as you resize your window or control. The adorner layer, though, is always around, and sits atop the window of your app; think of it as a sheet of glass. Drag and drop is a good use for it as well: since you’re moving all over the visual tree, implementing drag and drop any other way would cause you to go insane.

For my needs, the AdornerLayer is perfect. A small visual cue above the control (above as in higher in the z-order) that goes away when needed. The AdornerLayer contains adorners, so that’s the next thing I have to write. An Adorner is a UIElement so it has all the power of WPF behind it; I want to take advantage of it. My CueBanner will likely be a string, but it could be something else, an image, say. I want something that will handle all that for me. Using the It’s in the Framework, Dummy principle, I knew that the good folks on the WPF team already came up something that does that, the ContentPresenter. That’s all my CueBannerAdorner does: wrap a ContentPresenter in an Adorner. It’s a blatant, purposeful copy of Bea Costa’s DraggedAdorner from the Drag and Drop sample.

internal class CueBannerAdorner : Adorner
{
   private readonly ContentPresenter contentPresenter;

   public CueBannerAdorner(UIElement adornedElement, object cueBanner) : 
      base(adornedElement)
   {
      this.IsHitTestVisible = false;

      contentPresenter = new ContentPresenter();
      contentPresenter.Content = cueBanner;
      contentPresenter.Opacity = 0.7;
      contentPresenter.Margin =
         new Thickness(Control.Margin.Left + Control.Padding.Left, 
                       Control.Margin.Top + Control.Padding.Top, 0, 0);
   }

   private Control Control
   {
      get { return (Control) this.AdornedElement; }
   }

   protected override Visual GetVisualChild(int index)
   {
      return contentPresenter;
   }

   protected override int VisualChildrenCount
   {
      get { return 1; }
   }

   protected override Size MeasureOverride(Size constraint)
   {
      //here's the secret to getting the adorner
      //to cover the whole control
      contentPresenter.Measure(Control.RenderSize);
      return Control.RenderSize;
   }

   protected override Size ArrangeOverride(Size finalSize)
   {
      contentPresenter.Arrange(new Rect(finalSize));
      return finalSize;
   }
}

By default, WPF sizes everything to the content it creates. The one thing that took me a little time to figure out is the right Size value to pass to the ContentPresenter in MeasureOverride. Amazing how generic that code is, eh? Despite all my griping earlier, WPF is still totally awesome. Classes like ContentPresenter are pure magic.

Great. Now we just need to add our adorner to the AdornerLayer. We do that in the event handlers I subscribed to in the CueBannerPropertyChanged handler:

private static void control_GotFocus(object sender, RoutedEventArgs e)
{
   Control c = (Control)sender;
   if (ShouldShowCueBanner(c))
   {
      RemoveCueBanner(c);
   }
}

private static void control_Loaded(object sender, RoutedEventArgs e)
{
   Control control = (Control)sender;
   if (ShouldShowCueBanner(control))
   {
      ShowCueBanner(control);
   }
}

private static void RemoveCueBanner(UIElement control)
{
   AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);

   Adorner[] adorners = layer.GetAdorners(control);
   if (adorners == null) return;
   foreach (Adorner adorner in adorners)
   {
      if (adorner is CueBannerAdorner)
      {
         adorner.Visibility = Visibility.Hidden;
         layer.Remove(adorner);
      }
   }
}

private static void ShowCueBanner(Control control)
{
   AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);
   layer.Add(new CueBannerAdorner(control, GetCueBanner(control)));
}

private static bool ShouldShowCueBanner(Control c)
{
   DependencyProperty dp = GetDependencyProperty(c);
   if (dp == null) return true;
   return c.GetValue(dp).Equals("");
}

private static DependencyProperty GetDependencyProperty (Control control)
{
   if (control is ComboBox)
      return ComboBox.TextProperty;
   if (control is TextBoxBase)
      return TextBox.TextProperty;
   return null;
}

That just about does it. Now you can set a cue banner to just about anything for TextBox or ComboBox. The code is similar to how ToolTip works. Here are a few examples:

<StackPanel>
    <TextBox Name="textBox1" 
         VerticalAlignment="Top" 
         HorizontalAlignment="Stretch">
        <sm:CueBannerService.CueBanner>
            <Image Source="Forest.jpg"/>
        </sm:CueBannerService.CueBanner>
    </TextBox>
    <ComboBox Height="23" 
              sm:CueBannerService.CueBanner="Pick Something" 
              IsEditable="True" 
              IsDropDownOpen="False">
        <System:String>Geek</System:String>
        <System:String>Cool Guy</System:String>
    </ComboBox>

</StackPanel>

But I’m not done yet! Condy's not getting enough hints.

Why limit ourselves to just text controls? I know I keep reminding you about what a cue banner is, but here it is again: a small visual hint about what you’re supposed to do. That needn’t be limited to edit controls.

I recently started looking into this whole Web 2.0 thing and got a Flickr account. Their Uploadr tool is pretty useful and look what they have in their image list pane thing (it’s written with XUL on Mozilla):

Flickr's Uploadr tool

Here’s where all that generic code shines. We can easily add some support for CueBanners on List controls, we just need some way to tell when to display it and when to turn it off. In WPF, when we talk about List Controls, we’re talking about ItemsControl. There is a slight wrinkle in that there are two ways to add Items to an ItemsControl: through the non-dependency property, Items, or through the ItemsSource dependency property using data binding. When we first get a reference to our ItemsControl, we have to account for both:

   1: private static void CueBannerPropertyChanged(DependencyObject d, 
   2:                                              DependencyPropertyChangedEventArgs e)
   3: {
   4:  Control control = (Control)d;
   5:  control.Loaded += control_Loaded;
   6:  if (d is ComboBox || d is TextBox)
   7:  {
   8:     control.GotFocus += control_GotFocus;
   9:     control.LostFocus += control_Loaded;
  10:  }
  11:  if (d is ItemsControl && !(d is ComboBox))
  12:  {
  13:     ItemsControl i = (ItemsControl) d;
  14:     //for Items property
  15:     i.ItemContainerGenerator.ItemsChanged += ItemsChanged;
  16:     itemsControls.Add(i.ItemContainerGenerator, i);
  17:     //for ItemsSource property
  18:     DependencyPropertyDescriptor prop =
  19:        DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, i.GetType());
  20:     prop.AddValueChanged(i, ItemsSourceChanged);
  21:  }
  22: }

Here’s the complete implementation of CueBannerPropertyChanged. I’m not entirely happy with this implementation, but I couldn’t see a way to handle the Items otherwise. The Items collection isn’t a dependency property so we have to use something else. What I really want is for the ItemsControl to raise an event when the Items collection changes. I had to settle for going through the ItemsControl’s ItemContainerGenerator (the class factory for ItemContainers), which meant I had to track ItemContainerGenerators to ItemsControls because I can’t access the ItemsControl from the ItemContainerGenerator’s ItemsChanged event handler, hence the itemsControls dictionary on line 16. If anyone knows a better way, please leave a comment (if you got down this far :)). The ItemsSource property is a dependency property so we can use the DependencyPropertyDescriptor class to add an EventHandler when the property value changes. I was worried about the sender in that event but it turns out to be what you’d expect it to be, namely the ItemsControl instance. Now you can easily add a CueBanner to a ListBox

<Window x:Class="WpfApplication1.Window3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sm="clr-namespace:Soundmind.Windows;assembly=Soundmind.Windows"
    Title="Window3" Height="300" Width="300">
    <Grid>
        <ListBox >
            <sm:CueBannerService.CueBanner>
                <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                    <TextBlock Height="23">
                        <Run Text="Drag some images here, bitches" FontSize="18"/>                        
                    </TextBlock>
                    <TextBlock TextAlignment="Center">
                        <Run Text="Or click add to find photos" FontFamily="Arial" />
                    </TextBlock>
                </StackPanel>
            </sm:CueBannerService.CueBanner>
        </ListBox>
    </Grid>
</Window>

which looks like the following:

A ListBox with a CueBanner