Blinx
Blinx

Reputation: 400

Items added to ItemsControl not using ItemTemplate

I'm relatively new to wpf so I apologise in advance for any bad coding practices.

I'm trying to create a dashboard application which a user can customise by adding different controls (Tables, Graphs etc.) and move them around/resize them.

I was originally using a Canvas to draw my controls and had the moving and resizing working. Due to needing the content to be dynamic, I switched to using an ItemsControl like so:

<ItemsControl Name="dashboardCanvas" ItemsSource="{Binding Path=CanvasContents}" Grid.Row="1">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.Resources>
            <ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type local:MoveThumb}">
                <Rectangle Fill="Transparent"/>
            </ControlTemplate>
            <ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="Control">
                <Grid>
                    <local:ResizeThumb Height="2" Cursor="SizeNS" Margin="0 -4 0 0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
                    <local:ResizeThumb Width="2" Cursor="SizeWE" Margin="-4 0 0 0" VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
                    <local:ResizeThumb Width="2" Cursor="SizeWE" Margin="0 0 -4 0" VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
                    <local:ResizeThumb Height="2" Cursor="SizeNS" Margin="0 0 0 -4" VerticalAlignment="Bottom"  HorizontalAlignment="Stretch"/>
                    <local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                    <local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0" VerticalAlignment="Top" HorizontalAlignment="Right"/>
                    <local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
                    <local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
                </Grid>
            </ControlTemplate>
            <ControlTemplate x:Key="DesignerItemTemplate">
                <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                    <local:MoveThumb Template="{StaticResource MoveThumbTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Cursor="SizeAll"/>
                    <Control Template="{StaticResource ResizeDecoratorTemplate}"/>
                    <ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
                    <Button Content="x" VerticalAlignment="Top" HorizontalAlignment="Right" Width="10" Height="10" Click="Button_Click"/>
                </Grid>
            </ControlTemplate>
        </ItemsControl.Resources>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                    <local:MoveThumb Template="{StaticResource MoveThumbTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Cursor="SizeAll"/>
                    <Control Template="{StaticResource ResizeDecoratorTemplate}"/>
                    <ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
                    <Button Content="x" VerticalAlignment="Top" HorizontalAlignment="Right" Width="10" Height="10" Click="Button_Click"/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
                <Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

I now have a problem where any controls I add to the ItemsControl do not have the template applied to them.

I've seen this question: Why Does ItemsControl Not Use My ItemTemplate? But I can't inherit ItemsControl into my controls as they already inherit from ContentControls.

Here is my main Control Object:

class TableControl: DashboardItem
{
    public TableControl()
    {
        Width = 100;
        Height = 100;
        Content = new Ellipse
            {
                Fill = new SolidColorBrush(Colors.Green),
                IsHitTestVisible = false
            };
    }

    public int X
    {
        get
        {
            return 10;
        }
    }

    public int Y
    {
        get
        {
            return 200;
        }
    }
}

DashboardItem at the moment is simply:

class DashboardItem : ContentControl
{

}

In the code behind I have an ObservableCollection of DashboardItems, which the ItemsControl is bound to.

How would I force the ItemsControl Template to be applied to all items in the control?

Upvotes: 0

Views: 1040

Answers (2)

Emmanuel DURIN
Emmanuel DURIN

Reputation: 4913

There is strange mix in your code. You must not have an ObservableCollection of ContentControl. Make your objects DashboardItems , real business objets (or viewmodel objets), may be holding X and Y properties, but without inheritance of ContentControl.

It seems that WPF doesn't care of your Template if you provide a GUI object.

If you need to have different appearances for different items of the Items Control, then you 'll be able to use
-a TemplateSelector (for selecting Template for a given line)
-or the DataType property of the DataItemTemplate

Upvotes: 2

Mark A. Donohoe
Mark A. Donohoe

Reputation: 30378

Just adding another solution. As the accepted answer points out, if you use an ItemsControl directly, any GUI objects you pass in will simply be arranged on the ItemsPanel as-is, thus bypassing your DataTemplate entirely. (If it's not a GUI object, it's wrapped in a ContentPresenter first.)

To get around this, you can create a subclass of ItemsControl that you force to always create a container for your items. You do this by returning false for IsItemItsOwnContainerOverride. This tells the control that the item has to be wrapped in a container first--which again, in the default implementation of an ItemsControl is a simple ContentPresenter--and thus it will always apply any given ItemTemplate.

Here's the code...

public class EnsureContainerItemsControl : ItemsControl {

    protected override bool IsItemItsOwnContainerOverride(object item) {
        return false; // Force the control to always generate a container regardless of what was passed in
    }
}

Upvotes: 1

Related Questions