Is it possible to bind a Canvas's Children property in XAML? Is it possible to bind a Canvas's Children property in XAML? wpf wpf

Is it possible to bind a Canvas's Children property in XAML?


<ItemsControl ItemsSource="{Binding Path=Circles}">    <ItemsControl.ItemsPanel>         <ItemsPanelTemplate>              <Canvas Background="White" Width="500" Height="500"  />         </ItemsPanelTemplate>    </ItemsControl.ItemsPanel>    <ItemsControl.ItemTemplate>        <DataTemplate>            <Ellipse Fill="{Binding Path=Color, Converter={StaticResource colorBrushConverter}}" Width="25" Height="25" />        </DataTemplate>    </ItemsControl.ItemTemplate>    <ItemsControl.ItemContainerStyle>        <Style>            <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />            <Setter Property="Canvas.Left" Value="{Binding Path=X}" />        </Style>    </ItemsControl.ItemContainerStyle></ItemsControl>


Others have given extensible replies on how to do what you actually want to do already. I'll just explain why you couldn't bind Children directly.

The problem is very simple - data binding target cannot be a read-only property, and Panel.Children is read-only. There is no special handling for collections there. In contrast, ItemsControl.ItemsSource is a read/write property, even though it is of collection type - a rare occurence for a .NET class, but required so as to support the binding scenario.


ItemsControl is designed for creating dynamic collections of UI controls from other collections, even non-UI data collections.

You can template an ItemsControl to draw on a Canvas. The ideal way would involve setting the backing panel to a Canvas and then setting the Canvas.Left and Canvas.Top properties on the immediate children. I could not get this to work because ItemsControl wraps its children with containers and it is hard to set the Canvas properties on these containers.

Instead, I use a Grid as a bin for all of the items and draw them each on their own Canvas. There is some overhead with this approach.

<ItemsControl x:Name="Collection" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">    <ItemsControl.ItemsPanel>        <ItemsPanelTemplate>            <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>        </ItemsPanelTemplate>    </ItemsControl.ItemsPanel>    <ItemsControl.ItemTemplate>        <DataTemplate DataType="{x:Type local:MyPoint}">            <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch">                <Ellipse Width="10" Height="10" Fill="Black" Canvas.Left="{Binding X}" Canvas.Top="{Binding Y}"/>            </Canvas>        </DataTemplate>    </ItemsControl.ItemTemplate></ItemsControl>

Here's the code behind that I used to set up the source collection:

List<MyPoint> points = new List<MyPoint>();points.Add(new MyPoint(2, 100));points.Add(new MyPoint(50, 20));points.Add(new MyPoint(200, 200));points.Add(new MyPoint(300, 370));Collection.ItemsSource = points;

MyPoint is a custom class that behaves just like the System version. I created it to demonstrate that you can use your own custom classes.

One final detail: You can bind the ItemsSource property to any collection you want. For example:

<ItemsControls ItemsSource="{Binding Document.Items}"><!--etc, etc...-->

For further details about ItemsControl and how it works, check out these documents: MSDN Library Reference; Data Templating; Dr WPF's series on ItemsControl.