Introduction
Welcome to my seventh beginner's tutorial for Expression Blend and Silverlight. This time, we will be looking at Styling the Generated Content of a ListBox via Additional Templates, and I will do my best to guide you through this.
Again, before commencing this tutorial, I recommend that you read my previous CodeProject tutorials. I am writing them as a series, and as such, this tutorial will presume prior knowledge.
What have we covered so far?
In the last part of this tutorial, we discussed Control Template and how this effectively makes up the Border/Framework/Stage of a ListBox
. We Styled these elements (mainly the ScrollViewer
s) to suit the ListBox
's intended use/surroundings, whatever they may be... I have no idea either, so I threw a frame around the application to give it some context. But if we look back at the previous tutorial, we can see this just highlights that the Content of the ListBox
and TreeView
are not really matching the new Style
.
The yellow Folders icon in the TreeView
doesn't really fit the colour scheme, nor does the blue hyperlink text in the ListBox
. Also, when the application is run, we have pale blue MouseOver States for the files and folders. As well as a rectangular selection area on the ListBox
that spills outside of the bordered panel that frames/holds it (the ScrollContentPresenter
). Now, absolutely nothing in the Control Template of the ListBox
will have any bearing or affect on the problems/issues I have just raised. The reason for this is because the Control Template has nothing to do with the Generated Content of a ListBox
, TreeView
(or any other Control
). All it does, is set the Stage (Framework/Border) of the Control
and hold the ScrollContentPresenter
, which is the portal to the imaginary world of Generated Content. I call it imaginary, because without any Content, it's all invisible! So thank whoever you may pray to for Sample Data, as it truly is wonderful for designing UI on Generated Content. Alternatively, you can have a word with your developer, who can create a specific Design time sample data source, like defwebserver has here.
Quick overview of Additional Templates
Let us have a look at the Additional Templates of a ListBox
and try to get our head around what each one does.
Basically, we have three extra Templates that control and manipulate the Generated Content that appears in the ScrollContentPresenter
. Each has a different job or goal in presenting and formatting the Generated Content and Data. Below is a simplistic UI Designer oriented diagram of the Template relationships.
Simplistic ListBox Template diagram - Intended for designers, not programmers!
Items Panel Template
What we basically have is the Item Template and Item Container Style Template within the Items Panel Template. Even though the Item Panel is the third in the list of available Templates, it is "sort of" the parent of the other two Templates, as it defines how they will Layout as a whole. This could be as a StackPanel
(default), a WrapPanel
, or maybe a DockPanel
. Basically, anything that inherits from the Panel
class. You can also specify a Grid
or maybe a Canvas
, but there is little point, as each instance of the Item Template will just appear on top of one another...
At the risk of repeating myself: the Items Panel Template is the Panel
that the ListBox
uses to layout the Generated Items that are defined in the Item Template. By default, this is a StackPanel, but this can be changed depending on your data and requirements.
The most light reason to edit the Items Panel Template is to change the orientation of the StackPanel
from Vertical
to Horizontal
. Or possibly, make it a WrapPanel
, but be warned, this can cause issues with selection navigation. (I'm waiting for a friend (Jason Young) to blog his solution to this issue, so will update when available!)
Item Template
This is where we arrange the different elements that make up an instance of the Generated Content. This could be something like an Icon
/Image
, with a Title
, an accompanying Description
, a CheckBox
, etc... You name it, it could possibly be one of the elements that could be laid out in the Item Template.
In our application, defwebserver has setup an Image
and a HyperlinkButton
in a Horizontal StackPanel
.
This example is probably as basic as it gets really, and there is nothing stopping us doing a lot more, which we will cover later in this article.
Item Container Style Template
This is easily the most interesting of the three available Templates, and where all the magic happens. As this is where we entertain and interact with the user to produce visually appealing animations and effects!
The default setting for this Template is shown in the image above. And along with some Rectangles for various visual States, we have a ContentPresenter
that gets its input for the Item Template. Notice that next to the "Return Scope" icon, this Template is actually called "ListBoxItem Template", and in the screen grab for the Item Template section above this, next to the "Return Scope" icon. It is actually called the "ContentPresenter Template". Ignore the "SilverlightFileTemplate", as defwebserver created this name when he edited a copy of the original Template. So you could say that the arrangement of the Templates as shown in the diagram earlier should be more like the diagram below:
No matter how you want to look at it, we are most likely to be interested in the Item Template to layout our Generated Content, and the Item Container Style Template to interact with this Generated Content. We manipulate the Item Container Style Template using the Visual States Manager (VSM), and as the image below shows, we have more State Groups than we have covered before, when dealing with buttons...
The obvious addition is a State Group called "LayoutStates
" which, as you would expect, can be used to control the elements within this Template during their Loaded
and Unloaded
States. Not so obvious is the addition of Effects in Blend 4, which allows for some funky transitions between States in a State Group.
Another thing to consider with the Item Container Style Template is that it has an associated Style applied to it, and this is different to the ListBox Control Template Style.
Therefore, a ListBoxItem
can have a different Style applied to it, while still using the same surrounding ListBox
. So rather than having a whole new ListBox
with different Generated Content interaction, colours, and styles, it is possible to just pass the ListBox
a new ListBoxItem
Style to change the interaction, colours, and Template elements..
Overview summary
So those are the three Additional Templates of a ListBox
as an overview, and if this is the first time you are looking at these, it may be a little confusing. So the best thing to remember is that these Templates are not really equal, that you may have presumed it by their listing in the Additional Templates. They are basically nested within one another, but in the reverse order as shown in the list of Additional Templates.
Basically, follow the Content Presenter, all the way from the ScrollContentPresenter
of the ScrollViewer
in the ListBox Control Template into the Items Panel Template (which is also known as the ItemsPresenter Template). This then leads to the Content Presenter of the ItemContainerStyle
, which gets its Generated Content from the Item Template. So if we look at our diagram again, we should look from the centre outwards, to get our heads around how the Generated Content is Presented and Styled.
Also, the purple sections of the diagram signifies where Styles are placed within the ListBox
control. Please appreciate once again that this is a simplistic "Designer" oriented view of the Additional Templates.
Let's get stuck in!
To make a start at editing some Additional Templates, I will take over from defwebserver's Drag and Drop File Manager article, using this as a starting point to format the Generated Content via the Additional Templates.
To keep things interesting because I was getting bored of it, and to free up more "real estate", I've changed the look of the application again. So it has a thinner frame, collapsed rivets (not removed), and a new blue colour scheme.
I have also Styled the GridSplitter
with a few rivets, and integrated it with the PictureFrameControl
. And the ones of you with eagle eyes will have noticed I've Styled the TreeView
a little with new expanders and folder icons. Which I have only done so not to detract from the application while we work on the ListBox
.
So download the updated application from here and we can make a start!
Items Panel Template
Let's look at this Template first, as it is the least interesting of the three, and in a lot of cases will probably not need any editing at all. Select the ListBox
, and choose Edit Additional Templates > Edit Layout of Items > Create Empty.
Call the Template something like "ListBoxItemsPanelTemplate
" and hit OK.
Now if we look in Objects and Timeline, we can see that this is an ItemsPresenter Template, and as I said earlier, this Template controls/defines the layout of the area set by the ScrollContentPresenter
in the Control Template.
As the image above shows, all we have in the Items Panel Template is a StackPanel
whose default orientation is Vertical
.
So select the StackPanel
and change the HorizontalAlignment
from "Vertical
" to "Horizontal
", as shown in the image below.
This should change the ListBox
in the Artboard so that only the first Generated Item is visible in the ListBox
. The other Generated Items are now to the right of this first Item, as one long stream. Which is great for maybe a Ticker Tape application, where items scroll from right to left, or left to right, but not really right for this application. The other really cool thing about the Items Panel Template is the ability to change the Layout Style to a WrapPanel
. Which I won't do here, as it deserves more than a quick explanation, and if you are unsure about what a WrapPanel
can do, check out this video from Microsoft Mix10.
Now change the StackPanel
's HorizontalAlignment
back to "Vertical
", and come out of the Items Panel Template.
(And in the words of Officer Barbrady (South Park) "Move along people, there's nothing to see here")
As that is pretty much it for the Items Panel Template!
Item Template
To break with the order, I discussed the Templates in the Overview section. We will look at the Item Template before we address the Item Container Style Template. If you have been paying attention and taking onboard what I have said so far about Templates, you should realise that in order to Style the Generated Content in the Item Container Style Template, we first should format the Generated Content in the Item Template.
defwebserver has given us some Generated Content in this application, but to properly demonstrate what we can do in the Item Template, I would like a little more Sample Data to play with, which I have already setup in the downloaded project.
So go to the Data tab, select "Collection", and drag this onto the ListBox
in the Artboard.
This should change the Sample Data for the ListBox
, to hopefully the same as the image below.
We now have a lot more Generated Content, but currently it is a mess and jumbled up.
So select the ListBox
and choose Edit Additional Templates > Edit Generated Items > Edit Current.
This will take us into the Item Template, which shows all the Sample Data within a StackPanel
.
Now to make things a bit clearer, rename the items as shown in the image below.
(The Sample Data has been imported in the same order it appears in the Data tab.)
The first thing I want to do is change the StackPanel
Orientation
to Horizontal
and change the general Layout of these items, so that they Stack left to right.
In the Artboard, you should hopefully now see a CheckBox
, with an Image
to the right of it and some Text
to the right of the image.
Now in Objects & Timeline, drag the image above the CheckBox
to change the order they are displayed in the StackPanel
.
With the Image still selected, change the size to 32 for both the Width
and Height
to reduce the size of the image.
Now select both the ItemDescription
and ItemTitle
elements, right click and choose Group Into > StackPanel.
Drag the new StackPanel
above the "Buy" CheckBox
in Objects & Timeline, to change the ordering of the parent StackPanel
.
Expand the child StackPanel
, select the ItemTitle
, and drag it above the ItemDescription
element to change the ordering of this StackPanel
.
Select the StackPanel
directly above the ItemTitle
, change the Orientation
to Vertical
, and set a Margin
of 4 for the left side only.
(Ensure that the Width
and Height
of the StackPanel
are set to Auto
).
Now select the ItemTitle
, change the Font
to Bold and the size to 7 pt.
So we now have a Horizontal "parent" StackPanel
with elements laid out left to right. And in the middle of these Horizontal elements, we have a Vertical StackPanel
with one element laid out below another. Hopefully, you are starting to see what is going on in this Template, and have noticed that as we edit the top Item Template, all the instances of the Item Template displayed below automatically update with our edits to the Item Template. You should also be appreciating how useful a StackPanel
can be with regards to Layout, and I will now do a little more to demonstrate this. We still have three elements that are not visible in the Item Template, as they are to the right of the StackPanel
containing the TitleDescription
text, and hence off the end of the screen. So we need to format the TitleDescription
text so that it will Wrap and take up less Horizontal space. But I also want the ItemTitle
text length to be uninterrupted and to flow across (above) all of the other following elements (independent of the ItemDescription
text).
So select the ItemDescription
element and choose Group Into > StackPanel, and set the StackPanel
Orientation
to Horizontal
.
Select ItemDescription
again, change the Font size to 7 pt, and in Advanced Properties, change TextWrapping
to "Wrap
".
Now change the Width
of the ItemDescription
element to 140, and ensure the parent StackPanel
Width
is set to Auto
. Select the Buy
, StockQuantity
, and StockTitle
elements together, and choose Group Into > StackPanel.
Ensure the StackPane
l's Orientation
is set to Vertical
, and rearrange the order to StockTitle
, StockQuantity
, and Buy
.
Next, drag the latest StackPanel
inside of the StackPanel
above it in Objects and Timeline so that it is directly below the ItemDescription
, as shown in the image below.
(Ensure the Width
and Height
of the newest StackPanel
are set to Auto
, and the Margin
s are set to 0).
Select the StockTitle
element, change the Font size to 7 pt, and make the text Bold. Now change the StockQuantity
Font to 7 pt and make the text Italic. This should result in something like the image below when the application is run:
(I have changed my ItemTitle
text to 9 pt to show clearly that it flows over and across the child StackPanel
, within it, and below it.)
Hopefully, I have demonstrated the Item Template enough for you to see this Template is all about Layout. As well as the flexibility of the StackPanel
within the Item Template. Obviously, we could space out and format our items further using Margins, and grouping elements into Grids. But I will leave you to play with this further... (Edit the current elements, add some more elements, and format all of these as you see fit.) I, however, need to move on to the Item Container Style Template!
But before we start on the Item Container Style Template, I want to discard all the changes we have made so far. These were just for demonstration purposes, and not part of the ongoing application that defwebserver and myself are developing.
So reload the original unedited project and once again go to the Item Template of the ListBox
.
Now in Assets, find the "PageIcon
" that I have "quickly" created, and insert a copy of the PageIcon
into the StackPanel
.
Set the size of the PageIcon
to 14 pixels in Width
, and 16 pixels in Height
. In Objects and Timeline, rename it to "PageIcon
" and drag it to the top of the StackPanel
list, above the Image
and HyperlinkButton
.
In the Artboard, we should now have two "Page" icons.
The blue one I have created is more suited to our project. As well as editable, to change colour along with our project. So delete the second white PageIcon
, as this is no longer needed. On the remaining PageIcon
, set a Margin
of 4 on the Left
side to space it away from the edge of the ListBox
. Now select the HyperlinkButton
, and also set a Margin
of 4 on the Left
side, to space it away from the PageIcon
. Change the foreground colour of the HyperlinkButton
to Black
, to make it match the text colour of the TreeView
items.
(The HyperlinkButton
can be edited further if needed, via its own Template and Style.)
Now we just need to set some free space above the list of items in the ListBox
, so select the StackPanel
and set a Margin
of 9 to the Top
. But because we are applying this Margin
to the Item Template, this Margin
is applied to every Item
, spacing them all out.
We cannot set a Margin
for just one Item
in the Item Template, everything we do here will apply to every item. So instead, change the Top Margin to 0 and the Bottom Margin to 1 (to give each Item
a little spacing and to match the TreeView
item spacing).
Now go to the ListBox Control Template, select the [ItemsPresenter] and set a Top Margin of 8.
That should hopefully space the Top of the items as a whole, and not each individual item.
Item Container Style Template
This is the Template I have been looking forward to discussing, and partly why I have left it until last. But before we get to the more advanced and interesting parts of this Template, we need to do some basic formatting for the MouseOver and Selected States.
So select the ListBox
and choose Edit Additional Templates > Edit Generated Item Container > Edit Current.
(Or Edit a Copy of the Template if you choose).
In Objects and Timeline, select the fillColor
element.
Now go to VSM, select the MouseOver State and change the element Opacity to 100%.
In the Artboard, the first item should now have a pale blue background, as shown in the image below:
Go back to the Base State and select the Eye symbol next to the MouseOver State.
(This will allow us to edit the fillColor
element, without setting any Keyframes.)
Change both the X and Y Radius for the fillColor
Rectangle
to 5, to round the corners of the Rectangle
. Change the Left and Right Margins to 3, and the Top Margin to 1. Now run the application, and during the MouseOver State, the selected item should look like the image below:
Back in Blend, select the MouseOver State and set the element Opacity
back to 35%. Now select the fillColor2
element, and in the Base State, click on the Eye symbol next to the Selected State.
As we did before, change both the X and Y Radius for the fillColor2 Rectangle
to 5, and change the Left and Right Margins to 3, and the Top Margin to 1. Repeat the same process for the FocusVisualElement
, applying a Radius to the corners, and setting Margins for the sides.
Getting silly with the Item Container Style Template
Now for the fun part of applying, some silly "over the top" effects to our ListBox
. Most of these are obviously not really practical for a real application, and the thing to remember when using Effects & Animations is that they are to enhance your application, not to distract from the message or purpose of your application! They may appear fun and entertaining the first few times, but this will soon turn to frustration and annoyance for the user. So don't get carried away...
However, I will go completely "over the top" here, just to demonstrate what can be done!!!
Let's look at the MouseOver State first, or rather the State Group called "CommonStates
". Any Effect we apply here will apply to all the States in this State Group.
Applying an Effect for the MouseOver State will apply to the Normal and Disabled States as well. But rather than discussing this, let's go ahead and see this in action...
Click on the Effects icon "fx" and choose Ripple. (Or any other Effect you fancy!)
Set a Duration for the Effect of say 1 second, and run your application to see the results.
When we MouseOver the ListBox
items, we get a Ripple Effect. And we also get the same Effect when the ListBox
items return to their Normal State (MouseOff).
Try out different Effects for yourself, adjust the Duration to suit, as well as play with different EasingFunctions.
Next, let us look at the SelectionStates and specifically the Selected State.
Choose an Effect that takes your fancy, and set a Duration for this Effect. I've chosen Slide In (LeftToRight), as this will show up easily in a screenshot!
Run your application, and use the arrow keys to change the Selected item.
See how this affects the Selected State, as well as the Unselected State. This may not be desirable, as you may not want the Slide In to occur on the unselected item. And we can control this, by adding a Transition to the Selected State.
By adding a Transition from Selected State > All Other States, we can apply a completely different Effect when an item is Unselected.
So just to demonstrate, I have added a new "Blinds" Effect for this Transition, with a Duration of 1 second.
Now when we Unselect an item (MouseOff), instead of the Slide In Effect, we get a Blinds Effect, as shown in the image below:
We can obviously do this in All the State Groups, so an Effect can be tailored to your exact needs.
(Or have no Effect at all in a Transition, if the Duration is set to 0).
Finally, in this section, I want to look at the LayoutStates for the Loading of the ListBox
items.
Select the BeforeLoaded Transition, set a Duration of 1 second, and an EasingFunction of Bounce Out.
Now, ensuring you have the root grid selected, in the Transform section, set a Translation of 250 on the X axis.
Now run the application, and hopefully during loading, the ListBox
items flow in from the right and bounces off the left side of the ListBox
.
(Hit Refresh or F5 to reload and show the animation again.)
There is no point showing a screenshot, so download the finished project if you are not working through the tutorial!
That's it
That concludes my "over the top" explanation of Additional Templates. Back to defwebserver! Please vote to invalidate the 3 star voters who don't have the stones to leave comments on how I can improve my articles/tutorials!!!