Set Width and Height of ItemsControl Children

2019-09-16 05:36发布

问题:

My CustomItemsControl looks like the following:

   <local:CustomItemsControl x:Name="CustomItemsControl" >
        <local:CustomItemsControl.ItemTemplate>
            <DataTemplate>
                <Border x:Name="rectangle" Background="Orange" CornerRadius="5"  />
            </DataTemplate>
        </local:CustomItemsControl.ItemTemplate>
    </local:CustomItemsControl>

Depending on the amount of the items which my CustomItemsControl contain, it should calculate the Width and the Height of "Container" Items.

I thought I could achieve that by calling the methods Measure/Arrange of the Items. But my Code doesn't seem to have any effects on the Item's size ((Actual)Width or (Actual)Height is NaN or 0)

public class CustomItemsControl : ItemsControl
{
    protected override Size MeasureOverride(Windows.Foundation.Size availableSize)
    {
        Windows.Foundation.Size size = base.ArrangeOverride(availableSize);
        if (ItemsSource != null)
        {
            double CellWidth = size.Width / Items.Count;
            foreach (var Item in Items)
            {
                DependencyObject Container = ContainerFromItem(Item);
                if(Container!=null)
                {
                    FrameworkElement Element = Container as FrameworkElement;
                    //Element.Width = CellWidth; 
                    //Element.Height = CellWidth; 
                    Element.Measure(new Size(CellWidth, CellWidth));
                    Element.Arrange(new Rect(0, 0, CellWidth, CellWidth));
                }

            }
        }
        return size;
    }
}

The items will not be displayed unless you set the Width and Height of the Border (e.g. 10). I try to accomplish that my CustomItemsControl calculates the Width and Height of the Items. What did I do wrong? How can I accomplish my plan?

回答1:

You should write an appropriate custom Panel with overridden MeasureOverride and ArrangeOverride methods and assign it to the ItemsPanel property of an ItemsControl:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <local:CustomPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border ... />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The CustomPanel class could look like shown below. The control arranges its child elements horizontally. It may be extended with an Orientation property like the one of StackPanel, to arrange its children either horizontally or vertically.

public class CustomPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        var size = new Size();

        if (double.IsInfinity(availableSize.Width)) // availableSize may be infinite
        {
            availableSize.Width = RenderSize.Width;
        }

        if (Children.Count > 0)
        {
            var cellWidth = availableSize.Width / Children.Count;
            var childSize = new Size(cellWidth, cellWidth);

            foreach (var child in Children)
            {
                child.Measure(childSize);
            }

            size.Width = availableSize.Width;
            size.Height = cellWidth;
        }

        return size;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        var size = new Size();

        if (Children.Count > 0)
        {
            var cellWidth = finalSize.Width / Children.Count;
            var childRect = new Rect(0, 0, cellWidth, cellWidth);

            foreach (var child in Children)
            {
                child.Arrange(childRect);
                childRect.X += cellWidth;
            }

            size.Width = finalSize.Width;
            size.Height = cellWidth;
        }

        return size;
    }
}


标签: c# uwp uwp-xaml