2

based on ItemsControl only shows first Item of each object I need your help again. The solution worked out very well but after vacation and doing other stuff I need to modify it.

Actually there are Objects (CanvasObject) which are drawn on startup/after reading xml data and others (Module) which are dropped into the canvas from a treeview. These Modules are showing up in the canvas visual children but I cant see them at the canvas.

This is my code so far - I tried different approaches but always got similar results:

C#:

public class CanvasLine
{
    public Point P1 { get; set; }
    public Point P2 { get; set; }
    public Brush Stroke { get; set; }
    public double StrokeThickness { get; set; }
    public DoubleCollection StrokeDashArray { get; set; }
}

public class CanvasObject
{
    public String Name { get; set; }
    public ObservableCollection<CanvasLine> CanvasLines { get; set; }
}

public class Module
{
    public Dictionary<String, String> Attributes { get; set; }
    public Point AnchorPoint { get; set; }
    public Double Height { get; set; }
    public Double Width { get; set; }
}

public class ViewModel
{
    ...
    public ObservableCollection<Object> CanvasObjects;
    ...
}

The Viewmodels ObservableCollection<Object> gets filled with CanvasObjects from a xml - these ones are shown correctly. After that I'm adding Modules to that Collection by dropping them to the canvas. These ones seems to be into the canvas children collection but are not visible.

Here is the corresponding / cleaned up XAML:

        <ItemsControl Grid.Column="1" Grid.Row="2" Margin="0" ItemsSource="{Binding CanvasObjects, UpdateSourceTrigger=PropertyChanged}">
        <ItemsControl.Resources>
            <ScaleTransform x:Key="LineTransform"
                            ScaleX="{Binding ActualWidth,
                 RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                            ScaleY="{Binding ActualWidth,
                 RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Background="Transparent" AllowDrop="True" Drop="Canvas_OnDrop"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplateSelector>
            <xmlTemp:TemplateSelector>
                <xmlTemp:TemplateSelector.ModuleTemplate>
                    <DataTemplate DataType="{x:Type xmlElements:Module}">
                        <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource Self}}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Canvas/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemContainerStyle>
                                <Style TargetType="ContentPresenter">
                                    <Setter Property="Canvas.Left" Value="{Binding AnchorPoint.X}"/>
                                    <Setter Property="Canvas.Top" Value="{Binding AnchorPoint.Y}"/>
                                </Style>
                            </ItemsControl.ItemContainerStyle>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Rectangle Width="{Binding Width}" Height="{Binding Height}" StrokeThickness="2" Fill="Black" Stroke="Black">
                                        <Rectangle.RenderTransform>
                                            <StaticResource ResourceKey="LineTransform"/>
                                        </Rectangle.RenderTransform>
                                    </Rectangle>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </DataTemplate>
                </xmlTemp:TemplateSelector.ModuleTemplate>
                <xmlTemp:TemplateSelector.LineObjectTemplate>
                    <DataTemplate DataType="{x:Type dt:CanvasObject}">
                        <ItemsControl ItemsSource="{Binding CanvasLines}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Canvas/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Path Stroke="{Binding Stroke}"
                                  StrokeDashArray="{Binding StrokeDashArray}">
                                        <Path.Data>
                                            <LineGeometry
                                                Transform="{StaticResource LineTransform}"
                                                StartPoint="{Binding P1}"
                                                EndPoint="{Binding P2}"/>
                                        </Path.Data>
                                        <Path.Style>
                                            <Style TargetType="Path">
                                                <Style.Triggers>
                                                    <Trigger Property="IsMouseOver" Value="True">
                                                        <Setter Property="StrokeThickness">
                                                            <Setter.Value>
                                                                <MultiBinding Converter="{StaticResource MultiplicationConverter}">
                                                                    <Binding Path="StrokeThickness" Mode="OneWay"/>
                                                                    <Binding Source="3"/>
                                                                </MultiBinding>
                                                            </Setter.Value>
                                                        </Setter>
                                                    </Trigger>
                                                    <Trigger Property="IsMouseOver" Value="False">
                                                        <Setter Property="StrokeThickness" Value="{Binding StrokeThickness, Mode=OneWay}"/>
                                                    </Trigger>
                                                </Style.Triggers>
                                            </Style>
                                        </Path.Style>
                                    </Path>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </DataTemplate>
                </xmlTemp:TemplateSelector.LineObjectTemplate>
            </xmlTemp:TemplateSelector>
        </ItemsControl.ItemTemplateSelector>
    </ItemsControl>

Here are the missing event and template selector:

private void Canvas_OnDrop(Object sender, DragEventArgs e)
    {
        Module Module = e.Data.GetData("Module") as Module;
        Canvas Canvas = sender as Canvas;
        if (Module != null && Canvas != null)
        {
            Module.Width = 0.1;
            Module.Height = 0.2;

            Module.AnchorPoint = e.GetPosition(Canvas);
            ViewModel.CanvasObjects.Add(Module);
        }
    }

public class TemplateSelector : DataTemplateSelector
{
    public DataTemplate LineObjectTemplate { get; set; }
    public DataTemplate ModuleTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is CanvasObject)
            return LineObjectTemplate;
        if (item is Module)
            return ModuleTemplate;
        return base.SelectTemplate(item, container);
    }
}

If I'm changing the ModuleTemplates ItemsControl to a ListBox I can see at least that there is some selected element in the top left corner after dropping a Module somewhere in the canvas. I'm thinking that the Rectangles Container might have no size but I'm not sure how to handle that correctly. Also the dropping position has no effect.

Possibly it's just a stupid error, just like the transparent, not dropable/hitable background which costs me over an hour today and I'm "seeing" it tomorrow after a few hours of sleep but every help and hint is highly appreciated!

Greetings

Edit:

THX to elgonzo I found the error. The Modules ItemsControl was unnecessary! THX again, perfect time to finish work now ;)

Following Code works fine:

        <ItemsControl Grid.Column="1" Grid.Row="2" Margin="0" ItemsSource="{Binding CanvasObjects, UpdateSourceTrigger=PropertyChanged}">
    <ItemsControl.Resources>
        <ScaleTransform x:Key="LineTransform"
                        ScaleX="{Binding ActualWidth,
             RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                        ScaleY="{Binding ActualWidth,
             RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
    </ItemsControl.Resources>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Transparent" AllowDrop="True" Drop="Canvas_OnDrop"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplateSelector>
        <xmlTemp:TemplateSelector>
            <xmlTemp:TemplateSelector.ModuleTemplate>
                    <DataTemplate DataType="{x:Type xmlElements:Module}">
                        <DataTemplate.Resources>
                            <Style TargetType="ContentPresenter">
                                <Setter Property="Canvas.Left" Value="{Binding AnchorPoint.X}"/>
                                <Setter Property="Canvas.Top" Value="{Binding AnchorPoint.Y}"/>
                            </Style>
                        </DataTemplate.Resources>
                        <Rectangle Width="{Binding Width}" Height="{Binding Height}" StrokeThickness="2" Fill="Black" Stroke="Black">
                            <Rectangle.RenderTransform>
                                <StaticResource ResourceKey="LineTransform"/>
                            </Rectangle.RenderTransform>
                        </Rectangle>
                    </DataTemplate>
            </xmlTemp:TemplateSelector.ModuleTemplate>
            <xmlTemp:TemplateSelector.LineObjectTemplate>
                <DataTemplate DataType="{x:Type dt:CanvasObject}">
                    <ItemsControl ItemsSource="{Binding CanvasLines}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <Canvas/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Path Stroke="{Binding Stroke}"
                              StrokeDashArray="{Binding StrokeDashArray}">
                                    <Path.Data>
                                        <LineGeometry
                                            Transform="{StaticResource LineTransform}"
                                            StartPoint="{Binding P1}"
                                            EndPoint="{Binding P2}"/>
                                    </Path.Data>
                                    <Path.Style>
                                        <Style TargetType="Path">
                                            <Style.Triggers>
                                                <Trigger Property="IsMouseOver" Value="True">
                                                    <Setter Property="StrokeThickness">
                                                        <Setter.Value>
                                                            <MultiBinding Converter="{StaticResource MultiplicationConverter}">
                                                                <Binding Path="StrokeThickness" Mode="OneWay"/>
                                                                <Binding Source="3"/>
                                                            </MultiBinding>
                                                        </Setter.Value>
                                                    </Setter>
                                                </Trigger>
                                                <Trigger Property="IsMouseOver" Value="False">
                                                    <Setter Property="StrokeThickness" Value="{Binding StrokeThickness, Mode=OneWay}"/>
                                                </Trigger>
                                            </Style.Triggers>
                                        </Style>
                                    </Path.Style>
                                </Path>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </DataTemplate>
            </xmlTemp:TemplateSelector.LineObjectTemplate>
        </xmlTemp:TemplateSelector>
    </ItemsControl.ItemTemplateSelector>
</ItemsControl>
Sven.L
  • 45
  • 1
  • 9
  • In order to draw different kinds of shapes or geometries, you may use an approach like this: https://stackoverflow.com/a/40190793/1136211 – Clemens Mar 22 '18 at 17:09
  • Why do you do `` in the datatemplate for a Module? What do you think this binding achieves? (Check documentation for RelativeSource Self: https://msdn.microsoft.com/en-us/library/system.windows.data.relativesourcemode(v=vs.110).aspx) I think that you did not want to assign the ItemsControl itself to the ItemsSource property... –  Mar 22 '18 at 17:12
  • Also, what is the purpose of that ItemsControl inside the datatemplate for a Module? Is it to display the Attributes dictionary? –  Mar 22 '18 at 17:20
  • Actually this `ItemsSource="{Binding RelativeSource={RelativeSource Self}}"` is a leftover from trying different things. When moving to a Collection of Objects and the TemplateSelector i was not sure if it's a problem that the modules itemscontrol template has not itemssource set because all bound properties are at the top level - in contrast do the canvasobjects. I should have deleted this before posting because it had no effect. – Sven.L Mar 22 '18 at 17:24
  • No, the Attributes dictionary has no visual representation at this point. This might be the problem since the Module Object has no internal collection or something like that. I'm going to give that a quick try before finishing work for today. Maybe it's just a stupid copy/paste leftover... – Sven.L Mar 22 '18 at 17:30
  • @Clemens I'll have a deeper look into your approach tomorrow, but since I have to learn much more WPF Stuff i'm pretty sure my approach is not the perfect one. Due to deadlines and a step by step design of that software I have to do some compromises on the other hand. – Sven.L Mar 22 '18 at 17:34

0 Answers0