{"id":49,"date":"2012-06-09T22:55:00","date_gmt":"2012-06-09T22:55:00","guid":{"rendered":"http:\/\/tpodolak.com.hostingasp.pl\/blog\/2012\/06\/09\/windows-phone-wlasny-datatemplateselector\/"},"modified":"2016-01-31T00:15:41","modified_gmt":"2016-01-31T00:15:41","slug":"windows-phone-wlasny-datatemplateselector","status":"publish","type":"post","link":"https:\/\/tpodolak.com\/blog\/2012\/06\/09\/windows-phone-wlasny-datatemplateselector\/","title":{"rendered":"Windows Phone &#8211; w\u0142asny DataTemplateSelector"},"content":{"rendered":"<p>Pisz\u0105c moj\u0105 ma\u0142\u0105 aplikacj\u0119 pod Windows Phone po raz kolejny natkn\u0105\u0142em si\u0119 na problem. Pod WP7 nie ma tak przydatnej rzeczy jak\u0105 jest DataTemplateSelector znany nam bardziej, lub mniej z Silverlighta oraz WPF-a.Na szcz\u0119\u015bcie napisane w\u0142asnego DataTemplateSelector-a nie jest specjalnie skomplikowane. Jak zwykle w takich przypadkach liczy si\u0119 pomys\u0142 &#8211; jak dobrze, \u017ce jest Google. Nasz customowy DataTemplateSelector zostanie oparty o kontrolk\u0119 ContentControl. Po pierwsze stw\u00f3rzmy klas\u0119 bazow\u0105 DataTemplateSelectora dziedzicz\u0105c\u0105 po ContentControl,w kt\u00f3rej przeci\u0105\u017camy funkcj\u0119 OnContentChanged,<\/p>\n<pre lang=\"csharp\">\r\npublic abstract class AbstractDataTemplateSelector : ContentControl\r\n{\r\n    public abstract DataTemplate SelectTemplate(object item, DependencyObject container);\r\n    \r\n    protected override void OnContentChanged(object oldContent, object newContent)\r\n    {\r\n        base.OnContentChanged(oldContent, newContent);\r\n        ContentTemplate = SelectTemplate(newContent, this);\r\n    }\r\n}\r\n<\/pre>\n<p>Klasa ta b\u0119dzie klas\u0105 z kt\u00f3rej b\u0119d\u0105 wywodzi\u0107 si\u0119 wszystkie nasze TemplateSelectory. Za\u0142\u00f3\u017cmy, \u017ce chcemy zbudowa\u0107 DataTemplateSelector, kt\u00f3ry b\u0119dzie obs\u0142ugiwa\u0142 aplikacj\u0119 chata. Powinien on zatem reagowa\u0107 na dwa typy element\u00f3w:<\/p>\n<ul>\n<li>wiadomo\u015bci przychodz\u0105ce<\/li>\n<li>wiadomo\u015bci wychodz\u0105ce<\/li>\n<\/ul>\n<p>Stw\u00f3rzmy zatem &#8220;wyspecjalizowany&#8221; DataTemplateSelector, kt\u00f3ry w zale\u017cno\u015bci od typu wiadomo\u015bci zwr\u00f3ci odpowiedni DataTemplate.<\/p>\n<pre lang=\"csharp\">\r\npublic class ChatMessageTemplateSelector : AbstractDataTemplateSelector\r\n{\r\n    public DataTemplate Out { get; set; }\r\n    public DataTemplate In { get; set; }\r\n\r\n    public override DataTemplate SelectTemplate(object item, DependencyObject container)\r\n    {\r\n        ChatMessage message = item as ChatMessage;\r\n        if (message != null)\r\n        {\r\n            switch (message.MessageDirection)\r\n            {\r\n                case MessageDirection.In:\r\n                    return In;\r\n                case MessageDirection.Out:\r\n                    return Out;\r\n                default:\r\n                    return Out;\r\n            }\r\n        }\r\n        return In;\r\n    }\r\n}\r\n<\/pre>\n<p>W klasie ChatMessageTemplateSelector przeci\u0105\u017cyli\u015bmy metod\u0119 SelectTemplate. W metodzie tej, na podstawie zbindowanego obiektu (parametr item) okre\u015blamy jaki template powinni\u015bmy zwr\u00f3ci\u0107. Templaty do wiadomo\u015bci przychodz\u0105cych oraz wychodz\u0105cych zosta\u0142y zdefiniowane jako propertisy.<\/p>\n<ul>\n<li>Out &#8211; template wiadomo\u015bci wychodz\u0105cej<\/li>\n<li>In &#8211; template wiadomo\u015bci przychodz\u0105cej<\/li>\n<\/ul>\n<p>Pozostaje nam tylko zdefiniowa\u0107 wymienione wy\u017cej templaty. Nie b\u0119dziemy robi\u0107 tego w kodzie, ale w XAML-u. Nasz nowo stworzony DataTemplateSelector wykorzytamy w ListBox-ie<\/p>\n<pre lang=\"xml\">\r\n<ListBox  ItemsSource=\"{Binding MessageList,Mode=TwoWay}\" Grid.ColumnSpan=\"2\" HorizontalContentAlignment=\"Stretch\" VerticalAlignment=\"Stretch\"\r\n                     ItemTemplate=\"{StaticResource GeneralChatMessageTemplate}\" \/>\r\n<\/pre>\n<p>Jako, \u017ce nasz ChatMessageTemplateSelector jest tak naprawd\u0119 obiektem typu ContentControl, zatem mo\u017cemy go zbindowa\u0107 do w\u0142a\u015bciwo\u015bci ItemTemplate ListBox-a. Zas\u00f3b GeneralChatMessageTemplate wygl\u0105da w nast\u0119puj\u0105cy spos\u00f3b<\/p>\n<pre lang=\"xml\">\r\n<DataTemplate x:Key=\"GeneralChatMessageTemplate\">\r\n            <Client:ChatMessageTemplateSelector HorizontalContentAlignment=\"Stretch\" Content=\"{Binding}\" In=\"{StaticResource IncomingChatMessageTemplate}\" Out=\"{StaticResource OutcomingChatMessageTemplate}\">\r\n            <\/Client:ChatMessageTemplateSelector>\r\n<\/DataTemplate>\r\n<\/pre>\n<p>Jak wida\u0107 jest to obiekt typu ChatMessageTemplateSelector, kt\u00f3rego w\u0142a\u015bciwo\u015b\u0107 Content jest zbindowana do aktualnego kontekstu (pojedyncze s\u0142owo kluczowe Binding). Widzimy r\u00f3wnie\u017c, \u017ce ustawili\u015bmy warto\u015bci w\u0142a\u015bciwo\u015bci odpowiadaj\u0105cych za templaty poszczeg\u00f3lnych wiadomo\u015bci (In=&#8221;{StaticResource IncomingChatMessageTemplate}&#8221; Out=&#8221;{StaticResource OutcomingChatMessageTemplate}&#8221;). Wspomniane templaty wygl\u0105daj\u0105 w nast\u0119puj\u0105cy spos\u00f3b<\/p>\n<pre lang=\"xml\">\r\n<DataTemplate x:Key=\"IncomingChatMessageTemplate\">\r\n            <Border BorderThickness=\"0,0,0,1\" BorderBrush=\"#2d3550\" >\r\n                <Grid Background=\"#181c2a\" HorizontalAlignment=\"Stretch\">\r\n                    <Grid.ColumnDefinitions>\r\n                        <ColumnDefinition \/>\r\n                        <ColumnDefinition \/>\r\n                    <\/Grid.ColumnDefinitions>\r\n                    <Grid.RowDefinitions>\r\n                        <RowDefinition><\/RowDefinition>\r\n                        <RowDefinition><\/RowDefinition>\r\n                    <\/Grid.RowDefinitions>\r\n                    <StackPanel Orientation=\"Horizontal\">\r\n                        <Border BorderThickness=\"1\" BorderBrush=\"White\" Margin=\"5,5,0,0\">\r\n                            <Image Stretch=\"None\"  Width=\"30\" Height=\"30\" MaxWidth=\"30\" MinHeight=\"30\" MaxHeight=\"30\"  Source=\"..avatar_4934.bmp\"><\/Image>\r\n                        <\/Border>\r\n                        <TextBlock Padding=\"5,5,5,0\" Foreground=\"White\" FontFamily=\"Segoe UI, Tahoma\" FontSize=\"12\" FontWeight=\"Bold\" TextTrimming=\"WordEllipsis\"  TextAlignment=\"Left\" VerticalAlignment=\"Center\" HorizontalAlignment=\"Left\"  Text=\"{Binding Sender.UserName,Mode=TwoWay}\"><\/TextBlock>\r\n                    <\/StackPanel>\r\n                    <TextBlock FontFamily=\"Segoe UI, Tahoma\" FontSize=\"10\" Padding=\"5,5,5,0\" Foreground=\"#8e929f\" TextTrimming=\"WordEllipsis\"  Grid.Column=\"1\" TextAlignment=\"Right\" VerticalAlignment=\"Center\" HorizontalAlignment=\"Right\" Text=\"{Binding SendTime, Mode=TwoWay, StringFormat='{0:dd.MM HH:mm:ss}'}\"><\/TextBlock>\r\n                    <TextBlock FontFamily=\"Segoe UI, Tahoma\" FontSize=\"12\" Margin=\"5,0,0,0\" TextWrapping=\"Wrap\" Grid.ColumnSpan=\"2\" Grid.Row=\"1\" Text=\"{Binding Message,Mode=TwoWay}\" ><\/TextBlock>\r\n                <\/Grid>\r\n            <\/Border>\r\n<\/DataTemplate>\r\n<\/pre>\n<pre lang=\"xml\">\r\n<DataTemplate x:Key=\"OutcomingChatMessageTemplate\">\r\n            <Border BorderThickness=\"0,0,0,1\" BorderBrush=\"#2d3550\">\r\n                <Grid HorizontalAlignment=\"Stretch\">\r\n                    <Grid.ColumnDefinitions>\r\n                        <ColumnDefinition \/>\r\n                        <ColumnDefinition \/>\r\n                    <\/Grid.ColumnDefinitions>\r\n                    <Grid.RowDefinitions>\r\n                        <RowDefinition><\/RowDefinition>\r\n                        <RowDefinition><\/RowDefinition>\r\n                    <\/Grid.RowDefinitions>\r\n                    <StackPanel Orientation=\"Horizontal\">\r\n                        <Border BorderThickness=\"1\" BorderBrush=\"White\" Margin=\"5,5,0,0\">\r\n                            <Image Stretch=\"None\"  Width=\"30\" Height=\"30\" MaxWidth=\"30\" MinHeight=\"30\" MaxHeight=\"30\"  ><\/Image>\r\n                        <\/Border>\r\n                        <TextBlock Padding=\"5,5,5,0\" Foreground=\"#8e929f\" FontFamily=\"Segoe UI, Tahoma\" FontSize=\"12\" FontWeight=\"Bold\" TextTrimming=\"WordEllipsis\"  TextAlignment=\"Left\" VerticalAlignment=\"Center\" HorizontalAlignment=\"Left\"  Text=\"{Binding Sender.UserName,Mode=TwoWay}\"><\/TextBlock>\r\n                    <\/StackPanel>\r\n                    <TextBlock FontFamily=\"Segoe UI, Tahoma\" FontSize=\"10\" Padding=\"5,5,5,0\" Foreground=\"#8e929f\" TextTrimming=\"WordEllipsis\"  Grid.Column=\"1\" TextAlignment=\"Right\" VerticalAlignment=\"Center\" HorizontalAlignment=\"Right\" Text=\"{Binding SendTime, Mode=TwoWay, StringFormat='{0:dd.MM HH:mm:ss}'}\"><\/TextBlock>\r\n                    <TextBlock FontFamily=\"Segoe UI, Tahoma\" FontSize=\"12\" Margin=\"5,0,0,0\" TextWrapping=\"Wrap\" Grid.ColumnSpan=\"2\" Grid.Row=\"1\" Text=\"{Binding Message,Mode=TwoWay}\" ><\/TextBlock>\r\n                <\/Grid>\r\n            <\/Border>\r\n<\/DataTemplate>\r\n<\/pre>\n<p>Od teraz gdy do ListBox-a zostanie dodany nowy item, pierwsz\u0105 rzecz\u0105 jaka si\u0119 odpali b\u0119dzie funkcja OnContentChanged. W funkcji tej AbstractDataTemplateSelector na podstawie nowo przyby\u0142ego itemu ustawi w\u0142a\u015bciwo\u015b\u0107 ContentTemplate, na taki template jaki zwr\u00f3ci mu funkcja SelectTemplate. Wynik dzia\u0142ania ChatMessageTemplateSelector wygl\u0105da w nast\u0119puj\u0105cy spos\u00f3b<br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2012\/06\/windows-phone-wlasny-datatemplateselector\/Result.jpg\" rel=\"attachment wp-att-422\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2012\/06\/windows-phone-wlasny-datatemplateselector\/Result.jpg\" alt=\"DataTemplateSelector\" width=\"429\" height=\"800\" class=\"aligncenter size-full wp-image-422\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2012\/06\/windows-phone-wlasny-datatemplateselector\/Result.jpg 429w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2012\/06\/windows-phone-wlasny-datatemplateselector\/Result-80x150.jpg 80w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2012\/06\/windows-phone-wlasny-datatemplateselector\/Result-161x300.jpg 161w\" sizes=\"auto, (max-width: 429px) 100vw, 429px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pisz\u0105c moj\u0105 ma\u0142\u0105 aplikacj\u0119 pod Windows Phone po raz kolejny natkn\u0105\u0142em si\u0119 na problem. Pod WP7 nie ma tak przydatnej rzeczy jak\u0105 jest DataTemplateSelector znany nam bardziej, lub mniej z Silverlighta oraz WPF-a.Na szcz\u0119\u015bcie napisane w\u0142asnego DataTemplateSelector-a nie jest specjalnie skomplikowane. Jak zwykle w takich przypadkach liczy si\u0119 pomys\u0142 &#8211; jak dobrze, \u017ce jest Google. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[107,30],"tags":[242,240],"class_list":["post-49","post","type-post","status-publish","format-standard","hentry","category-datatemplate","category-windows-phone","tag-datatemplate","tag-windows-phone"],"_links":{"self":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/49","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/comments?post=49"}],"version-history":[{"count":6,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/49\/revisions"}],"predecessor-version":[{"id":555,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/49\/revisions\/555"}],"wp:attachment":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/media?parent=49"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/categories?post=49"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/tags?post=49"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}