[WPF系列-数据邦定之DataTemplate 根据对象属性切换模板

 

引言

书接上回[WPF系列-数据邦定之DataTemplate],本篇介绍如何根据属性切换模板(DataTemplate)

 

切换模板的两种方式:

 

  • 使用DataTemplateSelector来切换模板
  • 使用DataTrigger来实现模板切换。
  • 使用Style来是实现模板切换

 

A DataTemplateSelector does not respond to PropertyChange notifications, so it doesn‘t get re-evaluated when your properties change.

The alternative I use is DataTriggers that changes the Template based on a property.

For example, this will draw all TaskModel objects using a ContentControl, and the ContentControl.Template is based on the TaskStatus property of the TaskModel

 

使用DataTrigger切换模板

 

<DataTemplate DataType="{x:Type viewModels:CorePlugViewModel}">
            <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowGridLines="True" >
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Name}" Margin="4"></TextBlock>
                <ContentControl x:Name="viewBox" Grid.Row="1" HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch">
                        <Image  Source="{Binding MapThumbnail}" />
                </ContentControl>
            </Grid>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding HasMap}" Value="True">
                    <Setter Property="Template" TargetName="viewBox">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ContentControl}">
                                <views:CorePlugWithMap VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinHeight="10"/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>

 

使用DataTemplateSelector切换模板

在 DataType 属性一节中,我们讨论了您可以针对不同的数据对象定义不同的数据模板。 这在您拥有不同类型的 CompositeCollection 或不同类型的项集合时尤其有用。 在使用 DataTrigger 来应用属性值一节中,我们演示了如果您拥有相同类型的数据对象集合,您可以创建 DataTemplate,然后根据每个数据对象的属性值使用触发器来应用更改。 虽然触发器允许您应用属性值或启动动画,但是它们无法让您灵活重构数据对象的结构。 在某些情况下,可能需要您为类型相同但属性不同的数据对象创建其他 DataTemplate。
例如,当 Task 对象的 Priority 值为 1 时,您可能需要为它指定完全不同的外观,以给予您自己一个提醒。 在这种情况下,您需要创建 DataTemplate 来显示高优先级的 Task 对象。 让我们将以下 DataTemplate 添加到资源部分:

<DataTemplate x:Key="importantTaskTemplate">
  <DataTemplate.Resources>
    <Style TargetType="TextBlock">
      <Setter Property="FontSize" Value="20"/>
    </Style>
  </DataTemplate.Resources>
  <Border Name="border" BorderBrush="Red" BorderThickness="1"
          Padding="5" Margin="5">
    <DockPanel HorizontalAlignment="Center">
      <TextBlock Text="{Binding Path=Description}" />
      <TextBlock>!</TextBlock>
    </DockPanel>
  </Border>
</DataTemplate>

 

请注意,此示例使用 DataTemplate.Resources 属性。 DataTemplate 中的元素共享该部分中定义的资源。
若要提供逻辑以根据数据对象的 Priority 值选择要使用的 DataTemplate,需要创建 DataTemplateSelector 的子类并重写 SelectTemplate 方法。 在下面的示例中,SelectTemplate 方法提供逻辑以根据 Priority 属性的值返回适当的模板。 可以在封装 Window 元素的资源中找到要返回的模板。

 

using System.Windows;
using System.Windows.Controls;

namespace SDKSample
{
    public class TaskListDataTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate
            SelectTemplate(object item, DependencyObject container)
        {
            FrameworkElement element = container as FrameworkElement;

            if (element != null && item != null && item is Task)
            {
                Task taskitem = item as Task;

                if (taskitem.Priority == 1)
                    return
                        element.FindResource("importantTaskTemplate") as DataTemplate;
                else
                    return
                        element.FindResource("myTaskTemplate") as DataTemplate;
            }

            return null;
        }
    }
}

然后,我们可以将 TaskListDataTemplateSelector 声明为资源:

<Window.Resources>


...


<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>


...


</Window.Resources>

若要使用模板选择器资源,请将其分配到 ListBox 的 ItemTemplateSelector 属性。 ListBox 为基础集合中的每一项调用 TaskListDataTemplateSelector 的 SelectTemplate 方法。 该调用会将数据对象作为项参数来传递。 然后,将由该方法返回的 DataTemplate 应用于该数据对象。

 

<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}"
         ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
         HorizontalContentAlignment="Stretch"/>

使用模板选择器后,ListBox 现在如下所示:

[WPF系列-数据邦定之DataTemplate 根据对象属性切换模板

这正是此示例要得到的结果。有关完整示例,请参见 Introduction to Data Templating Sample(数据模板化简介示例)

 

 

使用Style切换模板

<DataTemplate x:Key="personTemplate" TargetType="{x:Type local:TaskModel}">
     <TextBlock Text="I‘m an Open Task" />
</DataTemplate> 

<DataTemplate x:Key="companyTemplate" TargetType="{x:Type local:TaskModel}">
     <TextBlock Text="I‘m a Closed Task" />
 </DataTemplate>

<DataTemplate DataType="{x:Type local:TaskModel}"><ContentControl Content="{Binding}">
  <ContentControl.Style>
    <Style TargetType="ContentControl">
      <Style.Triggers>
        <DataTrigger Binding="{Binding AccountType}" Value="Person">
          <Setter Property="ContentTemplate" Value="{StaticResource personTemplate}" />
        </DataTrigger>
        <DataTrigger Binding="{Binding AccountType}" Value="Company">
          <Setter Property="ContentTemplate" Value="{StaticResource companyTemplate}" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </ContentControl.Style>
</ContentControl>
</DataTemplate>

 

上面这个例子没有给一个默认的ContentTemplate,我们可以改为:

<DataTemplate x:Key="OpenTaskTemplate" TargetType="{x:Type local:TaskModel}">
     <TextBlock Text="I‘m an Open Task" />
</DataTemplate> 

<DataTemplate x:Key="ClosedTaskTemplate" TargetType="{x:Type local:TaskModel}">
     <TextBlock Text="I‘m a Closed Task" />
 </DataTemplate>

<DataTemplate DataType="{x:Type local:TaskModel}">
     <ContentControl Content="{Binding }">
         <ContentControl.Style>
             <Style TargetType="{x:Type ContentControl}">

                 <!-- Default Template -->
                 <Setter Property="ContentTemplate" Value="{StaticResource OpenTaskTemplate}" />

                 <!-- Triggers to change Template -->
                 <Style.Triggers>
                     <DataTrigger Binding="{Binding TaskStatus}" Value="Closed">
                         <Setter Property="ContentTemplate" Value="{StaticResource ClosedTaskTemplate}" />
                     </DataTrigger>
                 </Style.Triggers>
             </Style>
         </ContentControl.Style>
     </ContentControl>
 </DataTemplate>

 

 

比较

方式 优点 缺点
DataTriger    
StyleTriger    
DataTemplateSelector   无法相应propertyChanged事件

 

 

 

参考

Change Data template dynamically

数据模板化概述

[WPF系列-数据邦定之DataTemplate 根据对象属性切换模板

上一篇:如何在kubesphere优雅的使用jmeter集群进行性能测试


下一篇:day6-作业