2

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'
Luboš Suk
  • 1,526
  • 14
  • 38
  • 3
    An items collection in a view model should not contain UI elements. Instead, the collection should contain data items, to which the elements in your DataTemplates are bound (like in [this example](https://stackoverflow.com/a/22325266/1136211)). – Clemens Apr 17 '18 at 14:23
  • @Clemens thanks for hint, im aware of this, but i cannot imagine how i can use this approach with my SingleNodeControl. Its something like container for multiple elements (img, labels, texboxes etc). How i fill in data for these subelements without creating it in code? – Luboš Suk Apr 17 '18 at 15:15
  • 1
    your items collection may be an `IEnumerable`, i.e. contain anything. Then you declare different DataTemplates for different item types. – Clemens Apr 17 '18 at 15:17
  • Clemens is right. Go see the example at the link. Each type of element should be its own type with whatever properties that element requires. Put them in an ObservableCollection bound to your UI, and use DataTemplates to create UI for each element type. –  Apr 17 '18 at 16:54
  • 1
    Your lines are probably there, but all at `0,0` in the Canvas. An ItemsControl wraps each item in a ``, and you need to bind the position in the `ItemsContainerStyle` so the positioning gets applied to the `ContentPresenter` rather than to the element inside that tag. I wrote [a blog post](https://rachel53461.wordpress.com/2011/09/17/wpf-itemscontrol-example/) about this a long while back, with some visual examples so you can see what is actually being rendered. Perhaps that might help explain it? – Rachel Apr 18 '18 at 16:17

1 Answers1

2

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.

Andy
  • 11,864
  • 2
  • 17
  • 20