Hello World


Friday, June 6, 2008

MIX08 Session: Applications = Designers + Developers for WPF and Silverlight

This is a Big Tutorial. So get a JUG of Coffee Handy.

Last week I reviewed some of the sessions from MIX08.
I was most impressed with the MIX08 CT06 Session: Applications = Designers + Developers held by Celso Gomes and Kirupa Chinnathambi which dealt with Re-Styling a ListBox. The FurnitureShowroom example showed how to completely change the style of a ListBox.
Here's a link to the Video session: MIX08 CT06 Session: Applications = Designers + Developers
Have a look at the Video before attempting this tutorial, it will give you a good overview.

The following screen shot is from Celso's and Kirupa's WPF application with a completly re-styled ListBox (Look Ma! "no scroll bars").


Even though the session gave a good overview of how to create a really nice application using WPF and Expression Blend and Design, I got a bit lost with the Control styling part. I thought that was the most interesting part of the demonstration, but that’s me, I look for the tricky stuff.
Celso had created these styles beforehand so we did not get to see how he did that. But still a fantastic example of WPF power.

I thought I would try and replicate what they did using the fabrikam sample data.
I was able to produce a similar example and also pull apart the ListBox and re-style it.
Here's the low-down on how to re-style a ListBox to resemble Celso's. I didn't write any C# code for this example it was all done using Expression Blend.

Pre-requisites first : I used the following tools.

  1. Expression Blend 2
  2. Visual Studio 2008 (3.5)
  3. Platform Windows Vista Ultimate
Here's a Link to Expression Blend: Expression Blend 2 Download
A bit of an Overview first.
For most controls, there is appearance and behavior. Consider a button: appearance is the raised area that you can press, and the behavior is the Click event that gets raised in response to a click. Sometimes, there may be a control that provides the behavior that you need but not the appearance that you need. You can use style setters to set property values to affect the look of control. However, to change the structure of a control or to set property values on the components that comprise a control, you need to use a ControlTemplate.
The data and UI you see in the above form is really a reconstructed ListBox control with re-styled ListBoxItems. The scrollbars have been disabled and re-styled so we still get the same behaviour as a ListBox but without the look. (We want the Engine but not the Body)
Quote:
Windows Presentation Foundation (WPF) styling and templating refer to a suite of features (styles, templates, triggers, and storyboards) that allow an application, document, or user interface (UI) designer to create visually compelling applications and to standardize on a particular look for their product.
(What a Mouthfull); straight out the book, but basically that’s it in a nutshell.
The question is how? Usually something so powerful as the above quote requires time and patients’ to get real handle on, especially when you are designing a unique UI, you need to understand the technology to do the job right. Well WPF has the power to create any type of UI you can imagine.
But it helps to have HELP.
OK enough babble lets get to work.
I am not going to go into the basics of styles and templating, you can read WPF SDK docs for that information. I just want show how to turn your every day WPF ListBox into something like Celso's.
Below is my application using the fabrikam data. You will notice the default ListBox. Typical ListBox stuff. Scroll bars and Items one below the other.

So to get a UI like the Furnitureshowroom example we need to change the default style.

Go to the end of this tutorial to see the finished product.

In my fabrikam application, we have a ListBox control that is bound to a list of images and text. I used the fabrikam XML file for my data source and the images that are part of the fabrikam tutorial.
In WPF, you use a DataTemplate to define the visual representation of data. Basically, what you put into a DataTemplate determines what the data looks like in the rendered application.
So lets give our ListBox a new DataTemplate so we don't have this list collection look. If you have Microsoft Expression Blend it makes this a whole lot easier. So I will asume you have it and use that tool to change the XAML.
Open up Expression Blend and create a new WPF .exe application named "CustomListBox".
Double Click the LayoutRoot object in Objects and Timelines so it is highlighted yellow.

Click on the the Asset Library and find the ListBox control. Draw a ListBox on the area. Its usually drawn inside a Grid container.
Locate some data. You can use the fabrikam XML file and the images as your data source. You will need to create an images directory in your project and copy the images from the following ZIP file into that directory to map to the fabrikam XML file structure.
Here's a Link to the Fabrikam data

Download the fabrikam XML Data and Images
Once you have your ListBox you need to bind your datasource to it.
Under Projects and in the Data section you will notice the +XML item. If you click that, you can locate your XML data source and attach it to the Project. The new DataSource can now be bound to your ListBox. Expand the +XML datasource untill you see the Product Array item as the following image shows.

Drag the Product (Array) item onto your ListBox. Dont worry all the fields will follow. A small dialog will be displayed, select Bind Product to ListBox and Select Field is ItemSource and Click OK and Click OK again to close this form.
Good your DONE!

Now to the good stuff. D
ouble click on the ListBox control so its is highlighted yellow.
Right click and select the submenus as the following image shows. You need to get to the ListBoxes ItemTemplate.

The next image shows the current DataTemplate.
Notice the StackPanel item. It has a group of TextBlock controls under it.
This is your DataTemplate.

Our data from the fabrikam sample has real images but you will notice that the default ListBox shows the text path of the image not the image itself. How about we change that first. Delete the TextBlock item in the StackPanel that holds the image path details and replace it with an Image control, you find the Image control in the Asset Library. Next we need to bind the Source property of the image control to the Image element in the XML Datasource.
Your StackPanel should look like the one below. The Image control replaces the TextBlock.

Next select the Image control and under Common properties click the little yellow icon on the right to bring up the DataBinding Menu.

Click the Data Binding menu item to display the Create Data Binding form.

Click the Image element in the Products Array and click Finish.

Cool your almost there.
Test it. Select Control + S to save your Project and Press F5 to run.
Should see something like the following screen shot.

But still nothing Like Celso's style right.


OK I'll get to the point.
We need to create a new DataTemplate to hold our list items. Go to the Project tab and right click on the Project name and select Add New Item. We will add a new Window to hold our template. Once the new window is created double click on the LayoutRoot object and Delete it. Next add a new Canvas to the Window object (Canvas's are in the Asset Library). We are going to add 4 new controls to the Canvas item of the new Window. First double click the Canvas item so it is highlighted yellow. Then right click on it and rename it to NewTemplate. While it is still highlighted add 3 new TextBlocks and 1 new Image control. Rename the controls to match the following screen shot. It should look like the following.

Next right click on the NewTemplate and copy it to the clipboard. Go back to our main Window where the ListBox is and confirm we are still in the ItemTemplate of the ListBox. If somehow the breadcrumb has vanished double click on the ListBox control so its is highlighted yellow. Right click and select the submenus as the following image shows. You need to get to the ListBoxes ItemTemplate.

We should by now have an empty ItemTemplate, you can remove this altogether and replace it with your own. Delete the StackPanel with all its controls. It will look like the following shot. Don't Delete the ItemTemplate we will want that to hold our DataTemplate.
Now with the ItemTemplate selected right click and Paste the the NewTemplate we created in the new window into the ItemTemplate. Resize the new template to fit in side the layout of your panel. Your Objects and Timelines view should look like the following shot.

Now this where the fun begins. If you run it here you will not see any data because we have not bound the template controls to the datasource. Remember this is a new DataTemplate we are building, the bindings we had before were lost when we deleted the old stackpanel. So we have to bind the controls in the NewItemTemplate to our DataSource.
Its pretty easy.
Click on the Name TextBlock. Under the Common Properties section in the Properties Editor, locate the Text attribute and click the little yellow icon on the right. Click the Data Binding menu item and the Create Data Binding form will be displayed. Expand the fields tree untill you see the Name field, click it, and select Finish. Do this for all the TextBlock controls. With the Image control its the same proceedure but the binding is done with the Source property.

With all the Controls now bound to their datasource counterparts you can run the application, Press Control+S to Save and F5 to Run. It should resemble the following shot
.
I know, it doesn't look much different than the previous one. I just wanted to demonstrate how you can create a new DataTemplate. I'll leave the Bells and Wistles to You.


If you scroll you will only see one item at a time, not the list as in the first instance.
So we have finished creating a new DataTemplate and assigned it to the ListBoxes ItemTemplate. A new DynamicResource named ProductTemplate exists and below is the syntax on the assignment to a ListBox. Itemtemplate="{DynamicResource ProductTemplate}" Click on the following image to see the DataTemplate XAML.

Not Finished YET. We now have to create a new ItemContainerStyle. In WPF, the ControlTemplate of a control defines the appearance of the control. You can change the structure and appearance of a control by defining a new ControlTemplate for the control. I am not going to copy the design of the FurnitureShowRoom but I will try to copy the behaviour. That is, we will create a ControlTemplate for a TargetType="{x:Type ListBoxItem}" and also pull apart the ListBox VerticalScrollBar and extract the bits we need and hide the rest.
First thing to do is get rid of that selection background when we click on a list item. The blue color can be changed to any color you like. But I think we wont need it because we are not going to use the scrollbar at all. At least not the way you think.
What we need to do so we don't have the blue background when an item is selected is change the Background color on the IsSelected Trigger property.
To drill down to the ItemContainerStyle Click on the ListBox and select the menu items in the screen shot below to get down to that level.

(TIP: To get back to the ListBox root, click the icon in Objects and Timelines).


Next right click on the ItemContainerStyle and select the menu items as the following screen shows.

Next click on the ContentPresenter object in the Template and then click the IsSelected property in the Triggers section. You will see in the Properties when active section displayed and the Bd.Background = #FF454545 property. We need to set this value to either an opacity of 0% or change the value to your background color of choice. If you click on the Bd.Background property you will see the main properties in the Properties Editor change to reflect the current state.
TIP: If you want to get to a particular property you can search for it by typing the property name in the search textbox provided, as shown below. This will display the Properties editor where you can modify the values. For now set the A color of the Background color to 0%.
Press Control+S to and F5 to test your changes. you should see no change in the Background of the selected item. If you need to roll back to the original settings keep pressing Control+Z until you get back to the start. If you have a neutral background leave it there and get back to the ListBox.
TIP: To get back to the ListBox root, click the icon in Objects and Timelines.
Open up the XAML code view and search for the new ControlTemplate of TargetType="{x:Type ListBoxItem}, this is your new style for the Selected ListItem. The following screen shot shows the XAML that was created from the previous exercise.




At this point you might want to get another Jug of Coffee.

Next we will grab the Up and Down buttons that a part of the VerticalScrollBar and replace them with our own. Like in the FurnitureShowRoom screen shot.
We want to re-style the control below so as to use the Commands for the up and down repeatbuttons but be able to locate those buttons any where on our form and not in the scroll bar itself. That means we have to hide the scroll bar and re-style the templates that hold the repeatbuttons. So we will need to drill doen to the PART_Track of vertical scroll bar.

First: Click on the ListBox object in Objects and Timelines so it is highlighted. In the Properties Editor type scroll in the Search box. This will display the Layout properties for the Horizontal and Vertical Scroll bars. Select the HorizontalScrollBarVisibility property and Disable it. This will prevent the bottom scroll bar from being displayed.

Next: We are going to create a new ControlTemplate of TargetType="{x:Type ListBox}" and re-style the ScrollBars particularly the ScrollViewer by creating a ControlTemplate of TargetType="{x:Type ScrollViewer}"
We are going to create a Style resource with a Key named ListBoxStyleScrollBarModify.

Right click on the ListBox control in Objects and Timelines and follow the menu selection in the screen shot below.

Type Name the style as follows.

Basically what we need to do is set the ScrollBarBackground to Transparent, hide the Thumb and re-style the RepeatButtons.
With our ListBoxStyleScrollBarModify created lets begin.

First: we will set the ScrollBarBackground to no brush and hide the Thumb.
Right click on [ScrollViewer] and select the following menu items.

Click OK to the Control Template Resource name ScrollViewerControlTemplate1.
Now we should see a Grid with the PART_VerticalScrollBar. We need to hide the Background of this part.
Next: right click on the "PART_VerticalScrollBar" and select the menu items as follows;

Except the ScrollBarStyle1 name and press OK.
We should now be at the level that makes up the Control Parts.

Click on "Bg" under Template, and in the Properties Editor locate the Background brush and select No Brush. This will make it Transparent. You may have to click on the the little icon on the right of Background Brush and select Reset in the context menu, but basically you need to have the Background set to No-Brush.

Click on the Part_Track.
Go to the Properties Editor and scroll down untill you find the Visibility property.
Set it to Collapsed.
If you run the application now all that should be visible are the two RepeatButton controls.
Next: right click on the RepeatButton and follow the menu selection below.

The Template for the RepeatButtons is as follows.

Next: Click and delete the default style named "Chrome".


Now there is one problem. We have an empty Template so we can't just add our new Buttons to it, we have to add a container first. So double click on the Template object and select a new Grid control from the Asset library.

We will add a Grid to the Template. You can either draw the Grid in the Template or double click on the Grid control from the Asset library so it is placed inside the RepeatButton's Template.


It should look like the following screen shot.



Next: I created a Path object to represent my new RepeatButtons.
It is basically the Left Arrow from Celso's FurnitureShowRoom sample.
Click on the following image to view the Path XAML.


You can use this to place inside the Grid container.
Let's create a temporary window to hold this piece of XAML.

First: Select the Project name "CustomListBox" right click and Add New Item. We are going to create a new window and replace the Grid XAML with something like the above image.
If you use the above XAML and go to design view you will see an arrow.
This is going to be our new RepeatButton ControlTemplate Style.

Next: With your arrow created and while in design view, click on the arrow_left object and Copy it to the clipboard (Make sure you don't grab the attached Grid). We only need the arrow_left XAML object.

Next: Go back to the RepeatButton Grid in your main form and double click on the Grid under the Template and Paste the arrow into the Grid.

I do it this way so we are not working in XAML view. Its easier to do this stuff in design view.
It should look like the following screen shot.


Zoom in on the top RepeatButton area by holding down the Control Key and then use your mouse wheel to Zoom in or Out.

If you can't see the Arrow in the Grid, Zoom out and Right Click on the Arrow and Select Auto Size/Fill from the context menu. Drag it into the Grid if required. But it should be a sub-control in the Grid of the RepeatButton Template.

The following screen shot is what you should see. Our new Arrows are the RepeatButtons.


Next: We need to make a few changes. They are both Left Arrows, we need to make one a Right Arrow, and they are still in the wrong location. Lets fix that NOW.

Click on the RepeatButton as the following screen shot shows.

The Arrow should now be hightlighted like the one below.



Next: Drag the Arrow over untill it resembles the following screen shot.

Next: Repeat the proceedure for the Right Arrow. Drag it over untill it is lined up on Top edge but about 50mm apart.

Next: While the right arrow is still highlighted Flip it Horizontally. The following screen shot shows how.

This is only required to display it correctly, it's behaviour is already set. Right Arrow = Down , Left Arrow = Up.


Before we get to carried away we need to change the cursor to Hand and the rollover area on the Arrow needs to be a larger.

First: Right click on the RepeatButton and select Edit Control Parts (Template)/Edit Template, then double click on the Grid.

In the Properties Editor, change the Background on the Grid (NOT the Arrow) but the Grid, to have a Background Brush of Black or some color.
With the Background Brush set, change the the A color of the Background to 0% opacity.
We need the background to have a 0% opacity otherwise the Arrow may be hidden by the Color.

Next: Find the Cursor property on the Grid and change it to Hand.

Now when you MouseOver the Arrow it should respond without being exactly over the Arrow.

You should only need to do this on one of the Arrow Grids, as the other Grid will inherit the changes.

OK Your ready to Roll.

Test it: Control + S to Save and F5 to Run.

Your form should resemble the following.
If you click on the Arrow's you should get the same up and down behaviour as the default scrollbar.





Summary:

We started with a default ListBox, that displayed a typical list view.

XAML gave us the flexibility to completly change the UI of the ListBox control.

By Creating a new DataTemplate we could display an Image in our list.

Then we created an ItemContainerStyle to modify the IsSelected trigger so we didn't see the default blue background when a list item is selected.

And finally we created a new Style to override the ScrollBar UI.

By doing these three tasks we were able to completly change the appearance of the ListBox UI without any C# or VB.Net code.



Conclusion:

Expression Design has a Template for the Fabrikam layout. By exporting that template to XAML I added some bells and whistles to the above form and ended up with the following.



Goto a Fabrikam Product Tutorial

4GuysFromRolla.com Headlines