我有一个绘制多个矩形并操纵它们的任务。所以我使用ItemsControl
,它的ItemsPanel
作为Canvas
,包装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>
现在,因为Canvas的高度和宽度属性不包括它的子项,所以除非我通过计算子项的高度和宽度并将它们分配给Scrollviewer
来手动更改ItemsControl
高度和宽度,否则ItemsControl
将无法工作。
现在的问题是,是否有任何财产缺失自动执行此操作?
您可以使用覆盖MeasureOverride
方法的自定义Canvas
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;
}
}
哪个会像这样使用:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:MyCanvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
除了Canvas.Left
和Canvas.Top
之外,它还要求item容器元素在ItemContainerStyle中设置Width
和Height
:
<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>
然后ItemTemplate
看起来像这样:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Black">
<Rectangle Fill="{Binding Color}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
要么
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle StrokeThickness="1" Stroke="Black" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
您可能还想将SCrollViewer放入ItemsControl的ControlTemplate中:
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
@克莱门斯的答案很棒。我只想添加一些背景知道为什么在不清楚的情况下它是必要的。
在WPF中,Canvas
小组在被要求自己测量时不考虑其子女。父控件负责确保画布的大小适合其包含的项目。
在@Clemens提供的子类中,考虑所有孩子的逻辑在MeasureOverride
中提供。
请注意,这不会考虑任何非FrameworkElement
儿童。如果添加大量子项,您可能会注意到布局期间的性能损失。