【问题标题】:Why Does ItemsControl Not Use My ItemTemplate?为什么 ItemsControl 不使用我的 ItemTemplate?
【发布时间】:2010-10-01 21:37:09
【问题描述】:

我可以在 ItemsControl 中使用 ItemTemplate 以特定格式呈现项目。但是,如果 ItemsControl 中的某个项目碰巧是一个 TextBox,则呈现该 TextBox 而不是 ItemsTemplate 的一个实例。据我所知,任何 FrameworkElement 都是如此。这是 ItemsControl 的预期行为,还是我做错了什么?

一个例子:

<ItemsControl>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Grid Margin="5">
        <Rectangle Fill="Blue" Height="20" Width="20" />
      </Grid>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
  <ItemsControl.Items>
    <sys:Object />
    <TextBox />
    <sys:Object />
    <Rectangle Fill="Red" Height="20" Width="20" />
  </ItemsControl.Items>
</ItemsControl>

我希望这会显示四个蓝色矩形。我认为任何时候定义了 ItemTemplate 集合中的每个项目都会呈现为模板的实例。但是,在这种情况下,会呈现以下内容:一个蓝色矩形,后跟一个 TextBox,然后是一个蓝色矩形,然后是一个红色矩形。

【问题讨论】:

  • 我猜这是有意的行为,旨在让开发人员能够添加特殊的一次性使用控件。例如,我可能会使用它向 ComboBox 添加一个按钮以清除选择,或者我可能将一个 TextBox 放入一个过滤由 ItemsSource 指定的集合的 ListBox 中。我很想听到有人对这种行为有一些官方答案,因为我发现使用 ItemTemplate 违反直觉。
  • Anthony 提出的好问题和好答案,谢谢大家。
  • 它无疑是 UI 和数据模型的混搭。嗯。但是,一个人假设,作为一种优化,它希望减轻ItemsControl繁忙的工作,因此它必须包装它遇到的每个 POCO 实例。特别是因为ItemsPanel 中的ScrollViewer 可以迅速牵连成百上千个这些所谓的“容器”。这可能是一个纯粹的选择加入功能(即如果对 IsItemItsOwnContainerOverride 的基本调用总是返回 false)而不是 WPF 强行插入以断言您报告的意外行为可能会更好。

标签: wpf silverlight itemscontrol itemtemplate


【解决方案1】:

ItemsControl 有一个受保护的成员 IsItemItsOwnContainerOverride,它从项目集合中传递一个对象,如果该对象可以直接添加到项目面板而无需生成容器(从而被模板化),则返回 true

对于派生自 UIElement 的任何对象,基本实现返回 true。

要获得您期望的行为,您需要从 ItemsControl 继承并覆盖此方法并使其始终返回 false。不幸的是,事情还没有结束。如果项目是UIElementPrepareContainerForItemOverride 的默认实现仍然不会将ItemTemplate 分配给容器,因此您还需要覆盖此方法:-

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return false;
    }


    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item);
        ((ContentPresenter)element).ContentTemplate = ItemTemplate;
    }

【讨论】:

  • 截至 2015 年,他们可能已经修复了第二部分。使用 .NET 4.5.1 中的 WPF,如果我为 IsItemItsOwnContainerOverride, 返回 false,则模板似乎设置在项目容器上。
  • 我在 .NET 4 中也不需要 PrepareContainerForItemOverride 覆盖。
【解决方案2】:

我只是在这里推测,但我敢打赌这是ItemContainerGenerator 内部的行为。我敢打赌,ItemContainerGenerator 会查看一个项目,如果是 UIElement,它会说,“酷,项目容器已经生成,我会返回它”,如果不是,它会说,“我'最好为这个项目生成一个容器。DataTemplate在哪里?"

【讨论】:

  • 不,逻辑实际上是在ItemsControl 本身中实现的,在IGeneratorHost.GetContainerForItem(…) 的显式接口实现中,它发出IsItemItsOwnContainerOverride 查询,然后调用GetContainerForItemOverride — 或将数据项转换为DependencyObject。后者实际上是这里的最低要求,这就引出了一个问题,为什么IsItemItsOwnContainerOverride 的默认行为有比必要更严格的要求(即UIElement)?也许——正如我在上面提到的——让这个 WPF“功能”不再发挥作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-24
  • 1970-01-01
相关资源
最近更新 更多