WPF MeasureOverride loop

927 views Asked by At

This is the background:
Creating a WPF divided diagram
I've decided to remove the scrollviewers, and use only one that will increase by the base one changes.

I have quite a strange issue to resolve. This is the case, I have a set up of items in this way.
Parent -> Child.
ScrollViewer -> Canvas.
Canvas -> Grid.
Grid -> Multiple Canvases (divided to different grid columns).

<ScrollViewer x:Name="MainScrollView" HorizontalScrollBarVisibility="Auto"
                        VerticalScrollBarVisibility="Auto"
                        HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

                <s:DesignerCanvas Focusable="true" x:Name="MyDesignerTop"
                        FocusVisualStyle="{x:Null}" IsHitTestVisible="True"
                        Grid.ColumnSpan="2147483647" Panel.ZIndex="2147483647"
                        ContextMenu="{StaticResource DesignerCanvasContextMenu}">

                    <s:DesignerCanvas.Background>
                        <SolidColorBrush Opacity="0"/>
                    </s:DesignerCanvas.Background>
                    <Grid x:Name="MainGrid" Background="#FF61B5B9">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>

                        <s:DesignerCanvas Focusable="true" x:Name="MyDesigner"
                        Background="{StaticResource WindowBackgroundBrush}"
                        FocusVisualStyle="{x:Null}" Width="700" Height="700"
                         Margin="5"/>
                        <!--ContextMenu="{StaticResource DesignerCanvasContextMenu}"-->

                    </Grid>
                </s:DesignerCanvas>

</ScrollViewer>

I'll explain, I have an item on one of the lower canvases, and let's assume I want to move it from one canvas to another, I managed to pull that off since I have the higher hirerachy canvas which allow me to.

The problem is when I want to resize the item, let's assume that one of the item on one of the lower canvases is going towards the edge, I can rescale the canvas, however this has no effect on the upper grid (sometime it strangely does), so my upper canvas doesn't have any effect, and so my scrollviewer hasn't notified on the increase of size.

If I manually tell the grid to measure itself since one of the element childs exceed the divided canvas size, than it will also tell to all of it's child to measure themselves in order to return it their desired values, which will cause an infinite loop.

here is the MeasureOverride function:

protected override Size MeasureOverride(Size constraint)
    {
        Size size = new Size();

        foreach (UIElement element in this.InternalChildren)
        {
            double left = Canvas.GetLeft(element);
            double top = Canvas.GetTop(element);
            left = double.IsNaN(left) ? 0 : left;
            top = double.IsNaN(top) ? 0 : top;

            //measure desired size for each child
            element.Measure(constraint);

            Size desiredSize = element.DesiredSize;
            if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height))
            {
                size.Width = Math.Max(size.Width, left + desiredSize.Width);
                size.Height = Math.Max(size.Height, top + desiredSize.Height);
            }
        }
        // add margin 
        size.Width += 10;
        size.Height += 10;

        //Let's assume here I will tell the grid to manually measure itself -> infinite loop

        return size;
    }

How can I fix this? how can I notify all childs in chain to measure themselves without causing an infinite loop?

1

There are 1 answers

0
Ori Frish On BEST ANSWER

I strangely fixed the problem. I didn't use Width anymore, just MinWidth instead, and all the calculations were suddenly fixed.

<ScrollViewer x:Name="MainScrollView" HorizontalScrollBarVisibility="Auto"
                        VerticalScrollBarVisibility="Auto"
                        HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

                <s:DesignerCanvas Focusable="true" x:Name="MyDesignerTop"
                        FocusVisualStyle="{x:Null}" IsHitTestVisible="True"
                        Grid.ColumnSpan="2147483647" Panel.ZIndex="2147483647"
                        ContextMenu="{StaticResource DesignerCanvasContextMenu}">

                    <s:DesignerCanvas.Background>
                        <SolidColorBrush Opacity="0"/>
                    </s:DesignerCanvas.Background>
                    <Grid x:Name="MainGrid" Background="#FF61B5B9">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>

                        <s:DesignerCanvas Focusable="true" x:Name="MyDesigner"
                        Background="{StaticResource WindowBackgroundBrush}"
                        FocusVisualStyle="{x:Null}" MinWidth="600" MinHeight="600"
                         Margin="5"/>
                        <!--ContextMenu="{StaticResource DesignerCanvasContextMenu}"-->

                    </Grid>
                </s:DesignerCanvas>

</ScrollViewer>