2010-10-01 3 views
7

Я могу использовать ItemTemplate в ItemsControl для рендеринга элементов в определенном формате. Однако, если одним из элементов в ItemsControl является, скажем, TextBox, то TextBox визуализируется, а не экземпляр ItemsTemplate. Из того, что я могу сказать, это верно для любого элемента FrameworkElement. Является ли это предполагаемым поведением для ItemsControl, или я делаю что-то неправильно?Почему ItemsControl не использует мой ItemTemplate?

Пример:

<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, за которым следует синий прямоугольник, за которым следует красный прямоугольник.

+0

Я предполагаю, что это предназначено поведение, и чтобы разработчики могли добавлять специальные одноразовые элементы управления. Например, я могу использовать это, чтобы добавить кнопку в ComboBox, которая очищает выбор, или я могу поместить TextBox в ListBox, который фильтрует коллекцию, указанную в ItemsSource. Мне бы очень хотелось услышать, что у кого-то есть официальный ответ на это поведение, потому что я нашел это противоречивым для использования ItemTemplate. – Drew

+0

Отличный вопрос и отличный ответ от Энтони, спасибо, ребята. – Golvellius

ответ

12

ItemsControl имеет защищенный элемент IsItemItsOwnContainerOverride который передается объектом из коллекции предметов и возвращает 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; 
    } 
+1

С 2015 года они могли бы зафиксировать вторую часть. С WPF в .NET 4.5.1, если я верну 'false' для' IsItemItsOwnContainerOverride ', то шаблон, как представляется, будет установлен в контейнере элементов. –

2

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