Andreas
Andreas

Reputation: 478

Border disappearing on ItemsControl resize (using "stretchpanel")

Yesterday I asked how to get an ItemsControl to have its children equally distributed across the available space; and after happily reading the answer, I wrote (well actually kind of copied and adjusted it) my own "stretchpanel", which does exactly what i want. However my children are supposed to have a border on their right side, which works, as long as the child is bigger than its content. As soon as it gets smaller the border disappears and i can't tell why (and thus, not fix it). Below you can find a simplified version of my view and of the overriden methods from my stretchpanel, using this sample as basis. Thanks a lot in advance.

<Grid Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
  <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl x:Name="HorizontalListBox" Background="Blue" HorizontalAlignment="Left" HorizontalContentAlignment="Left" >
  <ItemsControl.Items>
    <System:String>Test</System:String>
    <System:String>Test</System:String>
    <System:String>This demonstrates the problem exceptionally well</System:String>
    <System:String>Test</System:String>
    <System:String>Test</System:String>
  </ItemsControl.Items>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Controls:StretchPanel Orientation="Horizontal" HorizontalAlignment="Stretch"/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Grid Background="Yellow" HorizontalAlignment="Stretch">
        <TextBlock Text="{Binding}" HorizontalAlignment="Stretch"/>
        <Border BorderBrush="Black" BorderThickness="0,0,1,0"/>
      </Grid>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

protected override Size MeasureOverride(Size availableSize)
{
  var size = new Size();
  SetSide(ref size, GetSide(availableSize));
  foreach (UIElement child in Children)
  {
    child.Measure(availableSize);
    SetOtherSide(ref size, Math.Max(GetOtherSide(size), GetOtherSide(child.DesiredSize)));
  }
  _measureSize = size;
  return size;
}

protected override Size ArrangeOverride(Size finalSize)
{
  double offset = 0;
  var Side = GetSide(_measureSize) / Children.Count;
  var Rest = GetSide(_measureSize) % Children.Count;
  foreach (UIElement child in Children)
  {
    double side = Math.Floor(GetSide(_measureSize) / Children.Count);
    if (Rest > 0)
    {
      side++;
      Rest--;
    }
    var final = new Size();
    SetSide(ref final, side);
    SetOtherSide(ref final, GetOtherSide(finalSize));
    child.Arrange(new Rect(GetOffsetPoint(offset), final));
    offset += side;
  }
  return finalSize;
}

Upvotes: 1

Views: 89

Answers (1)

Clemens
Clemens

Reputation: 128147

It will work if you write your StretchPanel like this, which measure its child elements with zero width and height:

public class StretchPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        foreach (UIElement element in Children)
        {
            element.Measure(new Size());
        }

        return new Size();
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        for (int i = 0; i < Children.Count; i++)
        {
            int x1 = (int)(finalSize.Width / Children.Count * i);
            int x2 = (int)(finalSize.Width / Children.Count * (i + 1));
            Children[i].Arrange(new Rect(x1, 0, x2 - x1, finalSize.Height));
        }

        return finalSize;
    }
}

and then set HorizontalAlignment="Stretch" (or don't set it at all, since that is the default value) on the ItemsControl.

Upvotes: 1

Related Questions