{"id":1705,"date":"2012-08-20T20:02:03","date_gmt":"2012-08-21T01:02:03","guid":{"rendered":"http:\/\/www.wiredprairie.us\/blog\/?p=1705"},"modified":"2012-08-20T20:02:03","modified_gmt":"2012-08-21T01:02:03","slug":"winrtxamlaka-metro-datatemplate-selection-based-on-data-types","status":"publish","type":"post","link":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1705","title":{"rendered":"WinRT\/Xaml\/AKA Metro DataTemplate selection based on Data Types"},"content":{"rendered":"

You may have noticed that WinRT does not have automatic resolution of a DataTemplate based on the data type of object added to an ItemsControl<\/a>. While unfortunate as this behavior is quite handy, it\u2019s not too difficult to replicate the functionality using a DataTemplateSelector<\/a>.<\/p>\n

WPF for example, could do something like this: <\/p>\n

\n
<DataTemplate DataType="{x:Type local:Task}"<\/span>>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}"<\/span> \/>
<TextBlock Text="{Binding Path=Description}"<\/span>\/>
<TextBlock Text="{Binding Path=Priority}"<\/span>\/>
<\/StackPanel>
<\/DataTemplate><\/pre>\n

<\/div>\n

When the Task type as shown above was found in a list, it would have been rendered as a StackPanel<\/a> with three TextBlock<\/a>s automatically. That rocked.<\/p>\n

WinRT (Metro\/Xaml, Windows 8 applications) are missing the DataType property of DataTemplates. Yes, some of you might say it\u2019s not missing as it\u2019s V1, but given the heritage of Windows 8 Xaml applications, I consider it missing.<\/p>\n

While an exact duplicate of the functionality isn\u2019t possible, it\u2019s relatively simple to get close.<\/p>\n

<<\/span>GridView\n    <\/span>x<\/span>:<\/span>Name<\/span>="itemGridView"\n<\/span>    <\/span>ItemsSource<\/span>="{<\/span>Binding <\/span>Source<\/span>={<\/span>StaticResource <\/span>groupedItemsViewSource<\/span>}}"\n    <\/span>ItemTemplateSelector<\/span>="{<\/span>StaticResource <\/span>typedTemplateSelector<\/span>}"\n    <\/span>SelectionMode<\/span>="None"\n    <\/span>IsItemClickEnabled<\/span>="True"<\/span>><\/span><\/pre>\n

Take the GridView above for example (using the template project in Visual Studio 2012).<\/p>\n

I\u2019ve assigned the ItemTemplateSelector to an instance of the TypedTemplateSelector class I\u2019ve created.<\/p>\n

In the Resources for the Page, I added a custom DataTemplate:<\/p>\n

\"image\"<\/p>\n

I\u2019ve added a DataTemplate with a Key called Type : SampleDataItem<\/strong> (without the spaces though \u2013 they\u2019re auto converted by my WordPress theme to a squiggle face: \"Confused).<\/p>\n

There\u2019s nothing special about the Template, just the name. It must start with Type:.<\/strong><\/p>\n

Here the custom template selector is being constructed in the Resources:<\/p>\n

    <\/span><<\/span>local<\/span>:<\/span>TypedTemplateSelector <\/span>x<\/span>:<\/span>Key<\/span>="typedTemplateSelector"\n                                 <\/span>DefaultTemplateKey<\/span>="Standard250x250ItemTemplate" \/>\n<\/<\/span>Page.Resources<\/span>><\/span><\/pre>\n
using <\/span>System;\n<\/span>using <\/span>System.Collections.Generic;\n<\/span>using <\/span>System.Linq;\n<\/span>using <\/span>System.Text;\n<\/span>using <\/span>System.Threading.Tasks;\n<\/span>using <\/span>Windows.UI.Xaml;\n<\/span>using <\/span>Windows.UI.Xaml.Controls;\n<\/span>using <\/span>Windows.UI.Xaml.Media;\n\n<\/span>namespace <\/span>WiredPrairie.TemplateSelector\n{\n    <\/span>public class <\/span>TypedTemplateSelector <\/span>: <\/span>DataTemplateSelector\n    <\/span>{\n        <\/span>private <\/span>Dictionary<\/span><<\/span>string<\/span>, <\/span>DataTemplate<\/span>> _cachedDataTemplates;\n\n        <\/span>\/\/\/ <summary>\n        \/\/\/ <\/span>Fallback value for DataTemplate\n        <\/span>\/\/\/ <\/summary>\n        <\/span>public string <\/span>DefaultTemplateKey { <\/span>get<\/span>; <\/span>set<\/span>; }\n\n        <\/span>\/\/\/ <summary>\n        \/\/\/ <\/span>Cache search results for a type (defaults to Enabled)\n        <\/span>\/\/\/ <\/summary>\n        <\/span>public bool <\/span>IsCacheEnabled { <\/span>get<\/span>; <\/span>set<\/span>; }\n\n        <\/span>public <\/span>TypedTemplateSelector()\n        {\n            IsCacheEnabled = <\/span>true<\/span>;\n        }\n\n        <\/span>protected override <\/span>Windows.UI.Xaml.<\/span>DataTemplate <\/span>SelectTemplateCore(<\/span>object <\/span>item, Windows.UI.Xaml.<\/span>DependencyObject <\/span>container)\n        {\n            <\/span>\/\/ grab the Type name. Type will be searched as Type:NAME as shown below\n            \/*\n                <DataTemplate x:Key="Type:SampleDataItem">\n                    <Grid HorizontalAlignment="Left" Width="250" Height="250">\n                        <TextBlock Text="{Binding Title}" \/>\n                    <\/Grid>\n                <\/DataTemplate>\n             *\/\n            <\/span>string <\/span>key = item != <\/span>null <\/span>? <\/span>string<\/span>.Format(<\/span>"Type:{0}"<\/span>, item.GetType().Name.Split(<\/span>'.'<\/span>).Last()) : DefaultTemplateKey;\n            <\/span>DataTemplate <\/span>dt = GetCachedDataTemplate(key);\n            <\/span>try\n            <\/span>{\n                <\/span>if <\/span>(dt != <\/span>null<\/span>) { <\/span>return <\/span>dt; }\n\n                <\/span>\/\/ look at all parents (visual parents)\n                <\/span>FrameworkElement <\/span>fe = container <\/span>as <\/span>FrameworkElement<\/span>;\n                <\/span>while <\/span>(fe != <\/span>null<\/span>)\n                {\n                    dt = FindTemplate(fe, key);\n                    <\/span>if <\/span>(dt != <\/span>null<\/span>) { <\/span>return <\/span>dt; }\n                    <\/span>\/\/ if you were to just look at logical parents,\n                    \/\/ you'd find that there isn't a Parent for Items set\n                    <\/span>fe = <\/span>VisualTreeHelper<\/span>.GetParent(fe) <\/span>as <\/span>FrameworkElement<\/span>;\n                }\n\n                dt = FindTemplate(<\/span>null<\/span>, key);\n                <\/span>return <\/span>dt;\n            }\n            <\/span>finally\n            <\/span>{\n                <\/span>if <\/span>(dt != <\/span>null<\/span>)\n                {\n                    AddCachedDataTemplate(key, dt);\n                }\n            }\n        }\n\n        <\/span>private <\/span>DataTemplate <\/span>GetCachedDataTemplate(<\/span>string <\/span>key)\n        {\n            <\/span>if <\/span>(!IsCacheEnabled) { <\/span>return null<\/span>; }\n            VerifyCachedDataTemplateStorage();\n            <\/span>if <\/span>(_cachedDataTemplates.ContainsKey(key))\n            {\n                <\/span>return <\/span>_cachedDataTemplates[key];\n            }\n\n            <\/span>return null<\/span>;\n        }\n\n        <\/span>private void <\/span>AddCachedDataTemplate(<\/span>string <\/span>key, <\/span>DataTemplate <\/span>dt)\n        {\n            <\/span>if <\/span>(!IsCacheEnabled) { <\/span>return<\/span>; }\n            VerifyCachedDataTemplateStorage();\n            _cachedDataTemplates[key] = dt;\n        }\n\n        <\/span>\/\/\/ <summary>\n        \/\/\/ <\/span>Delay creates storage\n        <\/span>\/\/\/ <\/summary>\n        <\/span>private void <\/span>VerifyCachedDataTemplateStorage()\n        {\n            <\/span>if <\/span>(_cachedDataTemplates == <\/span>null<\/span>)\n            {\n                _cachedDataTemplates = <\/span>new <\/span>Dictionary<\/span><<\/span>string<\/span>, <\/span>DataTemplate<\/span>>();\n            }\n\n        }\n\n        <\/span>\/\/\/ <summary>\n        \/\/\/ <\/span>Returns a template\n        <\/span>\/\/\/ <\/summary>\n        \/\/\/ <param name="source"><\/span>Pass null to search entire app<\/span><\/param>\n        \/\/\/ <param name="key"><\/param>\n        \/\/\/ <returns><\/returns>\n        <\/span>private static <\/span>DataTemplate <\/span>FindTemplate(<\/span>object <\/span>source, <\/span>string <\/span>key)\n        {\n            <\/span>var <\/span>fe = source <\/span>as <\/span>FrameworkElement<\/span>;\n            <\/span>object <\/span>obj;\n            <\/span>ResourceDictionary <\/span>rd = fe != <\/span>null <\/span>? fe.Resources : <\/span>App<\/span>.Current.Resources;\n            <\/span>if <\/span>(rd.TryGetValue(key, <\/span>out <\/span>obj))\n            {\n                <\/span>DataTemplate <\/span>dt = obj <\/span>as <\/span>DataTemplate<\/span>;\n                <\/span>if <\/span>(dt != <\/span>null<\/span>)\n                {\n                    <\/span>return <\/span>dt;\n                }\n            }\n            <\/span>return null<\/span>;\n\n        }\n    }\n}\n<\/span><\/pre>\n","protected":false},"excerpt":{"rendered":"

You may have noticed that WinRT does not have automatic resolution of a DataTemplate based on the data type of object added to an ItemsControl. While unfortunate as this behavior is quite handy, it\u2019s not too difficult to replicate the functionality using a DataTemplateSelector. WPF for example, could do something like this: <DataTemplate DataType="{x:Type local:Task}"> […]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[4],"tags":[82,96,79,106,107],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pd5QIe-rv","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":1701,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1701","url_meta":{"origin":1705,"position":0},"title":"Windows 8 WinRT\/Metro Missing UpdateSourceTrigger","date":"August 5, 2012","format":false,"excerpt":"If you\u2019ve done WPF or Silverlight programming, you may have found an occasion where using the Binding property UpdateSourceTrigger set to PropertyChanged was extremely useful. (I know I have!) It may have looked something like this: The key feature was the live updating of the\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1730,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1730","url_meta":{"origin":1705,"position":1},"title":"How to find an element in a DataTemplate in WinRT\/XAML.","date":"September 7, 2012","format":false,"excerpt":"Here\u2019s one way to find a named element in a DataTemplate in XAML in Windows 8 XAML. You might try FindName to discover it doesn\u2019t work. That\u2019s because it\u2019s not recursive. So, I created a simple extension method to do the same thing: public static class FrameworkElementExtensions { public static\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"image","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2012\/09\/image.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":388,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/388","url_meta":{"origin":1705,"position":2},"title":"Silverlight Weather Demonstration","date":"June 26, 2008","format":false,"excerpt":"Demonstration available here. (You'll need to wait for a moment while it loads the first time). I've created a reasonably simple, yet multi-technology (and discipline) demonstration using Silverlight for the user interface and ASP.NET as the back-end. The demonstration uses: Silverlight 2.0 Data binding Delayed downloading of images \"Web services\"\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2008\/06\/image21.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":568,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/568","url_meta":{"origin":1705,"position":3},"title":"Data Binding and Tooltips in Silverlight","date":"September 19, 2008","format":false,"excerpt":"Have you ever wanted to databind a tooltip in Silverlight (or WPF for that matter), and found that the DataContext isn't available for tooltips (the datacontext is null)? It's very annoying. Tooltips, unfortunately, aren't connected to their parents in anyway when they're created, so they loose the ability to connect\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":670,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/670","url_meta":{"origin":1705,"position":4},"title":"Silverlight: Dynamically creating XAML elements at runtime","date":"January 19, 2009","format":false,"excerpt":"Given the following XML file: <\/Canvas> <\/asset> <\/assets> It\u2019s easy enough to create reusable assets in Silverlight and load them on demand from XML, and refer to the\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"image","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2009\/01\/image8.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":1524,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1524","url_meta":{"origin":1705,"position":5},"title":"Alternative to ApplicationSettings in .NET","date":"February 1, 2012","format":false,"excerpt":"After dealing with lost settings, an unclear upgrade path, and my own confusion surrounding the magic of Settings in a .NET client application, I decided to build my own. You\u2019re probably familiar with this UI in Visual Studio. It hasn\u2019t changed much since it was first created: A list of\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"image","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2012\/02\/image.png?resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts\/1705"}],"collection":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/comments?post=1705"}],"version-history":[{"count":2,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts\/1705\/revisions"}],"predecessor-version":[{"id":1766,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts\/1705\/revisions\/1766"}],"wp:attachment":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/media?parent=1705"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/categories?post=1705"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/tags?post=1705"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}

Here\u2019s the class that you\u2019d need below. It has a caching feature (IsCacheEnabled<\/strong>) to prevent the search from occurring more than once for a key. It\u2019s set to True by default. When used, the object searches from the current Item through all Parents trying to match the type of the object (via the VisualTreeHelper<\/a>). Only the ClassName is used as programmed below (and not the full namespace). You could easily change this behavior by removing the Split <\/strong>and Last <\/strong>calls.<\/p>\n