WPF - ItemTemplate не работает должным образом

У меня есть UserControl, который я использую для отображения списка UIElement. Элемент управления состоит из одного ItemsControl, ItemPanelTemplate которого переключен на горизонтальный StackPanel, его ItemsSource привязан к DependencyProperty, предоставленному UserControl, и его ItemTemplate установлен в UserControl.Resources.

Все работает нормально, за исключением того, что ItemTemplate никогда не применяется, и я не понимаю, почему. Полный исходный текст ниже.

UserControl.xaml -

<UserControl x:Name="UC" x:FieldModifier="private" x:Class="ContentSliderControl.ContentSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>

    <DataTemplate x:Key="pageTemplate">
        <Border CornerRadius="10" Padding="5" Height="200" Width="200" Background="#333">
            <ContentControl Content="{Binding}"/>
        </Border>
    </DataTemplate>

    <ItemsPanelTemplate x:Key="template">
        <StackPanel IsItemsHost="True"
            Orientation="Horizontal"
            ScrollViewer.HorizontalScrollBarVisibility="Disabled"
            ScrollViewer.VerticalScrollBarVisibility="Disabled"/>
    </ItemsPanelTemplate>
</UserControl.Resources>

<ItemsControl ItemsPanel="{StaticResource template}" 
              ItemTemplate="{StaticResource pageTemplate}" 
              ItemsSource="{Binding ElementName=UC,Path=Pages}"/>

UserControl.xaml.cs -

[ContentProperty("Pages")]
public partial class ContentSlider : UserControl
{


    public List<UIElement> Pages
    {
        get { return (List<UIElement>)GetValue(PagesProperty); }
        //set { SetValue(PagesProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Pages.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PagesProperty =
        DependencyProperty.Register("Pages", typeof(List<UIElement>), typeof(ContentSlider), new UIPropertyMetadata(null));



    public ContentSlider()
    {
        InitializeComponent();
    }
}

}

Я использую элемент управления в своем главном окне следующим образом:

    <slider:ContentSlider >
    <slider:ContentSlider.Pages>
        <Button>1</Button>
        <Button>2</Button>
        <Button>3</Button>
        <Button>4</Button>
    </slider:ContentSlider.Pages>
</slider:ContentSlider>

Кнопки выглядят нормально, но не внутри квадратной границы 200 пикселей.

Любая помощь будет приветствоваться. Спасибо.


person EightyOne Unite    schedule 19.03.2009    source источник


Ответы (5)


Поскольку это список UIElement, шаблон элемента применяется только в том случае, если элементы не могут быть отображены напрямую.

person Nir    schedule 19.03.2009
comment
Кроме того, если я заменяю ItemsControl на Listbox, они отображаются так, как ожидалось, поэтому я не уверен, что вы правы - person EightyOne Unite; 19.03.2009
comment
Кажется, я должен есть свои слова! Спасибо, Нир. - person EightyOne Unite; 20.03.2009

Nir верен, ItemsControl добавит элемент непосредственно в свой Panel, если они являются UIElements. Я не смог найти упоминания об этом поведении в MSDN, но доктор WPF упоминает его в его статья о контейнерах для предметов:

Если UIElement добавлен в коллекцию Items явного экземпляра ItemsControl (в отличие от экземпляра производного класса, такого как ListBox), он станет прямым дочерним элементом панели элементов. Если добавлен не-UIElement, он будет заключен в ContentPresenter.

Ваше решение, вероятно, состоит в том, чтобы вместо этого использовать ListBox и установить ItemContainerStyle на новый Style для ListBoxItem, и в этом стиле использовать ControlTemplate с вашим Border в нем.

person Robert Macnee    schedule 19.03.2009
comment
Ну разве это не какое-то безумное поведение? Спасибо за это, Роберт, тогда я дам Ниру правильный ответ и проголосую за тебя. Жалко, что у вас не может быть более одного правильного ответа, а? - person EightyOne Unite; 20.03.2009

Нир прав, эта настраиваемая реализация ItemsControl решит проблему и позволит использовать ваш собственный ItemTemplate:

public class ItemsControlForUIElement : ItemsControl
{
   protected override DependencyObject GetContainerForItemOverride()
   {
       return new ContentPresenter();
   }
   protected override bool IsItemItsOwnContainerOverride(object item)
   {
       return false;
   }
}
person bithavoc    schedule 11.08.2009

Роберт Макни поразил причину. Его решение включает использование шаблона управления, который может оказаться излишним для данного сценария. В качестве альтернативы используйте ListBox - установите ItemContainerStyle на новый стиль для ListBoxItem, и в этом стиле установите ContentTemplate на DataTemplate, который вы хотели использовать в ListBox ItemTemplate.

person Brian    schedule 28.05.2011

Если вы установите свойство DataType на DataTemplate, оно начнет работать.

person Steven    schedule 20.03.2009