善用 DataTemplateSelector 讓畫面更彈性
DataTemplateSelector 在開發 Windows Phone 或 Windows Store App 一定會很常使用到這個技術。
例如:ListView 的每一個 Item 根據值的差異而畫成不同樣子,這時候需要利用 DataTemplateSelector。
提供一種方法根據 data object 與 data-bound element 來選擇使用的 DataTempalte。
主要實作重點有二:
a. 增加一個類別繼承 DataTemplateSelecotr 補上轉換的 SelectTemplate 方法與邏輯;
b. XAML 中宣告該 Selector 與支援的 DataTemplate;
然而是不是什麼都要用到 DataTemplateSeleector 呢?
根據<DataTemplateSelector>的說明:
a. 如果是相同的 data object 中小部分的 properties 不同而有不同的呈現,則建議改用 Data Converter 或 DataTrigger 。
b. 如果是相同的 data object 所建立的 datatemplate 也可以指定不同的 data type 來做區格就不需要使用 datatemplateselector。
更多詳細的可參考<Data Templating Overview>的說明。
[範例程式]
1. 預期結果;
想要呈現二種不同的排版方式,一個是寬版的 size,一個是窄版的 size。
2. 建立要使用的 DataTemplateSelector;
public class ContentDataTemplateSelector : DataTemplateSelector
{
/// <summary>
/// 寬版的 DataTemplate
/// </summary>
public DataTemplate BigSizeTemplate { get; set; }
/// <summary>
/// 窄版的 DataTemplate
/// </summary>
public DataTemplate SmallSizeTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
RssItem dataObject = item as RssItem;
// 利用 dataobject 的 property 來識別
if (dataObject.StyleType == ItemType.All)
{
return BigSizeTemplate;
}
else
{
return SmallSizeTemplate;
}
}
}
3. 定義呈現的 XAML 與 DataTemplateSelector;
<Page.Resources>
<!-- 為 DataTemplateSelector 定義一個 Key -->
<local:ContentDataTemplateSelector x:Key="contentDataTemplateSelector">
<!-- 定義寬版的 datatemplate -->
<local:ContentDataTemplateSelector.BigSizeTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding imgUrl}" Stretch="UniformToFill" />
<StackPanel Background="Orange" VerticalAlignment="Top" HorizontalAlignment="Left" Width="70">
<TextBlock Foreground="White" Text="{Binding category}" Margin="6"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</StackPanel>
<Grid VerticalAlignment="Bottom" Background="Black" Height="53" Opacity="0.8">
<TextBlock Foreground="White" Text="{Binding title}" Margin="3"
FontSize="20" Height="53" TextWrapping="Wrap" VerticalAlignment="Center"
TextTrimming="CharacterEllipsis" />
</Grid>
</Grid>
</DataTemplate>
</local:ContentDataTemplateSelector.BigSizeTemplate>
<!-- 定義窄版的 datatemplate -->
<local:ContentDataTemplateSelector.SmallSizeTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding imgUrl}"
Stretch="UniformToFill" Height="80" Width="80" />
<StackPanel Grid.Column="1" Margin="3,4,0,0">
<StackPanel Background="Orange" HorizontalAlignment="Left">
<TextBlock Foreground="White" Text="{Binding category}" Margin="6"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</StackPanel>
<TextBlock Foreground="White" Text="{Binding title}" Margin="3"
FontSize="18" Height="53" TextWrapping="Wrap"
VerticalAlignment="Center" TextTrimming="CharacterEllipsis" />
</StackPanel>
</Grid>
</DataTemplate>
</local:ContentDataTemplateSelector.SmallSizeTemplate>
</local:ContentDataTemplateSelector>
</Page.Resources>
4. 執行結果:
上述的範例如果仔細來分析以,可以看出其實只有 width 的改變,其實可以直接使用 data convert 的機制,
來調整要顯示的大小即可。
======
上述主要介紹怎麼實作 DataTemplateSelector,但在使用情境仍需要考量資料量是否太大,
因為 DateTemplateSelector 是 runtime 時才動態調整的,一定沒有事先 compile 來的快速,
所以要多加考量例如藉由將資料切成區塊,每一次只給一小區域範圍等到滑動至置時才載下一個區域。
希望對大家有所幫助,謝謝。
References:
〉ContentControl Styles and Templates
〉WPF Based Dynamic DataTemplateSelector
〉WPF Tutorial - How To Use A DataTemplateSelector