Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArrangeOverride calls arranging children before calling more code

Tags:

c#

layout

wpf

Ok, just when I thought I had the layout system figured out, I hit a brick wall...

So I have a WPF window with a custom ItemsControl, the Items panel of which is a custom Panel, and each ItemContainer is a custom element.

When the window has InvalidateArrange() called, the order of the ArrangeOverride() calls seems to be fine, i.e.

Window -> List -> ItemsPanel -> ItemContainer -> ItemContainer -> etc...

The problem is, I have some code I want to call at the Window level after an ArrangeOverride that relies on all of the ItemContainers having been arranged and sized. The Window level ArrangeOverride() ends before the next item in the tree (the list) has it's ArrangeOverride called.

Is there a way to measure all of a windows children and then return to the Windows ArrangeOverride() to continue with some code, or is there an event to hook into or something?

Cheers

like image 523
Xeno Avatar asked Feb 03 '11 15:02

Xeno


1 Answers

You can call your custom code AFTER calling base.ArrangeOverride() in your window's ArrangeOverride implementation:

    protected override Size ArrangeOverride(Size arrangeBounds)
    {
        Size temp = base.ArrangeOverride(arrangeBounds);

        // custom code goes here!

        return temp;
    }

(I tested just now and it works: the custom code is executed after the ArrangeOverride of any child control in the window)

EDIT: Follows a tested and working example:

In window1.xaml.cs:

[...]
protected override Size ArrangeOverride(Size arrangeBounds)
{
    Trace.TraceInformation("Window1.ArrangeOverride START");
    Size temp = base.ArrangeOverride(arrangeBounds);
    Trace.TraceInformation("Window1.ArrangeOverride END");
    return temp;
}
[...]

In myUserControl.xaml.cs:

[...]
protected override Size ArrangeOverride(Size arrangeBounds)
{
    Trace.TraceInformation("{0}.ArrangeOverride START", Tag);
    Size s = base.ArrangeOverride(arrangeBounds);
    Trace.TraceInformation("{0}.ArrangeOverride END", Tag);
    return s;
}
[...]

In window1.xaml:

[...]
<local:myUserControl Tag="FirstLevelControl">
    <StackPanel>
        <local:myUserControl Tag="SecondLevelControl_1">
            <TextBlock>First</TextBlock>
        </local:myUserControl>
        <local:myUserControl Tag="SecondLevelControl_2">
            <TextBlock>Second</TextBlock>
        </local:myUserControl>
    </StackPanel>
</local:myUserControl>
[...]

And, finally, the output after the execution:

[...]
Test.vshost.exe Information: 0 : Window1.ArrangeOverride START
Test.vshost.exe Information: 0 : FirstLevelControl.ArrangeOverride START
Test.vshost.exe Information: 0 : SecondLevelControl_1.ArrangeOverride START
Test.vshost.exe Information: 0 : SecondLevelControl_1.ArrangeOverride END
Test.vshost.exe Information: 0 : SecondLevelControl_2.ArrangeOverride START
Test.vshost.exe Information: 0 : SecondLevelControl_2.ArrangeOverride END
Test.vshost.exe Information: 0 : FirstLevelControl.ArrangeOverride END
Test.vshost.exe Information: 0 : Window1.ArrangeOverride END
[...]

This demonstrate that the line of code between temp = base.ArrangeOverride and return temp is always executed AFTER all the code in all nested user controls' ArrangeOverride method. I've not tried to trace the execution of Arrange of built-in controls, but I suppose they have the same behaviour.

like image 156
BertuPG Avatar answered Nov 07 '22 00:11

BertuPG