A common question in the forums has been how to get dynamic icons in the Silverlight Toolkit TreeView and luckily there are quite a few options.

The Icon

Before you can make the icon dynamic you need a place to put it.  The basic idea is to create a HierarchicalDataTemplate and make room for an image:

<stackpanel.resources>
    <controls:hierarchicaldatatemplate 
        x:key="TaxonomyTemplate" 
        itemssource="{Binding Subclasses}">
        <stackpanel orientation="Horizontal">
            <contentpresenter margin="0 0 4 0" content="???" />
            <textblock text="{Binding Classification}" />
        </stackpanel>
    </controls:hierarchicaldatatemplate>
</stackpanel.resources>

<controls:treeview 
    x:name="MasterTree" 
    itemtemplate="{StaticResource TaxonomyTemplate}" />

I've added a ContentPresenter and the Content is what we're interested in setting dynamically.

Option #1 – The Fixed Template

If you have a rigidly defined hierarchy where you know the exact icon you want at each level you’re in luck, there is already a sample showing how to do just that in the NestedHierarchicalDataTemplate scenario, using three separate HierarchicalDataTemplates, one for each level.  This has the advantage of being easy for your designers to style the icons independent of the code, the obvious downside is it’s a fixed structure.

Option #2 – Binding to a Property

Another option is to add an Icon property to your object and bind the Content directly to it, like this:

<contentpresenter margin="0 0 4 0" content="{Binding Icon}" />

In your descendent classes you can override the Icon property and return the appropriate image for that class.  You can even go further and return different images based on state, such as availability, status, quantity, etc. 

Object model purists may be frothing at the mouth, since I dared put UI information into my objects, and in some scenarios I’d completely agree but what we’re doing here is creating UI model objects, not business model objects.  It’s a common pattern and has the great benefit of making your UI testable from inside unit tests instead of having to rely solely on UI macro recorder/playback frameworks.  I go so far as to recommend that if you’re doing a lot with states like icons, if something checked, multi-selection, color-coding, etc. that you create objects that sit between your business object and the actual UI elements.

Anytime you find yourself trying to get directly at a control to set/check state ask yourself if there is something you could be binding to instead.

Option #3 – The ValueConverter

If you’re binding directly to business objects or really don’t like the idea of adding an Icon property to your objects (you know who you are) then you can take all that logic and roll it up into a value converter.  IValueConverters are these great things that convert between two different types of values (I know, shocking).  A classic example is converting between a boolean and the Visibility enum.  We’re going to apply the same concept but this time convert between a type (our business object) and an icon.

First, we need a ValueConverter, what I’m calling the IconConverter:

public class IconConverter : IValueConverter
{
    public object Convert(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        if (value is Domain)
        {
            // return icon for Domain
        }

        if (value is Family)
        {
            // return icon for Family
        }

        if (value is Genus)
        {
            // return icon for Genus
        }

        return null;
    }

    public object ConvertBack(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Next, add it as a resource in your application so you can use it in your XAML (you will probably also need to add your project’s namespace to the XAML, that is where “local” comes from in my sample):

<usercontrol.resources>
    <local:iconconverter x:key="IconConverter" />
</usercontrol.resources>

Last, set the binding on the content presenter so it knows to use the converter when trying to determine the icon:

<controls:hierarchicaldatatemplate 
    x:key="TaxonomyTemplate" 
    itemssource="{Binding Subclasses}">
    <stackpanel orientation="Horizontal">
        <contentpresenter 
            margin="0 0 4 0"
            content="{Binding Converter={StaticResource IconConverter}}" />
        <textblock text="{Binding Classification}" />
    </stackpanel>
</controls:hierarchicaldatatemplate>

This technique has the advantage of centralizing everything as well as being usable on any type of object you’re using in your TreeView, whether they all descend from a common base-type or not and if you put it in the application’s resources you can use it throughout your application.  It is also still very testable from a unit test, which is always a plus.

The downside is that the is operator is expensive in terms of performance so if you have a lot of different classes you’re checking against, with a lot of items in the tree you may hit some perf issues.  This can be mitigated by keying off of other data that may be unique to your class-hierarchy.

DataType

The WPF crowd is probably jumping up and down saying, “But wait, wait, what about DataTarget?!”  In WPF one way you’d handle dynamic icons is to create a HierarchialDataTemplate per class you wanted to style and set its DataType property so when that Type appeared in the TreeView it would get its custom style.  It works great and is a tasty way to handle these situations but alas it’s not supported in Silverlight.  Personally I actually prefer option #2 and #3 if all you’re doing is changing icons.

Limitless Options

For every option I’ve proposed here there are probably a dozen others based on your specific needs, business objects and user interface.  If you come up with a great solution or have a situation that you don’t feel is covered here then please either leave a comment or visit us in the forums.

3 Comments

Ever since joining Microsoft back in August 2008 this blog has been pretty quiet and not just because I’ve been rolling around in the autumn leaves on campus but because of this gem, the Silverlight Toolkit.

At its highest level the Silverlight Toolkit is a collection of great controls and utilities that are continually being improved and polished until they are of the highest and most useful caliber.  You can find all the great details about this release over on my fearless leader’s blog and I highly recommend you check it out because beyond saying what the Silverlight Toolkit contains he also explains how it was built, how it will continue to be built and how it will be released in a very agile, very feedback-centric way.

One thing I want to stress is how important you, the developers, designers and those of uncertain vocation, are to this process.  Saying your feedback is valuable isn’t just lip service; we are watching the Issue Tracker, we are reading and responding in the Silverlight Controls forum, we are reading blog comments, in short we are listening to the people who use these controls day in and day out.

One of the features I love most about the Silverlight Toolkit is its iterative nature: We look at feedback, rub our brain cells together, roll up our sleeves and six to eight weeks later we have new controls that are ready to be previewed by the community or existing ones that have been polished to a high sheen by your feedback and continued testing.

I’m really looking forward to seeing what people do with these controls as well as what feedback is out there.  I’ll see everyone in the forums :)

Listening To Robot Rock/Oh Yeah by Daft Punk on Alive: 2007 (Live) in honor of how hard we all worked on this release.  Worked in fact… like robots.

1 Comments

As I've been working my way through the Silverlight & XAML landscape inside of Visual Studio I've come to realize how much better tools like TextMate, InType & E are at editing straight text. 

I was reminded of this today when I was trying to create a simple code snippet for XAML.  I whipped up a quick little snippet and went to use it how I always do, by typing the shortcut then pressing TAB.  Well, I tabbed and nothing happened.  OK, something happened, I got a tab, which I didn't expect at all.  It should have expanded my code snippet.  TAB TAB just got me two tabs and while I could get it using the highly awkward Ctrl + K, Ctrl + X that seemed just as much work as actually typing it so I ignored that.

After much searching I discovered that I need to put the angle bracket first and then I could get my tab completion to work.  This about blows my fragile little mind since one of the best uses of snippets is to avoid typing those silly brackets in the first place.  I can almost see how the decision was made to require a bracket but it only makes sense from a engineering stand-point, not a usability one.  It completely ignores the fact that angle brackets are not the easiest things to type quickly.

My solution to all of this is two-fold.  First, once I get to Microsoft I'm going to hunt down the XAML IDE team and second to stop using Visual Studio 2008 for editing XAML.  I've setup a good handful of snippets in InType and discovered something odd yet not all that surprising: I can build a full XAML UI by hand in Intype faster than I can do it in Blend and much faster than using Visual Studio.  Anyone that hand-codes HTML won't be too shocked by this because it's fairly common knowledge that a skilled HTML coder can bust out a page faster in a good text editor than in Dreamweaver.

I really hope the Visual Studio IDE team is looking hard at the new wave of tools like Intype & E, they really are that much more productive.

1 Comments

I've been putting myself through a crash course on Silverlight\WPF these last few days and here are a few random thoughts.  All of this is after a 60 minute breakneck tour of WPF\Silverlight so I'm more than likely missing a whole bunch of things and probably doing things bass-ackwards but hey, that's why they call it learning.

  • There are three stock layout managers (used for placing controls): Canvas, Stack & Grid.  Where is the CSS-style panel?  If designing web pages has taught us anything it's that the grid quickly gets cumbersome.  Note to self if I get hired at Microsoft: Create a CSSLayoutPanel that uses stock CSS to position the controls.
  • I forgot how painful an experience it is to enter XML in Visual Studio.  I've been spoiled by Intype and E TextEditor where you don't need to enter the opening angle bracket to get code completion.  Also, I must be doing something wrong because entering XML attributes is downright painful in Visual Studio.  This is where I'm stuck:
    • Type "<ColumnDefinition "
    • Type "W", brings up Intellisense
    • Tab to complete, you now have Width=""
    • Type "50"
    • Now what?  How do I get beyond the ending quote without a lot of keyboard gymnastics?  I can press Right Arrow or End but they're not quickly reachable from the home row.  I can just type another quote but instead that'll just add a second ending quote which isn't what we want.  What should really happen is that I should be able to press Tab to tab out of quotes and put the caret one space past the ending quote.  This is how TextMate, Intype and E all handle this and it works wonderfully.
  • There needs to be a nice bundle of XAML specific code-snippets.  The argument that all "real" design work is usually done in something like Blend is crap because even with all the great GUI builders like Delphi, Visual Studio, Dreamweaver, etc. people are still constantly dropping down to the code to get that pixel perfect design so might as well offer up some snippets to make it easier.
  • I'd like to talk to the person that decided that Silverlight's margin property should list margin in "L T R B" order while CSS defines it as "T R B L".  It's not exactly a horrible idea but why pollute the knowledge space needlessly and make people remember two almost identical things?  There are obviously a lot of similarities between XAML and semantic XHTML yet instead of easing the transition by reusing common usage patterns they decided  to make things just a little different.  Annoying.
  • For all my whinging defining UI via a markup-style language is definitely a plus, regardless of the angle bracket tax.
  • I wonder if you could represent XAML or WPF as YAML instead?  Staring at all the XML about breaks my head in two.
  • Printing, is that even a possibility with Silverlight?  How many times have I printed something from a web page with zero control over margins, headers, footers, etc.  Seems some very cool label printing applications could be whipped up in Silverlight as well, CD labels, shipping, etc.

4 Comments

Designed by Free CSS Templates. | Sign in