TimeLinePanel - Custom WPF Control Part 1

Wednesday, January 10, 2007 1:39:18 AM (GMT Standard Time, UTC+00:00)

Frequently when I see a new technology presented, there are often demos of key concepts that stick in my mind. These examples become things that I feel I must try to build and thoroughly understand myself. At Microsoft's Tech Ed conference in Boston back in June, one of the demos that really stuck with me was the "Kayakalon" demo application used in presentations by Robert Ingebretsen and Lauren Lavoie from the WPF team.

The demo application touched on a number of items revolving around the graphical display of airline flight searches returned from a kayak.com web service. The end result would display flight legs on a graphical time line.

The creation of this TimeLinePanel become a task on the learning list to help me understand. I began trying to recreate the functionality of the control. I started off by inheriting from a Panel control to build a custom panel that would horizontally position child elements based on date criteria.

public class TimeLinePanel : Panel

    {

        protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)

        {

            return base.ArrangeOverride(finalSize);

        }

 

        protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)

        {

            return base.MeasureOverride(availableSize);

        }

    }

In order to handle the layout as required, we are able to override the ArrangeOverride and MeasureOverride methods. The MeasureOverride measures the size in layout required for child elements and determines a size for the element. The ArrangeOverride positions child elements and determines their size. What I wanted to do was to horizontally position the elements based two dates, the would become the start and stop dates for each object, or in the case of the above example the departure and arrival times of the flight legs. In order to take advantage of a WPF design, enabling me to put any type of child elements into this panel, I needed some way to attached these properties to any objects residing in this container, even if they had not concept of these dates.

In .Net 3.0, Microsoft introduces the concept of a DependencyProperty according to the docs "Represents properties that are registered with the Windows Presentation Foundation dependency property system. Dependency properties provide support for value expressions, property invalidation and dependent-value coercion, default values, inheritance, data binding, animation, property change notification, and styling. This class cannot be inherited."

More specifically, I want to make use of an attached property which is "A dependency property that can be attached to any DependencyObject type and that is not limited to the type which defines it. The attached property provider must provide a static get(PropertyName) and set(PropertyName) methods as accessors for these attached properties." So basically, in the end I can create a two properties, independent of their actual types, allowing me to define a start and end date that get attached to any child elements with default values, that can be changed. Through these I can control the layout of the controls.

        public static DependencyProperty EventDateProperty;

        public static DependencyProperty EventDateRangeProperty;

        static TimeLinePanel()

        {

            FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(DateTime.Parse("1/1/0001"), FrameworkPropertyMetadataOptions.Inherits );

            FrameworkPropertyMetadata metadataB = new FrameworkPropertyMetadata(DateTime.Parse("1/1/0001"), FrameworkPropertyMetadataOptions.Inherits);

 

            EventDateProperty = DependencyProperty.RegisterAttached("EventDate",

                typeof(DateTime), typeof(Control),metadata);

            EventDateRangeProperty = DependencyProperty.RegisterAttached("EventDateRange",

                typeof(DateTime), typeof(Control), metadataB);

        }

 

        public static void SetEventDate(DependencyObject dependencyObject, DateTime eventdate)

        {

            dependencyObject.SetValue(EventDateProperty, eventdate);

        }

        public static void SetEventDateRange(DependencyObject dependencyObject, DateTime eventdaterange)

        {

            dependencyObject.SetValue(EventDateRangeProperty, eventdaterange);

        }

Once these properties are in place, I can define my elements like this:


    Windows 1.0
    Windows 2.0
    Windows 3.0
    Windows 3.1
    Windows NT 3.51
    Windows 95
    Windows NT 4
    Windows 98
    Windows 2000
    Windows Me
    Windows XP
    Windows Vista

The end result renders like this:

Working through this example I discovered a lot of cool things that I could easily do to add functionality to this control. The main take away is how you can control how child elements are arranged.

Technorati tags: , , ,

Posted in wpf  | Comments [5] 


Tuesday, November 13, 2007 12:24:15 PM (GMT Standard Time, UTC+00:00)
Rob,

Super nice work here with the "real-world" custom panel. Thank you for the insite.

Cheers,

Karl
Tuesday, November 25, 2008 4:37:33 PM (GMT Standard Time, UTC+00:00)
Hi,
Where can I find the code base for the WPF version. I am trying to build a real-time updatable timeline and reviewing your code could be helpfull.

Cheers

Prasanna
Prasanna Rao
Wednesday, December 03, 2008 3:33:41 PM (GMT Standard Time, UTC+00:00)
Got source code? How do you control what underlying control is used by Panel? (eg Canvas). How do you get a reference to the underlying control to draw on it? (eg the horizontal timeline)
Ian
Wednesday, April 22, 2009 5:17:15 PM (GMT Daylight Time, UTC+01:00)
Is there any source available ?
Sek
Thursday, September 10, 2009 7:30:47 PM (GMT Daylight Time, UTC+01:00)
I agree, source code would be nice. I'm new to WPF and adding the controls or even labels as you've done isn't immediately apparent to me.
Thanks
Mark
Comments are closed.