datatemplateselector winrt
by Peter Daukintis
Having used DataTemplateSelectors previously with WPF and similar on Silverlight/Windows Phone I decided to check out whether they work the same in a xaml Metro application. It turns out to be pretty much the same (barring a few things being a bit buggy in the Win8 Developer Preview). Anyway, for reference, here’s a description:
First I created a custom data template selector. This enables you to intercept the decision of which template to use.
- public class MyDataTemplateSelector : DataTemplateSelector
- {
- public DataTemplate PlaceTemplate { get; set; }
- public DataTemplate PersonTemplate { get; set; }
- protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
- {
- if (item is Person)
- return PersonTemplate;
- if (item is Place)
- return PlaceTemplate;
- return base.SelectTemplateCore(item, container);
- }
- }
I then created an instance in my Main Page’s xaml… <p></p> <div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:8cc71fc9-a2ea-4159-93a7-e8a79ee2a0d9" class="wlWriterEditableSmartContent" style="float:none;display:inline;margin:0;padding:0;"> <div class="le-pavsc-container"> <div class="le-pavsc-titleblock">Create Instance</div> <div style="background:#fff;overflow:auto;"> <ol style="background:#ffffff;margin:0;padding:0 0 0 5px;"> <li><UserControl.Resources></li> <li class="le-pavsc-even"> <FlipView:MyDataTemplateSelector x:Key="mySelector" /></li> <li></UserControl.Resources></li> </ol> </div> </div> </div> <p>If you’re used to other xaml technologies you need to be careful with your namespace declaration as the syntax has changed for WinRT:</p> <div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:88952be7-d021-4be0-a0c7-ba52e413b9ac" class="wlWriterEditableSmartContent" style="float:none;display:inline;margin:0;padding:0;"> <div class="le-pavsc-container"> <div class="le-pavsc-titleblock">Using declaration</div> <div style="background:#fff;overflow:auto;"> <ol style="background:#ffffff;margin:0;padding:0 0 0 5px;"> <li>xmlns:FlipView="using:FlipView"</li> </ol> </div> </div> </div> <p>One thing we haven’t done is to create and set up the DataTemplates:</p> <div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:2bc677ae-c685-4c65-af0e-27c068a90db8" class="wlWriterEditableSmartContent" style="float:none;display:inline;margin:0;padding:0;"> <div class="le-pavsc-container"> <div class="le-pavsc-titleblock">DataTemplates</div> <div style="background:#fff;overflow:auto;"> <ol style="background:#ffffff;margin:0;padding:0 0 0 5px;"> <li><UserControl.Resources></li> <li class="le-pavsc-even"> <DataTemplate x:Key="myPersonTemplate"></li> <li> <Border Background="CornflowerBlue"></li> <li class="le-pavsc-even"> <TextBlock Text="{Binding Name}"</li> <li> FontSize="64"</li> <li class="le-pavsc-even"> Foreground="Red"</li> <li> HorizontalAlignment="Center"</li> <li class="le-pavsc-even"> VerticalAlignment="Center" /></li> <li> </Border></li> <li class="le-pavsc-even"> </DataTemplate></li> <li> <DataTemplate x:Key="myPlaceTemplate"></li> <li class="le-pavsc-even"> <Border Background="Orange"></li> <li> <Grid></li> <li class="le-pavsc-even"> <Image Source="{Binding Image}"></Image></li> <li> <TextBlock Text="{Binding PlaceName}" </li> <li class="le-pavsc-even"> FontSize="128" </li> <li> Foreground="AliceBlue" </li> <li class="le-pavsc-even"> HorizontalAlignment="Center" </li> <li> VerticalAlignment="Center" /></li> <li class="le-pavsc-even"> </Grid></li> <li> </Border></li> <li class="le-pavsc-even"> </DataTemplate></li> <li> <FlipView:MyDataTemplateSelector x:Key="mySelector"</li> <li class="le-pavsc-even"> PersonTemplate="{StaticResource myPersonTemplate}"</li> <li> PlaceTemplate="{StaticResource myPlaceTemplate}"></li> <li class="le-pavsc-even"> </FlipView:MyDataTemplateSelector></li> <li></UserControl.Resources></li> </ol> </div> </div> </div> <p></p> <p>Note that I have created the DataTemplates with a key in the UserControl Resources. This allows me to access the item as a StaticResource; I do this to set the properties on my custom DataTemplateSelector. Now the above may be used with any ItemsControl since that defines an ItemTemplateSelector property on which we can set our custom DataTemplateSelector. It just remains to mock up some data and try it out on a few different Containers:</p> <div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:81923292-f85f-4ae7-a5ee-ae173044c493" class="wlWriterEditableSmartContent" style="float:none;display:inline;margin:0;padding:0;"> <div class="le-pavsc-container"> <div class="le-pavsc-titleblock">Dummy Data</div> <div style="background:#fff;overflow:auto;"> <ol style="background:#ffffff;margin:0;padding:0 0 0 5px;"> <li>private ObservableCollection<object> _collection = new ObservableCollection<object></li> <li class="le-pavsc-even"> {</li> <li> new Person { Name = "fred", Age = 22 },</li> <li class="le-pavsc-even"> new Person { Name = "bob", Age = 22 },</li> <li> new Person { Name = "doris", Age = 22 },</li> <li class="le-pavsc-even"> new Place { PlaceName="Moscow", Image="./Images/350px-St__Basil2.jpg"},</li> <li> new Person { Name = "mabel", Age = 22 },</li> <li class="le-pavsc-even"> };</li> </ol> </div> </div> </div> <p>Note that I have used the instance type to be the criteria under which I swap the template but of course, the criteria could be anything here. To test on a FlipView just add</p> <div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:23f7ebce-2924-4f44-af50-6506153c849a" class="wlWriterEditableSmartContent" style="float:none;display:inline;margin:0;padding:0;"> <div class="le-pavsc-container"> <div class="le-pavsc-titleblock">FlipView</div> <div style="background:#fff;overflow:auto;"> <ol style="background:#ffffff;margin:0;padding:0 0 0 5px;"> <li><FlipView x:Name="myFlip" ItemTemplateSelector="{StaticResource mySelector}" /></li> </ol> </div> </div> </div> <p> </p> <p>and set the ItemSource in the code-behind:</p> <div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:e1b68e95-18de-4c9c-ae53-708ff85aa1b4" class="wlWriterEditableSmartContent" style="float:none;display:inline;margin:0;padding:0;"> <div class="le-pavsc-container"> <div class="le-pavsc-titleblock">ItemSource</div> <div style="background:#fff;overflow:auto;"> <ol style="background:#ffffff;margin:0;padding:0 0 0 5px;"> <li>myFlip.ItemsSource = _collection;</li> </ol> </div> </div> </div> <p>Just replace the above two steps to try this with a different container.</p> <p>FlipView seems to suffer from some issues where it rendered unexpected results; sometimes updating the template and sometimes not.</p> <p> </p> <p>The ListBox gave the expected results:</p> <p></p>
Comments