Wpf数据模板 - 如何访问ItemsControl中项目的父项?

时间:2013-07-05 22:56:22

标签: wpf xaml

我处境很奇怪。我正在生成按特定类别分组的项目列表。在我的视图模型中,我将项目存储在ReadOnlyDictionary<string, List<CustomObject>>的实例中,其中CustomObject表示我为存储每个列表项而创建的类。字符串是类别。在我看来,我的StackPanel里面有一个<ItemsControl>。 items控件有一个ItemTemplate,如下所示:

<DataTemplate x:Key="DataTemplateName">
    <StackPanel>
        <Separator />
        <TextBlock Text="{Binding Key}" />
        <ItemsControl ItemsSource="{Binding Value}" />
    </StackPanel>
</DataTemplate>

上面的绑定工作得很好。问题是我不希望第一个项目上方有分隔符。所以我想第一个项目我需要一个不同的风格。

我尝试使用ItemTemplateSelector,但问题是它只能访问当前项,因此无法知道它是否在第一个元素上。我也尝试过像

这样的事情
<Separator 
    Visibility={Binding ShowSeparator, RelativeSource={RelativeSource AncestorType={x:Type CustomObject}}}" />

...其中ShowCategories是CustomObject类中的依赖项属性,它查看ReadOnlyDictionary实例并说明是否显示分隔符。但是,当我这样做时,从不访问ShowCategories。我想即使它是,它也无法知道哪个项目正在调用它。

因此。我该怎么办?

2 个答案:

答案 0 :(得分:0)

我会选择MVVM方法:

  1. CustomObjectViewModel 保留在Dictionary中而不是CustomObject中,并使用 CustomObject作为其模型

  2. 在CustomObjectViewModel中,可以访问 CustomObjectService (或为了简单起见,对字典的引用)。

  3. 在上述服务中,有一个类似于:

    的方法

    Public Boolean IsCustomObjectFirst(CustomObjectViewModel vm){..}

    显然,这将检查给定项目的位置。

  4. 现在只需在 CustomObjectViewModel 中添加一个属性ShouldDisplaySeperator即可从CustomObjectService.IsCustomObjectFirst(this)

  5. 获取其值
  6. 现在只需在View的定义中使用它,使用类似于:

    的内容

    查看定义:

    <DataTemplate x:Key="DataTemplateName">
        <StackPanel>
            <Separator Visibilty="{Binding ShouldDisplaySeperator,Converter={StaticResource BooleanToVisibilityConverter}}" />
            <TextBlock Text="{Binding Model.Key}" />
            <ItemsControl ItemsSource="{Binding Model.Value}" />
        </StackPanel>
    </DataTemplate>
    

答案 1 :(得分:0)

您可以执行此操作,而无需在VM中添加新属性或使用ItemTemplateSelector

我更喜欢将它保留在xaml中,因为它只是View相关而且与任何需要“测试”的逻辑无关

因此xaml解决方案可能是使用ItemsControl.AlternationIndex

类似的东西:

<ListBox AlternationCount="{Binding RelativeSource={RelativeSource Self}, Path=ItemsSource.Count, Mode=OneWay}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel>
        <Separator x:Name="seperator" />
        <TextBlock Text="{Binding Key}" />
        <ItemsControl ItemsSource="{Binding Value}" />
      </StackPanel>
      <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=(ListBox.AlternationIndex),
                                        RelativeSource={RelativeSource FindAncestor,
                                                                      AncestorType={x:Type ListBoxItem}}}"
                      Value="0">
          <Setter TargetName="seperator"
                  Property="Visibility"
                  Value="Hidden" />
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

此代码段的两个关键部分。

  • 我们将AlternationCount上的ListBox指定为与ItemSource.Count相同的AlternationIndex,从而在每个ListBoxItem上生成唯一的DataTemplate.DataTrigger
  • AlternationIndex只检查当前项目以查看seperator是否为0,如果是,则隐藏{{1}}。