Windows 8 has now shipped and developers are busy building Windows Store Applications (bad name). Developers who have experience working with Xaml have expectations on how Xaml should behave. The other day I was trying to do something I have done before. I wanted to change the DataTemplate of an item in an items control based upon an item being selected in an item control.
In Xaml, Items Controls are made up of different template. These templates are used to control the look and behavior of the items in the list. The power of Xaml is data binding. Take a collection of objects and bind it to an Items Control. Each item is displayed and by default, the string representation is displayed. To change this behavior you have to setup a DataTemplate. This template is then applied to each item in the collection. The problem with DataTemplates are that they don’t respond to the interactions of the control.
The interactions are achieved through visual states. To modify these interactions you have to edit the ItemsContainerStyle. There are the visual states are laid out through VisualStateGroups. Here is where the Selected style is defined. The problem is the data in the DataTemplate has no knowledge of this template or it’s interactions. In fact DataTemplates aren’t associated with any specific control. The same DataTemplate can be used by any control.
To solve my problem I had to wire the DataTemplate to the states in the ItemsContainerStyle. This is an instance of a specific control. For a GridView it is a GridViewItem. For a ListView it is a ListViewItem. You get the point. In prior Xaml techologies you would use AncestorBinding to walk up the object tree until you found the Item control. You would then bind the IsSelected property to a trigger. This allowed you to apply different styles based on this property.
In Windows 8 Xaml, you don’t have ancestry binding nor do you have triggers. So how do you achieve the same thing in your Windows Store application? There are RelativeSource bindings available but ancestry mode is not there. The only mode that can help is the TemplateParent mode. So I started out hoping that the TemplateParent was the Item control but this was not the case. For DataTemplates the parent is usually a ContentPresenter, one of the parts within the ItemsContainerStyle.
Now I can pass the IsSelected property through to the DataTemplate. First I template bind the IsSelected property to the Tag property of the ContentPresenter.
I then set up two grids in the DataTemplate to control the content that is visible based on the IsSelected property. I created two controls one for normal view and one for a selected view. Trough value converters I convert the value from the Tag into a visibility for the grid.
That is it. This all that is needed. Now my selected item view will be displayed when the item is selected. For the most part the Xaml developers will feel comfortable developing Windows 8 Store apps. There will be time where you have to find alternatives to what you’re used to but those should be the exception and not the rule.
As I come across these I differences I will continue to post them here. You can download some sample code here.
Hey Dave, thanks for the article. I am trying to get one level higher, and bind to a property on the GridView itself, so that I can change the state of all the items in my GridViewItemList all at once (e.g. change the visibility of an element in my DataTemplate for every item in the list by binding to a single element on the GridView). Is this possible?
Thanks,
Bob
You might be able to do it by giving the GridView a x:name and then do an element binding. Then you binding may look something like this: {Binding propertyName, Element=elementName}.
Hope that helps.
Hi Dave! Exactly what I was looking for! Thanks!
Hello! I simply want to offer you a huge thumbs up for the great
info you have right here on this post. I will be returning to
your blog for more soon.
Hi Dave!
I’m using this solution for ListView and the error I’m getting is:
Type ‘TemplateBinding’ used after ‘{‘ must be a Markup Extension
I’m binding Tag property of ListViewItemPresenter in ListViewItemContainer template.
I have not seen that error before. I don’t know how to solve it without seeing all of what you are doing. If you are using a ListView it should have a selection template already and you should not have to do this. That is one of the benefits of using the ListView vs ItemsControl.
I’ve edited a copy of ListView ItemContainerStyle and here’s the code:
Now if I paste:
Tag=”{TemplateBinding IsSelected}”
in , is generate this error:
Type ‘TemplateBinding’ used after ‘{‘ must be a Markup Extension.
I want to round the corners of selected item’s border. Like in the following image:
I am not sure why you are receiving the exception. There might be a bug. I would address your question on the Microsoft forums.