0
votes

I need to implement something between listbox and panel. It has to have bindable itemssource without own style. So I decided to derived from FrameworkElement. I tried to add new button in code behind to my control and on changing ItemsSource property I call InvalidateMeasure. In MeasureOverride method I run over itemssource collection and call Measure with availableSize as parameter for each item. But as result I get weird DesiredSize of the control(in my case it was button) inside itemssouce - 16 height and 0 width. It's my code:

    // part from usercontrol's code behind  
    public MainPage()
    {
        InitializeComponent();

        dash.ItemsSource.Add(new Button { Content = "button 1 content", Padding = new Thickness(10) });
        dash.ItemsSource.Add(new Button { Content = "button 2 content", Padding = new Thickness(10) });
    }

    //part from my control
    protected override Size MeasureOverride(Size availableSize)
    {
        var desiredSize = new Size();
        foreach (UIElement item in ItemsSource)
        {
            item.Measure(availableSize);
            desiredSize.Height += item.DesiredSize.Height;
            desiredSize.Width += item.DesiredSize.Width;
        }
        return desiredSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {           
        double x = 25, y = 25;
        foreach (FrameworkElement item in ItemsSource)
        {
            item.Arrange(new Rect(x, y, item.DesiredSize.Width, item.DesiredSize.Height));
        }

        return base.ArrangeOverride(finalSize);
    }

I tried to set item Height and Width manually but it's not helped. Even tried to call Measure twice first time with new Size(double.PositiveInfinity,double.PositiveInfinity); And in any case buttons don't want to show up on user control.

Please help me to determine what i'm doing wrong!

1
Your approach is entirely wrong. You would usually set the ItemsPanel and ItemContainerStyle or ItemTemplate property of an ItemsControl or ListBox. Please tell us how the items shall be arranged, as currenlty you are trying to put them all on top of each other at x=25/y=25, which doesn't seem to make sense. - Clemens
I just tried to add items to my control and show them. I didn't care where they have to be. You have a point there, but as result I will get complex thing that can't be(and shouldn't be) based on ItemsControl or any other control. By the way I figured out the problem. I missed very important thing - visual tree. I didn't add new buttons to visual tree and they were without parent. I tried to look up how the other panels are working. They are use UIElementCollection which has internal constructor. I guess some "magic" happens there... Silverlight is very frustrating after wpf... - Crossman
You would definitely confuse users of your control, as its "items" can only be controls (or UIElements to be precise). However, items in the sense of the ItemsSource property could be any type of object. You should at least create a derived Panel, and add UIElements to its Children collection. If you'd eleborate a bit on how you actually want to arrange the children, you may get a useful solution here. - Clemens
See Remarks in Panel: For scenarios that require application layout that is not possible using any of the predefined Panel elements, custom layout behaviors can be achieved by inheriting from Panel and overriding the default measure and arrange behavior by using the MeasureOverride and ArrangeOverride methods. - Clemens

1 Answers

0
votes

What you are looking for is a derived Panel. Since you did not really explain how your desired layout should look like, the following example arranges the Panel's children "diagonally" by placing each child at the bottom right corner of the previous one. Moreover it ignores any horizontal or vertical alignment settings. You may use it like any other Panel and add children either in XAML or in code behind.

public class MyPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        var infiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);

        foreach (UIElement child in Children)
        {
            child.Measure(infiniteSize); // allow unconstrained child size
        }

        return new Size(); // consume as less size as possible
    }

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

        foreach (UIElement child in Children)
        {
            var size = child.DesiredSize;
            child.Arrange(new Rect(position, size));
            position.X += size.Width;
            position.Y += size.Height;
        }

        return new Size(position.X, position.Y);
    }
}