【问题标题】:WPF: Sizing Canvas to contain its childrenWPF:调整画布大小以包含其子项
【发布时间】:2019-03-11 11:41:15
【问题描述】:

我的任务是绘制多个矩形并对其进行操作。所以我使用ItemsControlItemsPanel 作为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

现在的问题是是否缺少任何自动执行此操作的属性?

【问题讨论】:

    标签: c# wpf canvas itemscontrol


    【解决方案1】:

    @Clemens 的回答很棒。我只是想添加一些上下文,说明为什么它是必要的,以防不清楚。

    在 WPF 中,Canvas 面板在要求测量自身时不会考虑其子级。父控件有责任确保画布的大小适合其将包含的项目。

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

    请注意,这不会考虑任何非FrameworkElement 的孩子。如果您添加大量子项,您可能会注意到布局期间的性能下降。

    【讨论】:

    • 感谢您的进一步澄清,如果您愿意,由于您带来了性能问题,您能否提供一个解决方案,以防有 50,000 个矩形? :-)
    【解决方案2】:

    您可以使用覆盖 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.LeftCanvas.Top,在ItemContainerStyle 中设置了它的WidthHeight

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-06
      • 2011-03-14
      相关资源
      最近更新 更多