I am currently trying to bind a collection of objects to a Canvas in Silverlight 3 using an ItemsControl as below:
<ItemsControl x:Name="ctrl" ItemsSource="{Binding myObjectsCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Stroke="LightGray" Fill="Black" StrokeThickness="2"
RadiusX="15" RadiusY="15" Canvas.Left="{Binding XAxis}"
Height="25" Width="25">
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Unfortunately it seems the binding on the Canvas.Left is being ignored. From what i have learned here it would appear this is due to the items being placed inside a content presenter not the actual canvas i have specified in the items panel.
Is there a way i can use data binding to determine the position of elements on a canvas?
I realize that this already has an answer accepted, but the way to achieve the initial goal without messing with margins is to create a custom ItemsControl and override the PrepareContainerForItemOverride method. In this method, you set the binding in code.
public class CustomItemsCollection
: ItemsControl
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
FrameworkElement contentitem = element as FrameworkElement;
Binding leftBinding = new Binding("Left"); // "Left" is the property path that you want to bind the value to.
contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
base.PrepareContainerForItemOverride(element, item);
}
}
You cannot use ItemsControl.ItemContainerStyle
in Silverlight. It doesn't exist. It exists only on a couple of leaf level classes like ListBox
itself.
You are right, a ContentPresenter is inserted between the Canvas and the Rectangle.
One workaround would be to set a left margin instead of a Canvas.Left
:
<Rectangle Stroke="LightGray" Fill="Black" StrokeThickness="2"
RadiusX="15" RadiusY="15" Height="25" Width="25">
<Rectangle.Margin>
<Thickness Left="{Binding XAxis}"/>
</Rectangle.Margin>
</Rectangle>
I know this question is a little old, but you can just use a render transform - I'm doing something similar;
<ItemsControl ItemsSource="{Binding Notes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Aqua"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="{Binding W}" Height="{Binding H}" BorderBrush="Navy" BorderThickness="5" CornerRadius="10">
<TextBlock Text="{Binding Text}"/>
<Border.RenderTransform>
<TransformGroup>
<RotateTransform Angle="0"/>
<TranslateTransform X="{Binding X}" Y="{Binding Y}"/>
</TransformGroup>
</Border.RenderTransform>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Add the following to your ItemsControl
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Left" Value="{Binding XPath=XAxis}"/>
</Style>
</ItemsControl.ItemContainerStyle>
No need for any custom controls