views:

894

answers:

4

I have a UserControl which I'm using to display a list of UIElements. The control consists of a single ItemsControl with it's ItemPanelTemplate switched for a horizontal StackPanel, its ItemsSource bound to a DependencyProperty exposed by the UserControl and its ItemTemplate set in the UserControl.Resources.

Everything works fine except the ItemTemplate never get's applied and I can't see why. The full source is below.

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"&gt;
<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();
    }
}

}

I consume the control in my main window like this -

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

The buttons appear fine but not inside the 200px square border.

Any help would be greatlly appriciated. Thanks.

+2  A: 

It's because it's a list of UIElement, the item template is only applied if the items can't be displayed directly.

Nir
What would you suggest then?
Stimul8d
Also, if i swap the ItemsControl for a Listbox then they render as expected so I'm not sure you're right there
Stimul8d
Seems I have to eat my words! Thanks Nir.
Stimul8d
+3  A: 

Nir is correct, ItemsControl will add item directly to its Panel if they are UIElements. I couldn't find any mention of this behavior in MSDN, but Dr. WPF mentions it in his article on item containers:

If a UIElement is added to the Items collection of an explicit ItemsControl instance (as opposed to an instance of a derived class like ListBox), it will become a direct child of the items panel. If a non-UIElement is added, it will be wrapped within a ContentPresenter.

Your solution is probably to use a ListBox instead, and set ItemContainerStyle to a new Style for ListBoxItem, and in that style, use a ControlTemplate with your Border in it.

Robert Macnee
Well isn't that some crazy behavior. Thanks for that Robert, I'll give Nir the correct answer then and vote you up. Shame you can't have more than one correct answer eh?
Stimul8d
A: 

If you set the DataType property on the DataTemplate it would start working.

Steven
+2  A: 

Nir is right, this custom ItemsControl implementation will solve the issue and let use your own ItemTemplate:

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