Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Building a WPF Application: Part 5

ChumChase Table of Contents

About 5pm today I was burnt-out from some difficult work on a particular client's project. Our last four projects have all been WPF with an emphasis on UI and UX. Fortunately, most of these were green field project, but the one I was working on today was not.

What made it so difficult is that the application is practically one big xaml file with all of the logic in the accompanying code behind. It's hard to modify the UI when it is so tangled up with the logic.  <sigh />

So at 5pm, I decided to take a break and work on ChumChase a bit.

Hope I'm not embarassing anyone...Here's a quick overview of what I did:

  • I began a basic 2D view that will be the actual default view for the application. The 3D view is cool, but it's a novelty and not much else. The 2D is really simple at the moment.
  • You can toggle between the 2D and 3D views. The underlying presentation model is the same. It doesn't change. The only code associate with the views is the trackball code for the 3D view.
  • I added profile pictures for the user associated with a feed entry.

Chasing Simplicity

Let's review my thinking process for adding the profile pictures.

I assumed that I could get the url for a given user's profile picture from FriendFriend's API. In fact, it is quite simple.

http://friendfeed.com/nickname/picture?size=medium

where nickname is the user you are interested in. You can provide small or large for the size as well. FriendFeed uses the term nickname where everyone else would use username.

The data template for a individual item on the feed looks like this (simplified for the post):

<DataTemplate>
    <Border>
        <DockPanel>
            <Grid DockPanel.Dock="Left">
                <!-- this image is where the profile pick will go -->
                <Image Width="50"
                       Height="50"
                       Margin="2,2,8,8" />
                <Image Width="16"
                       Height="16"
                       VerticalAlignment="Bottom"
                       Margin="2"
                       Source="{Binding Path=ServiceIcon}"
                       HorizontalAlignment="Right" />
            </Grid>

            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Path=Title}"
                           TextWrapping="Wrap"
                           FontSize="16" />
                <TextBlock Grid.Row="1"
                           Text="{Binding Path=User}" />
            </Grid>
        </DockPanel>
    </Border>
</DataTemplate>

The template is bound to an instance of FeedEntry which represents a single entry in the feed. Notice the binding to User in the bottom TextBlock. That's simply the nickname of the user associate with the entry.

My first thought was to add a new property to FeedEntry called UserProfilePictureUrl and bind it to the Source property on the Image.  This new property would merely inject the value of User into a url and return it. Even though it was simple, something nagged me about this. I felt like it should not be a concern of FeedEntry to provide the url for the profile picture. In addition, I knew that I would need to get the url in other places where FeedEntry was not part of the picture.

In some sense, the translation of a nickname into a profile pic url is standalone. I mean, the concept exists independent of any of the current entities in my model. Because of this, I decided to encapsulate the concept in a value converter.

public class NicknameToProfilePicUrlConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string size = (parameter == null)
                          ? "medium"
                          : parameter.ToString();

        string url = string.Format("http://friendfeed.com/{0}/picture?size={1}",
                                   value,
                                   size);
        return url;
    }

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

Then in the xaml, I used the converter like this (after adding a reference in the resources):

<Image Width="50"
       Height="50"
       Source="{Binding Path=User, Converter={StaticResource NicknameToProfilePicUrl}}"
       Margin="2,2,8,8" />

Notice that I'm actually binding to the nickname (note to self: I should rename User to Nickname). The converter takes the nickname and returns the url. Converters like this are easy to test as well.

This implementation isn't all that robust, but we'll handle that when the need arises.

So how do you feel about having a value converter that is so specific? I find myself using them more and more. Does it bother you to take this approach?

Off to bed...


Posted 11-13-2008 12:58 AM by Christopher Bennage

[Advertisement]

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)