Setting properties for WiX in MSBuild

I recently had the pleasurable and painful experience of learning WiX to build a windows installer for a Windows Mobile application. The pain came first: there is quite a learning curve to both WiX and the underlying Windows Installer technology; and the documentation is a little thin on WiX 3, the latest version as I write this. But after about two weeks struggling, the switch flipped, the sun shone, the chorus of angels began singing – I understood how it worked and saw that its design is very well thought out. It became a joy to use WiX. And it’s free. And it has pretty good Visual Studio support.

That’s not to say there aren’t problems. The documentation is definitely a problem, one to which I’ll try to make a small contribution in solving. I intend to post more about WiX in the future, but for now, I’ll cover one small thing which is setting properties for your WiX project in an automated build with MSBuild.

Part of the pretty good Visual Studio support is it’s own MSBuild-based project file. It has custom tasks that wrap the underlying command-line utilities, candle, lit, light, etc. This makes it really easy to make it part of your daily build or CI builds. One thing that often gets taken over by the build process is setting the version number of your assemblies. Versioning is especially important when it comes to installers, so keeping the installer version in sync with the application version is definitely a good practice.

To do this with your WiX installer project, we first have turn the version value to a variable. (Forgive me if I use the incorrect terms here, I don’t know the formal WiX names for these things. I’ll gladly change it if someone corrects me.)

Suppose we have the following, default wxs file given to us by Votive in Visual Studio:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" 
            Name="WixProject1" 
            Language="1033" 
            Version="1.0.0.0" 
            Manufacturer="WixProject1" 
            UpgradeCode="c93e09b9-9e8f-444c-a35b-84beb2c3788f">
        <Package InstallerVersion="200" Compressed="yes" />

        <Media Id="1" Cabinet="WixProject1.cab" EmbedCab="yes" />

        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLLOCATION" Name="WixProject1">
                    <!-- TODO: Remove the comments around this Component element
               and the ComponentRef below in order to add resources to this installer. -->
                    <!-- <Component Id="ProductComponent" Guid="51acaaef-c2fb-4ef3-a641-9475c81ac948"> -->
                        <!-- TODO: Insert files, registry keys, and other resources here. -->
                    <!-- </Component> -->
                </Directory>
            </Directory>
        </Directory>

        <Feature Id="ProductFeature" Title="WixProject1" Level="1">
            <!-- TODO: Remove the comments around this ComponentRef element
         and the Component above in order to add resources to this installer. -->
            <!-- <ComponentRef Id="ProductComponent" /> -->
        </Feature>
    </Product>
</Wix>

The property we’re concerned with is the Version attribute on the Product element. Right now it’s set to 1.0.0.0. The first thing we need to do is change this into a variable so that we can set the value from elsewhere. To do that we change the Version attribute above into the following:

<Product Id="*" 
         Name="WixProject1" 
         Language="1033" 
         Version="$(var.ProductVersion)" 
         Manufacturer="WixProject1" 
         UpgradeCode="c93e09b9-9e8f-444c-a35b-84beb2c3788f">
...
</Product>

This creates a preprocessor variable called ProductVersion (you can call it whatever you want). If you build the installer now, you get an error saying “Error    1    Undefined preprocessor variable ‘$(var.ProductVersion)’. “

Now we have to define that elsewhere. And where else but the project file!

To edit that, right click on the project node in solution explorer, select Unload Project… Then right click again and select Edit <ProjectName>.wixproj. You’ll get the proj file loaded as XML in the editor. Let me draw your attention to one of the PropertyGroups:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
  <OutputPath>bin\$(Configuration)\</OutputPath>
  <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  <DefineConstants>Debug</DefineConstants>
</PropertyGroup>

This is a property group that is only defined if the Configuration property is Debug and Platform is x86. You see that DefineConstants property set to Debug? That’s where we want to define our ProductVersion variable, like so:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
  <OutputPath>bin\$(Configuration)\</OutputPath>
  <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  <DefineConstants>Debug;ProductVersion=1.0.0.0</DefineConstants>
</PropertyGroup>

In general, you want to define all your properties in Name=Value; format. OK, we have that entered, so close the file, right click on the project node again in SOlution Explorer, select Reload Project. This makes Visual Studio read the project file again. Build again. No errors! Neat, eh?

Now we’ve managed to move setting the of the ProductVersion property into the MSBuild file, but remember what I said about that property group? It’s only defined in Debug builds. If we switched our project to Release, then we’d get the Undefined variable error again. (This is actually a big usability problem in VS, IMO; this happens all the time for many properties and settings).

What we really want is the ProductVersion property defined for all build configurations. But while we’re developing our installer, we want to use Visual Studio, so we don’t have to constantly go into the proj file to change things. No problem, I got you covered.

The good folks developing WiX for all of us obviously have our interests in mind by setting that Debug property by default, so we’re going to want to save that. We also want to define ProductVersion for Release builds. Let’s consider all the PropertyGroups in the wixproj file, the answer is practically shouting at us:

<PropertyGroup>
  <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
  <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
  <ProductVersion>3.0</ProductVersion>
  <ProjectGuid>{9b84d861-ac5d-4559-bc9c-0e59cb95ad90}</ProjectGuid>
  <SchemaVersion>2.0</SchemaVersion>
  <OutputName>WixProject1</OutputName>
  <OutputType>Package</OutputType>
  <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.0\Wix.targets</WixTargetsPath>
  <Name>WixProject1</Name>     
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
  <OutputPath>bin\$(Configuration)\</OutputPath>
  <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  <DefineConstants>Debug;ProductVersion=1.0.0.0</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
  <OutputPath>bin\$(Configuration)\</OutputPath>
  <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
</PropertyGroup>

First thing we should do is add the DefineConstants property with our ProductVersion property in Release:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
  <OutputPath>bin\$(Configuration)\</OutputPath>
  <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  <DefineConstants>ProductVersion=1.0.0.0</DefineConstants>
</PropertyGroup>

Got it, now: check out the Configuration and Platform properties in the first PropertyGroup. See what they do? They define a default if empty. Now why couldn’t we do that? We’ll define another property in the first property group called Version (you can call it what you like):

<Version Condition=" '$(Version)' == '' ">1.0.0.0</Version>

Alright, one more step, we replace the value in our DefineConstants declarations. I’ll do the Debug version, you do the Release:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
  <OutputPath>bin\$(Configuration)\</OutputPath>
  <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  <DefineConstants>Debug;ProductVersion=$(Version)</DefineConstants>
</PropertyGroup>

Got the Release section finished? Awesome. Reload the project. Build. Awesome.

It works!

Now, we can build this project on the command line and set any version we want.

msbuild installer.proj /p:Version=3.1.0.0

One thing to note though. Ideally, you’re going to mix and match your product assemblies and product installer. Well, maybe not, but if you have any code-based custom actions, you’re probably going to have a C# or VB project in you product installer solution.

The bad news is that the CSharp.targets file, the file with all the default C# build tasks also defines a DefineConstants property. It’s used for setting DEBUG and TRACE and all those. They conform to a certain format; one that doesn’t include Name=Value; formatting. So you get unnecessary warnings.

I’m not sure why they decided to reuse a well-known property name. Was it really so hard to type <PreprocessorVariable>?

Keep it DRAFT-y

The other day I was grabbing screenshots from an app I’m working on. I noticed a huge visual problem with a a list in the product: in a one-column ListView in Details view, each item’s text was truncated, as though the column’s width was just left to the default of 20 pixels (this is in .NET CF, but the problem below applies to the full framework WinForms as well). This is code I inherited, mind you! I certainly wouldn’t have coded it this way (No sir, nah-uh), but I found the offending code that that was trying to set the column width to the largest item; something like this:

private void ArrangeColumnWidth()
{
    //this is called after all the items have been added
    using (Graphics g = this.listView.CreateGraphics())
    {
        int maxWidth = 0;
        foreach (object item in this.listView.Items)
        {
            SizeF s = g.MeasureString(item.ToString());
            if (s.Width > maxWidth)
                maxWidth = s.Width;
        }
        this.listView.Columns[0].Width = maxWidth;
    }
}

Pretty standard find-the-max code, right? Except it wasn’t working. Since I knew there would always be one column, and we’d never change out of Details view, I, without thinking too hard about it, changed the above code to the following:

private void ArrangeColumnWidth()
{
    this.listView.Columns[0].Width = this.listView.Width;
}

“There! That should do it,” I thought — in the few seconds that it took me to write it. Of course, you’ve just read that, and thought, “What a fool! Anyone can see that if there are enough items in the ListView to cause scrolling vertically, then the column width will be too big, so you’ll get a horizontal scroll bar also. Duh! Everyone knows that. What was he thinking?”

And you’d be right.

But sometimes, when I’m in the flow, I have really fast edit, compile, run cycles. The first run after the above edit showed me the problem that you astute readers already found.

At this point, in my younger days, I’d bash away at determining the width of a standard scroll bar and hardcoding that number in my arithmetic. But I’ve learned the following refrain from using .NET since it came out: It’s in the Framework, Dummy!

So, I did a Google search, found a forum post, read it, couldn’t believe the solution was so simple, then went to the MSDN docs to confirm that it was true. It was! If you set the ColumnHeader.Width value to -1, it will size to the largest item. If you set the ColumnHeader.Width value to -2, it will size the header to the header text. It’s all right there on MSDN!

I didn’t know this little tidbit. So, I re-wrote the code. I got rid of the ArrangeColumnWidth() method altogether and now when I create the column, I set it’s width to -1. Problem solved!

Two things occurred to me when I read about those helpful values.

The first is that that is some old-ass .NET code. Microsoft doesn’t write .NET code like that anymore. Instead, I think it would be something like the following:

public enum ColumnWidthStyle
{
    Normal,
    SizeToMaximumItem,
    SizeToColumnHeader
}

ColumnHeader c = new ColumnHeader();
c.WidthStyle = ColumnWidthStyle.SizeToMaximumItem;

That code is more verbose, sure; but it’s way more discoverable, especially with IntelliSense. It’s also more readable; imagine coming back to this code a few months later: it would still make sense. The way we’re stuck with is essentially a magic number, a vestigial bump from the dark ol’ days of Win32 programming. I have no doubt that the ColumnHeader class is managed spackle over the Win32 equivalent, so we get those negative width numbers for free.

Even with the awkwardness of the API as it is, I’m still going to use it. That’s one method I don’t have to write. The whole point of using the .NET framework is that it does a lot for you. And yet…

I still see commercial code shipping with reams and reams of classes and methods that duplicate functionality in the Framework. Why!?!

We’ve all heard the principle of DRY (Don’t Repeat Yourself). I’ve got my own corollary, the DRAFT principle: Don’t Repeat A Framework Type. .NET, J2EE, Rails, Django, CPAN, whatever language and framework you prefer: assume they solve all your problems, learn them, use them, abuse them. And only if they are truly lacking should you write your own.

The Missing .NET #3: An AutoComplete TextBox in WPF, Part 4 – WPF Flourishes

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 new 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.


Well, we’re getting close. Part 1 showed that the standard controls in WPF were all you needed to make autocomplete happen. Part 2 started us on the road to packaging it up into a reusable component; Part 3 went neck deep into advanced WPF territory to finish the hard part of our implementation. In this final segment, I’ll cover some neat features of WPF that we can take advantage of to make our AutoComplete TextBox even better.

There is one more thing to discuss: improvements over the Win32 implementation. The code has a little more in it than what I’ve shown. When creating this, I based it on the ComboBox in the Windows Run dialog. What’s the point of doing this in WPF if we don’t take advantage of the new platform? I touched on Templates earlier when I replaced the TextBox template with my own in Part 3. The ListBox (more accurately, the ItemsControl) allows us to template the UI for our data objects with DataTemplates. What if we exposed that so we could change the look of the autocomplete list? Say we wanted to add an image for each item, as well as text.

Also, what if I wanted to index on more than one property? Currently, my implementation works on the ToString() method for each object, keeping the instances in the list that correspond to what’s typed in the TextBox. Wouldn’t it be cool if we could arbitrarily choose the properties to index on? Then we could get the same behaviour as the Outlook addressee textboxes in the New Mail Window.

I’ll deal with first one, um, first, since it’s the easiest: just expose a DependencyProperty or another Attached property of type DataTemplate. In the PropertyChanged event handler, assign it to the ListBox.ItemTemplate property which you can see in the code.

The second is just a matter of adding a new Dependency Property and changing the CollectionViewSource.Filter event handler like so:

private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
   AutoCompleteFilterPathCollection filterPaths = GetAutoCompleteFilterProperty();
   if (filterPaths != null)
   {
      Type t = e.Item.GetType();
      foreach (string autoCompleteProperty in filterPaths)
      {
         PropertyInfo info = t.GetProperty(autoCompleteProperty);
         object value = info.GetValue(e.Item, null);
         if (TextBoxStartsWith(value))
         {
            e.Accepted = true;
            return;
         }
      }
      e.Accepted = false;
   }
   else
   {
      e.Accepted = TextBoxStartsWith(e.Item);
   }
}

where AutoCompleteFilterPathCollection is a custom Collection<string> class with a TypeConverter applied so that we can write the list of properties in a property attribute as a comma-separated list in XAML thusly:

<TextBox ac:AutoComplete.FilterPath="LastName,Email"
         ac:AutoComplete.Source="{Binding Source={StaticResource people}}" 
         Name="textBox2"></TextBox>

Then we can get an autocomplete textbox that behaves similar to the Outlook To address bar, that indexes on Name and Email. Easy.

API Design Aside: Now we have three Dependency Properties; the client XAML is looking a little cluttered. At this point I may want to make my own AutoComplete object and have one attached DependencyProperty of that type that you set on the TextBox. This has the advantage of enabling sharing AutoComplete data across many controls. But, on the other hand, that design sacrifices the ease of use. There are a couple of ways to present this to the developer, now, is my point. I’ll leave that as an exercise for the reader.

The final thing I wanted to do was show how simple it is to enable this to work on ComboBoxes. It requires just a quick refactoring to parameterize a few things when we set the control in the AutoComplete instance, as shown in Part 3, which I reproduce here:

private static void OnSourcePropertyChanged(DependencyObject d, 
                                    DependencyPropertyChangedEventArgs e)
{
   AutoComplete ac = new AutoComplete();
   ac.TextBox = (Control)d;
   ac.ViewSource.Source = e.NewValue;
   d.SetValue(AutoCompleteInstancePropertyKey, ac);
}

internal Control TextBox
 {
    set 
    {
       control = value;
       Style s = (Style)this["autoCompleteTextBoxStyle"];
       viewSource = (CollectionViewSource)control.GetViewSource(s);
       viewSource.Filter += CollectionViewSource_Filter;
       value.SetValue(Control.StyleProperty, this["autoCompleteTextBoxStyle"]);
       value.ApplyTemplate();
       autoCompletePopup = (Popup) value.Template.FindName("autoCompletePopup", value);
       value.AddHandler(System.Windows.Controls.TextBox.TextChangedEvent, 
                                new TextChangedEventHandler(textBox1_TextChanged));
       value.LostFocus += textBox1_LostFocus;
       value.PreviewKeyUp += textBox1_PreviewKeyUp;
    }
 }

As you see, I’ve typed the TextBox property to Control so I can set this to a ComboBox as well, but there are a few things we’ll have to move into a custom type. For starters, the Style for ComboBox is different than TextBox, so we’ll have to repeat the steps that we took when extracting the TextBox style, namely (deep breath) open XamlPadX, extract the ComboBox style, put it in my ResourceDictionary, add the ListBox control to the visual tree and add the CollectionViewSource to the Style’s Resources.

Once we’ve done that, we want to change the TextBox property above. The two things that we need to change are the hard-coded resource key, "autoCompleteTextBoxStyle"; and we have to parameterize where the CollectionViewSource comes from which you can tell from the two Styles. You can see the code for all the details, but the TextBox property (which I should rename) now looks like this:

internal Control TextBox
{
   set 
   {
      control = AutoCompleteControl.Create(value);
      Style s = (Style)this[control.StyleKey];
      viewSource = control.GetViewSource(s);
      viewSource.Filter += CollectionViewSource_Filter;
      value.SetValue(Control.StyleProperty, this[control.StyleKey]);
      value.ApplyTemplate();
      autoCompletePopup = (Popup) value.Template.FindName("autoCompletePopup", value);
      value.AddHandler(System.Windows.Controls.TextBox.TextChangedEvent, 
                                    new TextChangedEventHandler(textBox1_TextChanged));
      value.LostFocus += textBox1_LostFocus;
      value.PreviewKeyUp += textBox1_PreviewKeyUp;
   }
}

My parameterization class is slightly more complicated because of other methods in the AutoComplete class. One thing that is truly magic in this case is setting the TextChangedEvent handler on the ComboBox. Notice that I’m adding a handler to the TextBox.TextChangedEvent. Look at the ComboBox API, and you won’t see a TextChangedEvent! Yet it works just as you’d expect it to. That’s some magic that I don’t understand. Magic or no, the ease with which we’ve introduced autocomplete for ComboBox can’t go unnoticed. Note also that the ComboBox’s own Items are unaffected by autocomplete (you can set them both to the same data source, though).

Phew! As you’ve seen over this massive edition of the Missing .NET, creating behaviour in WPF needn’t involve custom controls, but it does require a solid understanding of the underlying design concepts of WPF. There is definitely more we can do with this AutoComplete stuff as well. Hopefully, I’ve shown you the start of what’s possible.

The Missing .NET #3: An AutoComplete TextBox in WPF, Part 3 – Control Templates

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 new 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.


In Part 1, I roughed in my AutoComplete Textbox with standard WPF controls. In Part 2, I decided to deploy this as an attached property but ran into some trouble with inserting my WPF controls into an control’s visual tree. In this part below, I show how I solved the visual tree problem using ControlTemplates.

Charles Petzold has an example of creating a ControlTemplate in code in his Applications = Code + Markup: A Guide to the Microsoft Windows Presentation Foundation (Pro – Developer). It involves creating a nested set of factories: truly painful. So I quickly abandoned it as a tenable method for replacing the ControlTemplate. That meant a XAML solution for writing out the ControlTemplate.

But a XAML solution creates its own problems, especially since I’ll have to access the objects created by the template in code (the CollectionViewSource for one, and another control that has yet to make its appearance in this saga). Again, my ignorance with these advanced WPF concepts forced a solution that may not be the best one: I decided to use a ResourceDictionary.

The ResourceDictionary is damn near ubiquitous in WPF. Both FrameworkElement and FrameworkContentElement have a Resources property that allow you to store arbitrary .NET objects, so every control has a Resources property. This is often where styles or data sources are stored, but it can be any .NET object. You can also create your own ResourceDictionary as a standalone class, typically as App-level resources or as a Theme. The cool thing about ResourceDictionary, if you associate it with a class is that you can combine XAML and code like you do in a Window class. Since I’ve already got my AutoComplete class started, what I did was add a ResourceDictionary to my project and used the Class attribute (in the XAML namespace) to associate it with my AutoComplete class.

Now I have to write my own ControlTemplate for TextBox that will allow me to stick my ListBox to it. I could start from scratch, but then I’d have to recreate all the behaviour of the TextBox, including borders, colours, mouse over behaviour, etc, and I want to get this done. I have XamlPadX, so why not pull out the default TextBox style and manipulate it? It’s got the standard look and everything. So that’s what I do: stick that in my ResourceDictionary and change the template to add the ListBox, like this:

<ControlTemplate TargetType="TextBoxBase">
    <StackPanel>
        <mwt:ListBoxChrome Name="Bd">
            <ScrollViewer Name="PART_ContentHost" />
        </mwt:ListBoxChrome>
        <Popup x:Name="autoCompletePopup" 
               Placement="Bottom" 
               PlacementTarget="{Binding ElementName=Bd}"
               StaysOpen="False"
               AllowsTransparency="True">
            <ListBox x:Name="AutoCompleteListBox"
                     ItemsSource="{Binding Source={StaticResource viewSource}}" />
        </Popup>
    </StackPanel>
    <ControlTemplate.Triggers ...>
</ControlTemplate>

This is the relevant piece where I set the Template property on the Control. You can view the entire ResourceDictionary here (Or Download the source). It differs from the standard one in a few places: 1) The StackPanel that contains the TextBox and 2) the Popup containing the ListBox with the name AutoCompleteListBox. Why use the Popup? I’ll leave that as an exercise for the reader. 🙂 Note the ListBoxChrome element with the ScrollViewer inside it. The ListBoxChrome element resides in the Presenation.Aero assembly. Not listed is the Style.Resources property where I add the CollectionViewSource with the Filter event handled.

The methods for handling the CollectionViewSource.Filter and the TextBox.TextChanged events remain the same, I just have to move them to the AutoComplete class and hook them up to the TextBox when it’s passed to me in the OnSourcePropertyChanged event handler when my attached property changes, about which I mentioned earlier in Part 2. I did this with a private, read-only DependencyProperty that creates an AutoComplete instance to associate with the TextBox as the code below shows:

private static void OnSourcePropertyChanged(DependencyObject d, 
                                    DependencyPropertyChangedEventArgs e)
{
   AutoComplete ac = new AutoComplete();
   ac.TextBox = (Control)d;
   ac.ViewSource.Source = e.NewValue;
   d.SetValue(AutoCompleteInstancePropertyKey, ac);
}

internal Control TextBox
 {
    set 
    {
       control = value;
       Style s = (Style)this["autoCompleteTextBoxStyle"];
       viewSource = (CollectionViewSource)control.GetViewSource(s);
       viewSource.Filter += CollectionViewSource_Filter;
       value.SetValue(Control.StyleProperty, this["autoCompleteTextBoxStyle"]);
       value.ApplyTemplate();
       autoCompletePopup = (Popup) value.Template.FindName("autoCompletePopup", value);
       value.AddHandler(System.Windows.Controls.TextBox.TextChangedEvent, 
                                new TextChangedEventHandler(textBox1_TextChanged));
       value.LostFocus += textBox1_LostFocus;
       value.PreviewKeyUp += textBox1_PreviewKeyUp;
    }
 }

In the AutoComplete.TextBox setter is where I set the TextBox’s Style to my style and grab my CollectionViewSource and a reference to the Popup.

That’s essentially it. We’ve created an autocomplete TextBox in WPF! But what’s the point when you don’t take advantage of the new tech? Next time I’ll explain a couple of improvements we can make to the AutoComplete TextBox and show that adding support from ComboBox is really straightforward.

The Missing .NET #3: An AutoComplete TextBox in WPF, Part 2 – Making it reusable

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 new 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.


In Part 1 last time, I started creating an AutoComplete TextBox in WPF using only the controls given to us by Microsoft and the concepts of WPF. I showed how you can quickly get the meat of the problem solved using a custom ICollectionView that filters based on the text in the TextBox. In this part, I’ll discuss what’s needed to make it reusable.

Reusa-ma-bility

Alright. So we have a pretty good idea of what’s required, how are we going to package this up to be reused elsewhere? Right now, my implementation is good for the window that I implemented it in. I could make a new control, and add this logic to it, but I already said at the outset that that wasn’t going to happen.

What I decided to use was an attached property. The guidance on using Attached Properties was what finally sold me. See, I also want to use this on ComboBoxes eventually, but ComboBox and TextBox, which both have a Text property, don’t have a common ancestor past Control. One of the scenarios that the docs describe, but don’t provide an example of is wanting to have a property on different, unrelated parts of the control hierarchy. I don’t know why Microsoft can’t provide an example, but I can: the TextSearch class defines two attached properties with this scenario in mind. (Seriously, the docs for .NET 1.1 were awesome. What the hell happened to msdn?)

OK, so I’m going to use an attached property. What that looks like is the following:

public sealed partial class AutoComplete
{
  public static readonly DependencyProperty SourceProperty;

  static AutoComplete()
  {
     SourceProperty = DependencyProperty.RegisterAttached("Source",
                        typeof (object), typeof (AutoComplete),
                        new FrameworkPropertyMetadata(null,OnSourcePropertyChanged));     
  }

  public static object GetSource(DependencyObject o)
  {
     return o.GetValue(SourceProperty);
  }

  public static void SetSource(DependencyObject o, object value)
  {
     o.SetValue(SourceProperty, value);
  }
}

This is pretty standard stuff that you can find in the docs. The one piece that’s missing in that snippet is the event handler method OnSourcePropertyChanged that’s declared in the call to DependencyProperty.RegisterAttached. I’ll get to that in Part 3.

What this allows is I can use this on any DependencyObject, like so:

<StackPanel >
    <TextBox Name="textBox1" 
         local:AutoComplete.Source="{Binding Source={StaticResource people}}"
         VerticalAlignment="Top" 
         HorizontalAlignment="Stretch" 
         TextChanged="textBox1_TextChanged" />    
</StackPanel>

where local is my declared namespace for my assembly (Visual Studio does this for you).

Awesome. I can put this on a ComboBox now, or anything else that allows text input. Now we have an auto-completing TextBox. Your welcome.

Yes, you have a question? There’s some parts missing? Like what? Oh, right the ListBox, it’s not there anymore.

A Look-less Autocomplete TextBox

I’ve already solved the hard problem of getting the List to show up when the user types something; I just need to make that work on any TextBox. The trouble is, I’m manipulating the visual tree, which, to my belated discovery, is really hard to do in code after the TextBox is created. Turns what I want to do is create a ControlTemplate that contains my ListBox and replace the TextBox’s Template with my own.

One of the key concepts in WPF is what the folks at Microsoft call "look-less controls". The canonical example is the button. There are a bajillion — at my last count — samples of making buttons look different than the standard Windows button in WPF. They do this by manipulating either the Content property of the button, or its ControlTemplate. Either way, you still have a button that can be clicked, but you’ve changed the look of the button. All WPF controls act like this, more or less, to some degree: I was asked to make a ListBox turn into a TabControl and that’s non-trivial, nigh impossible, even though they are related in the control hierarchy.

Another example is the ComboBox. I mentioned in the first edition of The Missing .NET that the traditional Win32 ComboBox is made up of three controls: a button, a listbox, and a textbox. Well, so is the WPF ComboBox! Only, the WPF is a little more explicit about it, and more flexible. The place where this is done is the Control.Template dependency property; it’s a dependency property hanging off Control that lets you set the visual tree of your control. The standard controls manipulate this property in their default Style. One tool you want in your WPF developer toolbox is something that will deconstruct the default Styles of the standard controls; I use XamlpadX. Bombing around the styles should give you an understanding of how they work.

Deconstructing the ComboBox in XamlPadX, sure enough, we see the TextBox, the ToggleButton and the ItemsControl, of which ListBox is a descendent.

We’re getting into some seriously advanced, yet fundamental WPF stuff here, which is a little beyond the scope of this blog post, at least if I wanted to finish quickly. If you’re interested in learning about Templates and Styles, Google can be big help; if you’d prefer to learn offline, then any of the WPF books will be quite helpful. Start small, and work your way up. Learning how templates and styles work is definitely worth the effort.

So the only way to stick my ListBox into the visual tree is to replace the ControlTemplate of the TextBox.

This is where the internets came up short for me and I went out on my own. I have no idea if my solution is a good idea. It seems to work, and work well, but I don’t know enough about WPF to tell if this will work in every situation. Every solution creates its own problems and I ran into a few while solving this one.

OK, so what did I do?

You’ll have to wait ’til next time. 🙂