C# WPF:调整画布大小以包含其子级

C# WPF:调整画布大小以包含其子级,c#,wpf,canvas,itemscontrol,C#,Wpf,Canvas,Itemscontrol,我的任务是画多个矩形并操纵它们。因此,我使用了一个ItemsControl,它的ItemsPanel作为画布,以及一个包装滚动查看器: <ScrollViewer Height="200" Grid.Row="1" > <ItemsControl Name="rectanglesList" Background="AliceBlue"> <ItemsControl.ItemsPanel> <ItemsPan

我的任务是画多个矩形并操纵它们。因此,我使用了一个
ItemsControl
,它的
ItemsPanel
作为
画布
,以及一个包装
滚动查看器

<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>

现在,由于画布的高度和宽度属性不包括其子项,
Scrollviewer
将无法工作,除非我通过计算子项的高度和宽度之和并将其分配给
ItemsControl
来手动更改
ItemsControl
高度和宽度


现在的问题是,是否有我丢失的自动执行此操作的属性?

您可以使用自定义画布覆盖
MeasureOverride
方法

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;
    }
}
ItemTemplate
将如下所示:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <local:MyCanvas/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Border BorderThickness="1" BorderBrush="Black">
            <Rectangle Fill="{Binding Color}"/>
        </Border>
    </DataTemplate>
</ItemsControl.ItemTemplate>


您可能还希望将SCrollViewer放入ItemsControl的ControlTemplate中:

<ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
        <ScrollViewer HorizontalScrollBarVisibility="Auto"
                      VerticalScrollBarVisibility="Auto">
            <ItemsPresenter/>
        </ScrollViewer>
    </ControlTemplate>
</ItemsControl.Template>

@Clemens的答案很好。我只是想添加一些上下文,说明为什么在不清楚的情况下有必要这样做

在WPF中,<代码>画布面板在被要求测量自身时不考虑其子元素。父控件负责确保画布的大小适合其包含的项目

在@Clemens提供的子类中,
MeasureOverride
中提供了考虑所有子类的逻辑


注意,这将不考虑任何非代码>框架元素< /代码>子。如果您添加了大量的子项,您可能会在布局过程中注意到性能问题。

感谢您的进一步说明,如果您愿意,由于您带来了性能问题,您是否可以提供50000个矩形的解决方案?:-)
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Rectangle StrokeThickness="1" Stroke="Black" Fill="{Binding Color}"/>
    </DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
        <ScrollViewer HorizontalScrollBarVisibility="Auto"
                      VerticalScrollBarVisibility="Auto">
            <ItemsPresenter/>
        </ScrollViewer>
    </ControlTemplate>
</ItemsControl.Template>