Почему ItemsControl Не Использует Мой ItemTemplate?

Я могу использовать ItemTemplate в ItemsControl для отображения элементов в определенном формате. Однако, если один из элементов в ItemsControl является, скажем, текстовым полем, это текстовое поле отображается, а не экземпляр 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 определен, каждый элемент в коллекции отображается как экземпляр шаблона. Однако в этом случае отображается следующее: синий прямоугольник, за которым следует текстовое поле, затем синий прямоугольник, за которым следует красный прямоугольник.

2 ответов


на ItemsControl имеет защищенный который передается объект из коллекции items и возвращает true если этот объект может быть добавлен непосредственно на панель элементов без сгенерированного контейнера (и, следовательно, быть шаблоном).

базовая реализация возвращает true для любого объекта, производного от UIElement.

чтобы получить поведение, которое вы ожидаете, вам нужно будет унаследовать от ItemsControl и переопределить этот метод и всегда возвращать false. К сожалению, это еще не все. Реализация по умолчанию PrepareContainerForItemOverride все еще не назначает ItemTemplate в контейнере, если элемент UIElement поэтому вам также нужно переопределить этот метод: -

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


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

Я просто спекулирую здесь, но я бы поспорил, что это поведение, которое живет внутри ItemContainerGenerator. Держу пари, что ItemContainerGenerator смотрит на элемент, и если это UIElement Он говорит:" круто, контейнер элемента был сгенерирован, я просто верну его", и если это не так, он говорит: "мне лучше сгенерировать контейнер для этого элемента. Где DataTemplate?"