首页 > 解决方案 > 应用于不同模型的 Listbox DataTemplate

问题描述

我有两个表,其中也只包含一个作为键的值。我创建了一个列表框来显示和修改它。

我写了这个DataTemplate

<DataTemplate x:Key="ListboxItems">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <Label Grid.Column="0" Content="{Binding}" />
        <StackPanel Grid.Column="1" Orientation="Horizontal">
            <!--  edit to swap with save  -->
            <Button
                Content="&#xE74E;"
                ContentTemplate="{StaticResource IconPanelButton}"
                DockPanel.Dock="Right"
                Style="{StaticResource MahApps.Styles.Button.Flat}"
                ToolTipService.ToolTip="Save"
                Visibility="{Binding IsVisible}" />
            <!--  Cancel - visible only on edit  -->
            <Button
                Click="LockUnlock_Click"
                Content="{Binding Icon}"
                ContentTemplate="{StaticResource IconPanelButton}"
                DockPanel.Dock="Right"
                Style="{StaticResource MahApps.Styles.Button.Flat}"
                ToolTipService.ToolTip="{Binding ToolTip}" />
            <!--  Delete  -->
            <Button
                Click="LockUnlock_Click"
                Content="{Binding Icon}"
                ContentTemplate="{StaticResource IconPanelButton}"
                DockPanel.Dock="Right"
                Style="{StaticResource MahApps.Styles.Button.Flat}"
                ToolTipService.ToolTip="{Binding ToolTip}" />
            <!--  Add  -->
            <Button
                Click="LockUnlock_Click"
                Content="{Binding Icon}"
                ContentTemplate="{StaticResource IconPanelButton}"
                DockPanel.Dock="Right"
                Style="{StaticResource MahApps.Styles.Button.Flat}"
                ToolTipService.ToolTip="{Binding ToolTip}" />
        </StackPanel>
    </Grid>
</DataTemplate>

这是列表框,但我无法让它按我的意愿工作。

如果我这样离开它:

<Label Grid.Column="0" Content="{Binding}" />

我没有看到文字,而是看到类型TTypes1or TTypes2

但如果我写:

<Label Grid.Column="0" Content="{Binding Type1}" />

然后我不能在TType2列表框中使用它。

这是我使用它的地方:

<ScrollViewer
    Margin="2"
    HorizontalScrollBarVisibility="Auto"
    VerticalScrollBarVisibility="Auto">
    <ListBox
        Margin="2"
        AlternationCount="2"
        BorderThickness="1"
        ItemsSource="{Binding TTypes1}"
        SelectedIndex="0"
        SelectionMode="Single"
        ItemTemplate="{StaticResource ListboxItems}"
        Style="{StaticResource MahApps.Styles.ListBox.Virtualized}">
    </ListBox>
</ScrollViewer>

第二个是:

<ScrollViewer
    Margin="2"
    HorizontalScrollBarVisibility="Auto"
    VerticalScrollBarVisibility="Auto">
    <ListBox
        Margin="2"
        AlternationCount="2"
        BorderThickness="1"
        ItemsSource="{Binding TTypes2}"
        SelectedIndex="0"
        SelectionMode="Single"
        ItemTemplate="{StaticResource ListboxItems}"
        Style="{StaticResource MahApps.Styles.ListBox.Virtualized}">
    </ListBox>
</ScrollViewer>

我错过了什么?

标签: wpfxaml.net-coredata-bindingdatatemplate

解决方案


多个数据模板

处理这种情况的常用方法是为每种类型创建一个不同的数据模板,例如 forTType1TType2

<DataTemplate x:Key="ListboxItemsTType1"
              DataType="{x:Type local:TType1}">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="*" />
         <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>

      <Label Grid.Column="0"
             Content="{Binding Type1}" />
      <!-- ...other markup. -->
   </Grid>
</DataTemplate>
<DataTemplate x:Key="ListboxItemsTType2"
              DataType="{x:Type local:TType2}">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="*" />
         <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>

      <Label Grid.Column="0"
             Content="{Binding Type2}" />
      <!-- ...other markup. -->
   </Grid>
</DataTemplate>

ListBox在你的es中引用具体的模板。您还可以x:Key从数据模板中删除 ,因此它们会自动应用于ListBox. 这也适用于列表中的混合项目。

<ScrollViewer Grid.Row="0"
              Margin="2"
              HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Auto">
   <ListBox
      ItemTemplate="{StaticResource ListboxItems}"
      ...
   </ListBox>
</ScrollViewer>
<ScrollViewer Grid.Row="1"
              Margin="2"
              HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Auto">
   <ListBox
      ...
      ItemTemplate="{StaticResource ListboxItems}"
   </ListBox>
</ScrollViewer>

其他方法

如果您真的想保留单个数据模板,则必须根据绑定为数据上下文的对象的项目类型来切换绑定。有多种方法可以实现这一目标。

这是一个使用转换器的示例,该转换器将对象从相关问题转换为其类型,复制它。样式将使用数据触发器来应用基于该类型的正确绑定。Label

<local:DataTypeConverter x:Key="DataTypeConverter" />

<DataTemplate x:Key="ListboxItems">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="*" />
         <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>

      <Label Grid.Column="0">
         <Label.Style>
            <Style TargetType="{x:Type Label}"
                   BasedOn="{StaticResource {x:Type Label}}">
               <Setter Property="Content"
                       Value="{x:Null}" />
               <Style.Triggers>
                  <DataTrigger Binding="{Binding Converter={StaticResource DataTypeConverter}}"
                               Value="{x:Type local:TType1}">
                     <Setter Property="Content"
                             Value="{Binding Type1}" />
                  </DataTrigger>
                  <DataTrigger Binding="{Binding Converter={StaticResource DataTypeConverter}}"
                               Value="{x:Type local:TType2}">
                     <Setter Property="Content"
                             Value="{Binding Type2}" />
                  </DataTrigger>
               </Style.Triggers>
            </Style>
         </Label.Style>
      </Label>
      <StackPanel Grid.Column="1"
                  Orientation="Horizontal">
         <!--  edit to swap with save  -->
         <Button Content="&#xE74E;"
                 ContentTemplate="{StaticResource IconPanelButton}"
                 DockPanel.Dock="Right"
                 Style="{StaticResource MahApps.Styles.Button.Flat}"
                 ToolTipService.ToolTip="Save"
                 Visibility="{Binding IsVisible}" />
         <!--  Cancel - visible only on edit  -->
         <Button Click="LockUnlock_Click"
                 Content="{Binding Icon}"
                 ContentTemplate="{StaticResource IconPanelButton}"
                 DockPanel.Dock="Right"
                 Style="{StaticResource MahApps.Styles.Button.Flat}"
                 ToolTipService.ToolTip="{Binding ToolTip}" />
         <!--  Delete  -->
         <Button Click="LockUnlock_Click"
                 Content="{Binding Icon}"
                 ContentTemplate="{StaticResource IconPanelButton}"
                 DockPanel.Dock="Right"
                 Style="{StaticResource MahApps.Styles.Button.Flat}"
                 ToolTipService.ToolTip="{Binding ToolTip}" />
         <!--  Add  -->
         <Button Click="LockUnlock_Click"
                 Content="{Binding Icon}"
                 ContentTemplate="{StaticResource IconPanelButton}"
                 DockPanel.Dock="Right"
                 Style="{StaticResource MahApps.Styles.Button.Flat}"
                 ToolTipService.ToolTip="{Binding ToolTip}" />
      </StackPanel>
   </Grid>
</DataTemplate>

其他完全依赖代码但更易于重用的选项是:

  • 创建一个与触发器执行相同操作的特殊值转换器,返回在代码中创建的绑定,该绑定具有基于类型的属性路径
  • 创建一个自定义标记扩展,根据类型自动选择属性路径

我没有提供这些选项的示例,因为它们很复杂并且很大程度上取决于您的要求。此外,我推荐第一种方法来创建多个数据模板,因为我认为从维护和灵活性的角度来看这是最有利的。


推荐阅读