2
votes

I have a ListBox with a Canvas ItemsPanel. Items in this list are LabeledArrows:Labeled arrow example

LabeledArrow is just a view model class (non visual) that exposes properties like Start_X, Start_Y (arrow start), End_X, End_Y (arrow head) and Box_X, Box_Y (box possition) The ListBoxItem DataTemplate for the LabeledArrow is shown below.
The binding of ArrowLine X1, Y1, x2, Y2 to LabeledArrow Start_X, Start_Y etc properties works fine because ArrowLine has exposed coordinate properties (X1 etc). The box however is just TextBlock so I have to somehow set Canvas.Top and Canvas.Left attatched properties to possition it - but the binding as its shown below doesn't work.
Any ideas? Do I need to resort to wrapping LabeledArrow up as a UserControl?

<ListBox.Resources>         
<DataTemplate DataType="{x:Type tp:LabledArrow}">
    <Grid>
    <tp:ArrowLine Stroke="Red" StrokeThickness="2"
          X1="{Binding Path=Start_X}" Y1="{Binding Path=Start_Y}"
          X2="{Binding Path=End_X}" Y2="{Binding Path=End_Y}" />
    <TextBlock Text="{Binding Path=Value}"
               **Canvas.Left="{Binding Path=Box_X}"
               Canvas.Top="{Binding Path=Box_Y}"** />
    </Grid>
</DataTemplate>
</ListBox.Resources>

<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
        <Canvas IsItemsHost="True"  />
    </ItemsPanelTemplate>
</ListBox.ItemsPanel>
2

2 Answers

2
votes

You set the attached properties Canvas.Left and Canvas.Top on your TextBox, but the parent of the TextBox is a Grid. Attached properties are sometimes used to tell the parent of the Control how to layout this element. Canvas, Grid and DockPanel do that for example. What you want is set both properties on the item container, which is the direct child of the Canvas. The container uses the DataTemplate to display its content.

To do that add this to your ListBox

<ListBox.ItemContainerStyle>
    <Style>
        <Setter Property="Canvas.Left" Value="{Binding Path=Box_X}"/>
        <Setter Property="Canvas.Top" Value="{Binding Path=Box_Y}"/>
    </Style>
</ListBox.ItemContainerStyle>
0
votes

Just a wild guess...

  1. You could wrap your LabledArrow children in a Canvas instead of Grid
  2. Then make your coordinates at TextBlock relative to that local Canvas by subtracting... Box_X and Start_X and Box_Y and Start_Y (using multibinding and a converter to do so)

I think it will be mounted to a relative canvas at the coordinates you aspire... isnt it?