I have a task to draw multiple rectangles and manipulate them. So I'm using an ItemsControl
with it's ItemsPanel
as a Canvas
, and a wrapping ScrollViewer
:
<ScrollViewer Height="200" Grid.Row="1" >
<ItemsControl Name="rectanglesList" Background="AliceBlue">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Y}"/>
<Setter Property="Canvas.Top" Value="{Binding X}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Black">
<Rectangle Width="{Binding Width}" Height="{Binding Height}" Fill="{Binding Color}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Now since the Canvas height and width properties do not include it's children, the Scrollviewer
won't work unless I change the ItemsControl
height and width manually by calculating summing the heights and widths of the children and assigning them to the ItemsControl
.
The question is now is there any property 'm missing that does this automatically?
You may use a custom Canvas that overrides the MeasureOverride
method
public class MyCanvas : Canvas
{
protected override Size MeasureOverride(Size constraint)
{
base.MeasureOverride(constraint);
var size = new Size();
foreach (var child in Children.OfType<FrameworkElement>())
{
var x = GetLeft(child) + child.Width;
var y = GetTop(child) + child.Height;
if (!double.IsNaN(x) && size.Width < x)
{
size.Width = x;
}
if (!double.IsNaN(y) && size.Height < y)
{
size.Height = y;
}
}
return size;
}
}
and which would be used like this:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:MyCanvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
It requires that the item container element, besides Canvas.Left
and Canvas.Top
has its Width
and Height
set in the ItemContainerStyle:
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
<Setter Property="Width" Value="{Binding Width}"/>
<Setter Property="Height" Value="{Binding Height}"/>
</Style>
</ItemsControl.ItemContainerStyle>
The ItemTemplate
would then just look like this:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Black">
<Rectangle Fill="{Binding Color}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
or
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle StrokeThickness="1" Stroke="Black" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
You may also want to put the SCrollViewer into the ControlTemplate of the ItemsControl:
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>