Question

I have two classes [applicable to this question]. The first, XYAxes2, extends FrameworkElement. It overrides MeasureOverride and ArrangeOverride in an attempt to place it's sole child, XAxis (also extends FrameworkElement), in the desired position.

XYAxes2 (Parent):

Scale XAxis =//...
protected override Size MeasureOverride( Size availableSize ) {
    XAxis.Measure( availableSize );
    return (Size)availableSize;
}
protected override Size ArrangeOverride( Size finalSize ) {
    XAxis.Arrange( new Rect( 50, 50, 100, 200 ) );
    return finalSize;
}

Scale is a custom drawn component. Scale (Child):

protected override void OnRender( DrawingContext cx ) {
    ValidateTicks();
    if (Orientation == Orientation.Horizontal) {
        cx.DrawLine( Pen, new Point( -.5, .5 ), new Point( ActualWidth - .5, .5 ) );
        foreach (double tick in _ticks.Keys) {
            double val = ScaleTransformCallback( tick );
            double x = -0.5 + (int)((val - MinValue) * ActualWidth / (MaxValue - MinValue));
            cx.DrawLine( Pen, new Point( x, .5 ), new Point( x, TickLength - .5 ) );
            FormattedText txt = _ticks[tick];
            cx.DrawText( txt, new Point( x - txt.Width / 2, TickLength + TextMargin ) );
        }
    } else {
        double Left = maxTextWidth + 2 * TextMargin;
        double Right = this.TickLength + Left;
        cx.DrawLine( Pen, new Point( Right - .5, +.5 ), new Point( Right - .5, ActualHeight + .5 ) );
        foreach (double tick in _ticks.Keys) {
            double val = ScaleTransformCallback( tick );
            double y = -0.5 + ActualHeight - (int)((val - MinValue) * ActualHeight / (MaxValue - MinValue));
            cx.DrawLine( Pen, new Point( Right - .5, y ), new Point( Left - .5, y ) );
            FormattedText txt = _ticks[tick];
            cx.DrawText( txt, new Point( Left - txt.Width - TextMargin, y - txt.Height / 2 ) );
        }
    }
}

When debugging, ActualWidth in this function is always the width of the parent rather than the width set by ArrangeOverride, 100. The child is, however, clipped to the region specified by ArrangeOverride.

Am I do something wrong in one of these functions?

Edit: By inserting XAxis.Measure(100,200) into ArrangeOverride, the problem is apparently fixed. Surely, it shouldn't be necessary to call Measure everytime the arrangement is invalidated (this would mean InvalidateArrange would need to implicitly call InvalidateMeasure). Can anyone shed any light on the causes behind this?

Does anyone know where DesiredSize and ActualWidth/Height are actually set (obviously they are not set by my code)?

Was it helpful?

Solution

The solution I have used for this is to use multiple passes in the MeasureOverride function. I keep measuring with different sizes until a suitable overall size is determined.

By reading through the .Net 4.0 source code, it appears that :-

  • DesiredSize is set by the UIElement.Measure function to be the return value of MeasureOverride.

  • ActualWidth/ActualHeight (RenderSize) are set by FrameworkElement.ArrangeCore to be whatever value is returned from ArrangeOverride There doesn't appear to be any error checking or rounding applied.

I hope this can help other people.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top