WPF Layout algorithm woes - control will resize, but not below some arbitrary value.

Posted by Quantumplation on Stack Overflow See other posts from Stack Overflow or by Quantumplation
Published on 2010-04-15T15:08:04Z Indexed on 2010/04/15 18:23 UTC
Read the original article Hit count: 1002

Filed under:
|
|
|

I'm working on an application for a client, and one of the requirements is the ability to make appointments, and display the current week's appointments in a visual format, much like in Google Calender's or Microsoft Office. I found a great (3 part) article on codeproject, in which he builds a "RangePanel", and composes one for each "period" (for example, the work day.) You can find part 1 here:

http://www.codeproject.com/KB/WPF/OutlookWpfCalendarPart1.aspx

The code presents, but seems to choose an arbitrary height value overall (440.04), and won't resize below that without clipping. What I mean to say, is that the window/container will resize, but it just cuts off the bottom of the control, instead of recalculating the height of the range panels, and the controls in the range panels representing the appointment. It will resize and recalculate for greater values, but not less.

Code-wise, what's happening is that when you resize below that value, first the "MeasureOverride" is called with the correct "new height". However, by the time the "ArrangeOverride" method is called, it's passing the same 440.04 value as the height to arrange to.

I need to find a solution/workaround, but any information that you can provide that might direct me for things to look into would also be greatly appreciated ( I understand how frustrating it is to debug code when you don't have the codebase in front of you. :) )

The code for the various Arrange and Measure functions are provided below. The "CalendarView" control has a "CalendarViewContentPresenter", which handles several periods. Then, the periods have a "CalendarPeriodContentPresenter", which handles each "block" of appointments. Finally, the "RangePanel" has it's own implementation. (To be honest, i'm still a bit hazy on how the control works, so if my explanations are a bit hazy, the article I linked probably has a more cogent explanation. :) )

CalendarViewContentPresenter:
    protected override Size ArrangeOverride(Size finalSize)
    {
        int columnCount = this.CalendarView.Periods.Count;
        Size columnSize = new Size(finalSize.Width / columnCount, finalSize.Height);
        double elementX = 0;

        foreach (UIElement element in this.visualChildren)
        {
            element.Arrange(new Rect(new Point(elementX, 0), columnSize));
            elementX = elementX + columnSize.Width;
        }

        return finalSize;
    }

    protected override Size MeasureOverride(Size constraint)
    {
        this.GenerateVisualChildren();
        this.GenerateListViewItemVisuals();
        // If it's coming back infinity, just return some value.
        if (constraint.Width == Double.PositiveInfinity)
            constraint.Width = 10;
        if (constraint.Height == Double.PositiveInfinity)
            constraint.Height = 10;

        return constraint;
    }

CalendarViewPeriodPersenter:
    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement element in this.visualChildren)
        {
            element.Arrange(new Rect(new Point(0, 0), finalSize));
        }

        return finalSize;
    }

    protected override Size MeasureOverride(Size constraint)
    {
        this.GenerateVisualChildren();

        return constraint;
    }

RangePanel:
    protected override Size ArrangeOverride(Size finalSize)
    {
        double containerRange = (this.Maximum - this.Minimum);

        foreach (UIElement element in this.Children)
        {
            double begin = (double)element.GetValue(RangePanel.BeginProperty);
            double end = (double)element.GetValue(RangePanel.EndProperty);
            double elementRange = end - begin;

            Size size = new Size();
            size.Width = (Orientation == Orientation.Vertical) ? finalSize.Width : elementRange / containerRange * finalSize.Width;
            size.Height = (Orientation == Orientation.Vertical) ? elementRange / containerRange * finalSize.Height : finalSize.Height;

            Point location = new Point();
            location.X = (Orientation == Orientation.Vertical) ? 0 : (begin - this.Minimum) / containerRange * finalSize.Width;
            location.Y = (Orientation == Orientation.Vertical) ? (begin - this.Minimum) / containerRange * finalSize.Height : 0;

            element.Arrange(new Rect(location, size));
        }

        return finalSize;
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        foreach (UIElement element in this.Children)
        {
            element.Measure(availableSize);
        }
        // Constrain infinities
        if (availableSize.Width == double.PositiveInfinity)
            availableSize.Width = 10;
        if (availableSize.Height == double.PositiveInfinity)
            availableSize.Height = 10;
        return availableSize;
    }

© Stack Overflow or respective owner

Related posts about wpf

Related posts about wpf-controls