我有一个任务来绘制多个矩形并对其进行操作。因此,我使用的是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的height和width属性不包含子元素,因此除非我通过计算子元素的高度和宽度之和来手动更改Scrollviewer
的高度和宽度,否则ItemsControl
将不起作用并将它们分配给ItemsControl
。
现在的问题是,是否缺少任何自动执行的属性?
答案 0 :(得分:1)
您可以使用覆盖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>
答案 1 :(得分:1)
@Clemens的回答很好。我只是想添加一些上下文,以说明在不清楚的情况下为什么有必要这样做的原因。
在WPF中,Canvas
面板在被要求进行自我测量时不会考虑其子级。父控件的责任是确保画布的大小适合将包含的项目。
在@Clemens提供的子类中,MeasureOverride
中提供了考虑所有子级的逻辑。
请注意,这不会考虑任何非FrameworkElement
的孩子。如果添加大量子代,可能会在布局过程中发现性能下降。