nakiya
nakiya

Reputation: 14423

How to make a Grid like custom control for these requirements

I need a control having these features:

  1. It should be possible use it in xaml to design.
  2. It should be able to hold multiple child elements of a single type. Say Button for example.
  3. These child elements will have fixed dimensions. The control has to figure out what is the maximum number of children that it can completely display vertically and horizontally (Can't show any child partially). And only display those children but keep the non-visible children for later use. - I think I can get this requirement done with a Grid.
  4. Should be possible to animate these child elements - I guess this is not an issue.

I tried to write a custom control to do this. I inherited from a Grid and having seen that Grid implements IAddChild I thought I could catch elements being added if I overrode AddChild. But now I find that there is no implementation for AddChild in Grid either! So it seems I can't do it like that. Where should I start?

EDIT: Thanks to Alan's pointers, I got it working...

public class AutoLayoutingPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        Size size = new Size();
        size.Height = double.MaxValue;
        size.Width = double.MaxValue;

        foreach (UIElement child in Children)
        {
            child.Measure(size);
            size.Height += child.DesiredSize.Height;
            size.Width += child.DesiredSize.Width;
        }

        return availableSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        ArrangeGrid(finalSize);
        return finalSize;
    }

    private void ArrangeGrid(Size finalSize)
    {
        foreach (UIElement child in Children)
        {
            child.Visibility = Visibility.Hidden;
        }

        Size maxCellSize = new Size();

        foreach (UIElement child in Children)
        {
            maxCellSize.Height = Math.Max(child.DesiredSize.Height, maxCellSize.Height);
            maxCellSize.Width = Math.Max(child.DesiredSize.Width, maxCellSize.Width);
        }

        int rowCount = (int)Math.Floor(finalSize.Height / maxCellSize.Height);
        int colCount = (int)Math.Floor(finalSize.Width / maxCellSize.Width);

        int row = 0, col = 0;
        foreach (UIElement child in Children)
        {
            if (row < rowCount && col < colCount)
            {
                Rect pos = new Rect(col * maxCellSize.Width, row * maxCellSize.Height, maxCellSize.Width, maxCellSize.Height);
                child.Visibility = System.Windows.Visibility.Visible;
                child.Arrange(pos);
            }
            else
            {
                break;
            }

            if (++row >= rowCount)
            {
                row = 0;
                ++col;
            }
        }
    }
}

Upvotes: 0

Views: 566

Answers (1)

Alan
Alan

Reputation: 6689

I think you'll need to create a custom layout panel instead of trying to inherit from Grid (as to the IAddChild interface, it is implemented using EIMI and is therefore neither visible nor overridable from the outside). Here is a good starting point.

(Also, you'll need to think about how you want to restrict the type of child controls that your control can hold. Using generics would be an option, but I have doubts about XAML generics support.)

Upvotes: 1

Related Questions