Luboš Suk
Luboš Suk

Reputation: 1546

Multiple dataTemplates in ItemsControl and Canvas

Im trying to display some boxes (my own userControl defined in its own xaml file called singleNodeControl) on canvas and connect them with lines (normal xaml Line element binded to LineToParent class)

Both these two items are stored in Binding list in viewModel which is <UserControl> type. Both of these classes (boxes and lines) extending UserControl class so i can store them into single Binding list (canvasNodeSourceList)

SingleNodeControl class containt code in .cs file and also template in .xaml file.

LineToParent class contains only .cs code, where i store X1,X2,Y1,Y2 coordiantes to bind them later.

xaml with itemsControl looks. Which i thought works that if item in canvasNodeSourceList is type LineToParent it will use template bellow othervise it will use template stored in singleNodeControl xaml file (more bellow).

But it looks like that dataTemplate for line isnt used. SingleNodeCOntrols are drawed, but lines arent. What with templates am i missing? And is it even possible to define some template in external file and some in Items Control?

I just wana to display some boxes (which needs on xaml definition because they will have multiple inside elements) which can be connected by lines.

<ItemsControl x:Name="content" ItemsSource="{Binding canvasNodeSourceList}">                    
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate >
            <Canvas x:Name="contentCanvas" Background="White" Width="{Binding Width}" Height="{Binding Height}"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>                   
    <ItemsControl.Resources>
    <DataTemplate DataType="{x:Type slider:LineToParent}">
              <!--<Line X1="100" Y1="100" X2="10000" Y2="10000" StrokeThickness="5" Stroke="RED"></Line>-->
            <Line X1="{Binding leftPos1}" Y1="{Binding topPos1}" X2="{Binding leftPos2}" Y2="{Binding topPos2}" StrokeThickness="5" Stroke="Black"></Line>
        </DataTemplate>

    </ItemsControl.Resources>                  
</ItemsControl>

SingleNodeControl xaml file

<UserControl x:Class="WHS_qa.View.SingleNodeControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WHS_qa.View"
         mc:Ignorable="d"              
         >
<Grid>
    <Border BorderBrush="Black" BorderThickness="2">
        <StackPanel Name="NodeStackPanel">


        </StackPanel>
    </Border>

</Grid>

I also tried to modify itemsControl to look like this (changed itemsControl.Resource to itemsControl.itemTemplate) and testline was displayed (with all singleNodeControl elements) But output was full of errors

<ItemsControl x:Name="content" ItemsSource="{Binding canvasNodeSourceList}">                    
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate >
            <Canvas x:Name="contentCanvas" Background="White" Width="{Binding Width}" Height="{Binding Height}"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>                   
    <ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type slider:LineToParent}">
              <Line X1="100" Y1="100" X2="10000" Y2="10000" StrokeThickness="5" Stroke="RED"></Line>
            <!--<Line X1="{Binding leftPos1}" Y1="{Binding topPos1}" X2="{Binding leftPos2}" Y2="{Binding topPos2}" StrokeThickness="5" Stroke="Black"></Line>-->
        </DataTemplate>

    </ItemsControl.ItemTemplate>                  
</ItemsControl>

Errors in output

System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='SingleNodeControl'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='SingleNodeControl'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='SingleNodeControl'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'

Upvotes: 2

Views: 3367

Answers (1)

Andy
Andy

Reputation: 12276

When you're styling based on type, you don't want an itemtemplate. This is because your template is going to be based on datatype.
You do, however, want datatemplates for all the datatypes you will put in the itemssource of your itemscontrol.

This sample does the canvas in an itemscontrol thingm, templating out various objects:

https://1drv.ms/u/s!AmPvL3r385QhgooJ94uO6PopIDs4lQ

 <ItemsControl x:Name="ic" ItemsSource="{Binding Items}"
                      Background="{StaticResource bgroundImage}">
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type local:RectangleVM}">
                    <Rectangle Stroke="Green" Fill="White" 
                               Width="{Binding Width,Mode=TwoWay}"
                               Height="{Binding Height,Mode=TwoWay}"/>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:CircleVM}" >
                    <StackPanel>
                        <Ellipse Stroke="Red" Fill="White" 
                                 Width="{Binding EllipseWidth}" 
                                 Height="{Binding EllipseHeight}"
                                 />
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:TextBoxVM}">
                    <TextBox Text="{Binding TbText}"/>
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Name="TheCanvas"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Top" Value="{Binding Top}"/>
                    <Setter Property="Canvas.Left" Value="{Binding Left}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>

You also probably want the binding for canvas.left and canvas.top on the item container.

All the types presented are fairly different in that sample. If you have similar sort of items you can use a base class for most or some of these and that will be recognised even if you present a subtype.

Upvotes: 2

Related Questions