Rebuilding the PDC 2010 Silverlight Application (Part 4)

Following on from that previous post, I thought it might be nice to take a bit of a break and spend a post putting a little effort into making things look a little better in Expression Blend.

Part 4 – Working in Blend

I opened up the solution in Blend (loading up my 12 projects) and the first thing that I wanted to do was to change the background of the whole app and replace it with an image.

This raises the interesting question of where to put resources like this image? Options;

  1. Put them on the site of origin?
  2. Put them into the main shell XAP as content?
  3. Put them into the main shell’s assembly as resources?
  4. Let them go as content/resources into other XAPs or assemblies?
  5. Have a dedicated assembly referenced by the main XAP and put them there?

I went with 5 which leads me to having 13 projects Winking smile This is going to cause me a minor problem.

Dealing with a Minor Problem

I go ahead and create my special assembly for resources. Here it is in Blend added as a new library project;

image

and you can see that this is referenced from my MainShell project so that’s great as this DLL will end up in my main XAP.

I visit my MainShell project and edit my App.xaml to ensure that the PDCTutorial.Resources.xaml file is merged into my resource dictionary;

	<Application.Resources>
		<ResourceDictionary>
			<ResourceDictionary.MergedDictionaries>
				<ResourceDictionary Source="/PDCTutorial.ResourceDefinitions;component/PDCTutorial.Resources.xaml"/>
			</ResourceDictionary.MergedDictionaries>
		</ResourceDictionary>
	</Application.Resources>

and so all is good because at runtime this stuff will show up.

Now, I add a PDC background image to my PDCTutorial.ResourceDefinitions project and I build a brush around it in the XAML resource dictionary;

image

<ResourceDictionary
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
	<!-- Resource dictionary entries should be defined here. -->
	
	<ImageBrush 
		x:Key="backgroundBrush" ImageSource="Images/pdcBackground.png"/>
	
</ResourceDictionary>

Let’s say I now go and open up my Views project and I want to set the background of my LayoutRoot to be this brush that I’ve defined.

The problem is that this Views project is built into a different XAP file and so there’s no obvious link up to the resource dictionary that’s present in my MainShell XAP file and so I’m not going to see any resources to work with Sad smile

Even though those resources will be visible at runtime.

There’s a way to solve this in Blend 4. The easiest way that I can see it is if I hack my MainView.xaml here in order to make it use that resource. For example;

  <Grid
    x:Name="LayoutRoot"
		Background="{StaticResource backgroundBrush}">

Now, Blend is going to moan about this but if I hold my nerve and close and re-open the solution I’ll get;

image

when I open that MainView.xaml and Blend realises that there are resources in use that it can’t resolve.

This allows me to feed Blend with design time resource dictionaries and I can do just that here by feeding it my XAML resource file and then I can see that things resolve at design time which otherwise would not;

image

Blend puts these definitions into a DesignTimeResources.xaml file within the Properties folder of the project that was struggling to resolve the resources. You can also seem them on the Resources tab;

image

That gets me around my minor problem.

The only thing I’d say about this is I’ve a feeling that it adds references between projects that don’t otherwise need them so apply a bit of caution there and make sure your references are all bang on before you ship anything.

Bringing in the Jet Pack Styles

I like the Jet Pack styles so I downloaded them for the 100th time Winking smile from here and I went for the raw assets and added those files to my Resources project;

image

Now, this always seems to cause me problems because these files contain a whole bunch of styles with XAML namespaces that will not necessarily resolve. Specifically, I hit problems with DatePickerTextBox, CalendarItem, DataGridFrozenGrid and a number of others.

What I generally do is to remove these styles as they’re bloating out the XAML files and I’m not using those controls. In fact, the only style that I left in the SDKStyles.xaml file was for a ChildWindow and the only style I left in the ToolkitStyles.xaml file was the BusyIndicator.

I found that I didn’t want Styles.xaml at all so removed that one.

I edited my PDCTutorial.Resources.xaml file so that it included all the other files;

	
	<ResourceDictionary.MergedDictionaries>
		<ResourceDictionary Source="Styles/Brushes.xaml"/>
		<ResourceDictionary Source="Styles/Fonts.xaml"/>
		<ResourceDictionary Source="Styles/CoreStyles.xaml"/>
		<ResourceDictionary Source="Styles/SDKStyles.xaml"/>
		<ResourceDictionary Source="Styles/ToolkitStyles.xaml"/>
	</ResourceDictionary.MergedDictionaries>

and all seemed pretty good.

Styling the Tracks View

There’s not so much that I can do with the tracks view as it just displays a bunch of buttons. However, I opened it up and had a stab at making it look better than it does by default by using some of the resources that come from Jet Pack;

  1. It displays a ListBox and so I grouped that into a Grid with an auto-sized header row and into that header row I put a rectangle and bound its fill to the ControlBorderBrush resource.
  2. I also added a TextBlock to that same grid cell on top of the rectangle and set its foreground to white and bound its font family to the HeadingFontFamily resource and its size to Heading2FontSize and gave it a little margin.
  3. I made sure that my ListBox had no background.
  4. I found that the ListBox ItemContainerStyle from the Jet Pack theme was doing something odd with horizontal content alignment so I made a copy of that style and told it to horizontally stretch the content.
  5. I told the ListBox that it wasn’t allowed to stretch horizontally by setting HorizontalScrollbarVisibility to Disabled.
  6. I found that the BusyIndicator from the Jet Pack theme was doing something odd with the alignment of the busy content so I told it to centre it by editing the template and centering the busy content whilst leaving the non busy content displayed in accordance with HorizontalContentAlignment and VerticalContentAlignment which I had set to Stretch.

and then I styled the TrackView.xaml which simply displays a Button but I bound up the FontFamily to the resource ContentFontFamily and the size to the resource ContentFontSize.

I found that I’d set the ToolTip to a fixed width 192×48 so I addressed that by letting it auto-size but then the colour of the ToolTip was a fairly garish green so I reset that by wandering into my styles as in;

image

and resetting that colour. In doing so I found that there was a green highlight that I couldn’t get rid of and so I also edited the template for the Tooltip where the green seemed to come from a TopBorder element. I got rid of that colour.

With that done, my Tracks view looks like;

image

Styling the Sessions View

My SessionsView is also a BusyIndicator wrapped around a ListBox. I did a few basics;

  1. Made sure the BusyIndicator stretched itself as adding the Jet Pack theme seemed to have caused it to center itself.
  2. Made sure that the “LayoutRoot” grid was set to have no background along with the ListBox itself.
  3. Added a containing grid with a header in the exact same way as I did for the Tracks view.
  4. Made sure that the ListBox would not scroll horizontally by setting the HorizontalScrollbarVisibility to Disabled.
  5. Added a little margin to the ListBox itself.

I then wanted to work on the ItemsPanel for my ListBox. I editing the template and first changed the panel to be a WrapPanel;

image

and I wanted to make sure that items within this panel would perform fluid layout and so I added a FluidMoveBehavior to the panel;

image

and set up the properties so that it tracked the DataContext;

image

I also wanted my items in this particular ListBox to animate in/out of their positions and so I made a copy of the ItemContainerStyle (because I didn’t want this to affect any other ListBox) and edited its BeforeLoaded/BeforeUnloaded states to change the opacity to 0 over a 2 second period and to also apply a pixelate effect (this is going to be over the top);

image

With that set up it’s time to go and style the SessionView itself which is effectively the ListBox item for the sessions list.

I cleared the previous contents where I’d thrown the kitchen sink at the view and started from scratch with a Border that I set to a fixed width and height and applied a little margin too;

image

However, this is going to be tricky as I have no data to work with at design time and so it feels like time to add a little design time data into the project to make it easier.

Into the SessionView document, I added design time data based on the SessionViewModel;

image

and that raises the dialog that lets me choose the view model;

image

and gives me sample data to work with;

image

I tweaked some of the facets of this data to make it look more like the data I’m working with and with that done I’m able to go back to the designer for my SessionView and start to figure out how to display the bits of the data that I want.

The first thing I did was to set the background of my Border to be an ImageBrush with the Source data-bound to the ThumbnailUrl property. The images are now coming from my sample data;

image

and the next thing I want is the code and title of the session displayed somewhere so I figured I’d display them up at the top.

I added a sub grid with a background Rectangle and set it to align itself to the top and added two automatically sized rows with TextBlocks in them which were bound to Code and Name respectively from the data binding (this is easy with the design time data set up).

I set the TextBlock so that it didn’t wrap and so that it did text trimming and I also set the Tooltip to display the full Name in case of overflow.

I also set up the Tooltip for the whole border to display the Description of the session from the view model but then I found that I really didn’t like my tooltips;

image

Tooltips are way too wide and way too blurry. I went off and opened up CoreStyles.xaml and found the default ToolTip style and edited the template within there to remove the DropShadowEffect being used and also to set a maximum width on the root grid being used for the ToolTip.

image

It’s worth saying that I found 2 elements with drop shadow effects in that template and removed them both.

Even with that done I still wanted to get to the TextBlock within the ToolTip to tell it to Wrap and so I found that I needed to use a bit of XAML for this because I don’t know how to edit ToolTip content in Blend so I dropped a;

		<ToolTipService.ToolTip>
			<TextBlock Text="{Binding Session.Description}" TextWrapping="Wrap"/>
		</ToolTipService.ToolTip>

onto my Border and that gives me slightly nicer ToolTips;

image

I also noticed that my ListBox items here are highlighting themselves when selected so I edited the ListBoxItemStyle and the states within to take away the state transitions;

image

I also wanted to make sure that I had a picture of the presenter and their name in this view so I added a StackPanel with a Rectangle with an ImageBrush with ImageSource bound to the Speaker.ImageUrl and a TextBlock with text bound to the Speaker.Name property.

I also added a drop shadow onto the rectangle.

image

I realised that Speaker.ImageUrl is null in a lot of cases which leaves an empty rectangle and so I wanted to provide a TargetNullValue for the binding here so I added a new image to my PDCTutorial.ResourceDefinitions project, and used that as the TargetNullValue on that binding. I don’t know of any way to do this in Blend so I edited the binding;

  <Rectangle.Fill>
            <ImageBrush
              Stretch="UniformToFill"
              ImageSource="{Binding Session.Speaker.ImageUrl,TargetNullValue=/PDCTutorial.ResourceDefinitions;component/Images/anonSpeaker.png}" />
          </Rectangle.Fill>

my Session view wasn’t looking too bad at this point although some of the effects are bit too much;

image

Adding Checkboxes for Content Download

The last thing I wanted to do in this particular post was to add some CheckBoxes that offer the user the option to download (or not) the particular types of content that are available.

I added a StackPanel with 3 CheckBoxes to it to the bottom of my Grid;

image

I want to control the visibility of these items based on whether the underlying view model says we have PowerPoint/HiDef/LowDef and there are already bindable properties there for that but they are of type bool rather than of type Visibility.

I could make use of converters here or I could go with extra properties on the view model that do the conversion – I decided to go with adding properties to the ViewModel;

  public class SessionViewModel : PropertyChangedNotification
  {
    public Visibility ShowPowerpointDownload
    {
      get
      {
        return (BoolToVisibility(this.Session.Content.HasPowerPoint));
      }
    }
    public Visibility ShowHiDefDownload
    {
      get
      {
        return (BoolToVisibility(this.Session.Content.HasHighVideo));
      }
    }
    public Visibility ShowLoDefDownload
    {
      get
      {
        return (BoolToVisibility(this.Session.Content.HasLowVideo));
      }
    }

and then I can just bind to that straight from the view in Blend;

image

and so the checkboxes now show up as/when that particular type of content is available.

Those checkboxes need some different content rather than just a piece of text.

I found a folder icon in the Visual Studio 2010 image library and made use of that;

image

but then I want to take away the default visuals which put the little checkbox to the left of the content so I edited that template;

image

Now, I want a much simpler template than this. I don’t need all the complexity and so I refined it;

image

and I simply display the green arrow when the CheckBox is checked and I hide it and fade out the parent Grid a little when the CheckBox is unchecked.

So, we’ve come a little way in this post to making things look a bit better;

image

What’s Still Missing

There’s a bit of work to do here yet including things like;

  1. Add some UI that allows for an easy way to select “All Powerpoint” or “All Hi Def” or similar.
  2. Build some kind of downloading component.
  3. Build the download view.
  4. Capture the user’s selections for download and feed them through to the download component – at the moment, those CheckBoxes don’t bind to any real data.

Where’s the Source?

Here’s the source code for download.

What’s Next?

Perhaps that UI that makes it easy to select “All Powerpoint” or “All Hi Def”…