This is a migrated thread and some comments may be shown as answers.

RadDockPanel vs WPF's DockPanel

1 Answer 469 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
igal a
Top achievements
Rank 1
igal a asked on 01 Sep 2010, 03:39 PM
what is the difference between the two?

WPF's DockPanel:

/// <summary> 
/// DockPanel is used to size and position children inward from the edges of available space.
/// 
/// A <see cref="System.Windows.Controls.Dock" /> enum (see <see cref="SetDock" /> and <see cref="GetDock" />) 
/// determines on which size a child is placed.  Children are stacked in order from these edges until
/// there is no more space; this happens when previous children have consumed all available space, or a child 
/// with Dock set to Fill is encountered.
/// </summary>
public class DockPanel : Panel
    //-------------------------------------------------------------------
    // 
    //  Constructors 
    //
    //------------------------------------------------------------------- 
    #region Constructors
    /// <summary> 
    ///     Default DependencyObject constructor
    /// </summary> 
    /// <remarks> 
    ///     Automatic determination of current Dispatcher. Use alternative constructor
    ///     that accepts a Dispatcher for best performance. 
    /// </remarks>
    public DockPanel() : base()
    {
    
    #endregion 
    //--------------------------------------------------------------------
    // 
    //  Public Methods
    //
    //-------------------------------------------------------------------
    #region Public Methods
    /// <summary> 
    /// Reads the attached property Dock from the given element.
    /// </summary> 
    /// <param name="element">UIElement from which to read the attached property.</param>
    /// <returns>The property's value.</returns>
    /// <seealso cref="DockPanel.DockProperty" />
    [AttachedPropertyBrowsableForChildren()] 
    public static Dock GetDock(UIElement element)
    
        if (element == null) { throw new ArgumentNullException("element"); } 
        return (Dock) element.GetValue(DockProperty); 
    }
    /// <summary>
    /// Writes the attached property Dock to the given element. 
    /// </summary>
    /// <param name="element">UIElement to which to write the attached property.</param> 
    /// <param name="dock">The property value to set</param> 
    /// <seealso cref="DockPanel.DockProperty" />
    public static void SetDock(UIElement element, Dock dock) 
    {
        if (element == null) { throw new ArgumentNullException("element"); }
        element.SetValue(DockProperty, dock); 
    }
    private static void OnDockChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    {
        UIElement uie = d as UIElement; //it may be anyting, like FlowDocument... bug 1237275 
        if(uie != null)
        {
            DockPanel p = VisualTreeHelper.GetParent(uie) as DockPanel;
            if(p != null
            {
                p.InvalidateMeasure(); 
            
        }
    
    #endregion
    //-------------------------------------------------------------------- 
    //
    //  Public Properties + Dependency Properties's 
    // 
    //--------------------------------------------------------------------
    #region Public Properties
    /// <summary>
    /// This property controls whether the last child in the DockPanel should be stretched to fill any 
    /// remaining available space.
    /// </summary> 
    public bool LastChildFill 
    {
        get { return (bool) GetValue(LastChildFillProperty); } 
        set { SetValue(LastChildFillProperty, value); }
    }
    /// <summary>
    /// DependencyProperty for <see cref="LastChildFill" /> property. 
    /// </summary> 
    [CommonDependencyProperty]
    public static readonly DependencyProperty LastChildFillProperty = 
            DependencyProperty.Register(
                    "LastChildFill",
                    typeof(bool),
                    typeof(DockPanel), 
                    new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsArrange));
    /// <summary>
    /// DependencyProperty for Dock property. 
    /// </summary>
    /// <seealso cref="DockPanel.GetDock" />
    /// <seealso cref="DockPanel.SetDock" />
    [CommonDependencyProperty] 
    public static readonly DependencyProperty DockProperty =
            DependencyProperty.RegisterAttached( 
                    "Dock"
                    typeof(Dock),
                    typeof(DockPanel), 
                    new FrameworkPropertyMetadata(
                        Dock.Left,
                        new PropertyChangedCallback(OnDockChanged)),
                    new ValidateValueCallback(IsValidDock)); 
    #endregion 
    //-------------------------------------------------------------------
    // 
    //  Protected Methods
    //
    //--------------------------------------------------------------------
    #region Protected Methods
    /// <summary> 
    /// Updates DesiredSize of the DockPanel.  Called by parent UIElement.  This is the first pass of layout.
    /// </summary> 
    /// <remarks>
    /// Children are measured based on their sizing properties and <see cref="System.Windows.Controls.Dock" />.
    /// Each child is allowed to consume all of the space on the side on which it is docked; Left/Right docked
    /// children are granted all vertical space for their entire width, and Top/Bottom docked children are 
    /// granted all horizontal space for their entire height.
    /// </remarks> 
    /// <param name="constraint">Constraint size is an "upper limit" that the return value should not exceed.</param> 
    /// <returns>The Panel's desired size.</returns>
    protected override Size MeasureOverride(Size constraint) 
    {
        UIElementCollection children = InternalChildren;
        double parentWidth       = 0;   // Our current required width due to children thus far. 
        double parentHeight      = 0;   // Our current required height due to children thus far.
        double accumulatedWidth  = 0;   // Total width consumed by children. 
        double accumulatedHeight = 0;   // Total height consumed by children. 
        for (int i = 0, count = children.Count; i < count; ++i) 
        {
            UIElement child = children[i];
            Size   childConstraint;             // Contains the suggested input constraint for this child.
            Size   childDesiredSize;            // Contains the return size from child measure. 
            if (child == null) { continue; } 
            // Child constraint is the remaining size; this is total size minus size consumed by previous children.
            childConstraint = new Size(Math.Max(0.0, constraint.Width - accumulatedWidth), 
                                       Math.Max(0.0, constraint.Height - accumulatedHeight));
            // Measure child.
            child.Measure(childConstraint); 
            childDesiredSize = child.DesiredSize;
            // Now, we adjust: 
            // 1. Size consumed by children (accumulatedSize).  This will be used when computing subsequent
            //    children to determine how much space is remaining for them. 
            // 2. Parent size implied by this child (parentSize) when added to the current children (accumulatedSize).
            //    This is different from the size above in one respect: A Dock.Left child implies a height, but does
            //    not actually consume any height for subsequent children.
            // If we accumulate size in a given dimension, the next child (or the end conditions after the child loop) 
            // will deal with computing our minimum size (parentSize) due to that accumulation.
            // Therefore, we only need to compute our minimum size (parentSize) in dimensions that this child does 
            //   not accumulate: Width for Top/Bottom, Height for Left/Right. 
            switch (DockPanel.GetDock(child))
            
                case Dock.Left:
                case Dock.Right:
                    parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height);
                    accumulatedWidth += childDesiredSize.Width; 
                    break;
                case Dock.Top: 
                case Dock.Bottom:
                    parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width); 
                    accumulatedHeight += childDesiredSize.Height;
                    break;
            }
        
        // Make sure the final accumulated size is reflected in parentSize. 
        parentWidth = Math.Max(parentWidth, accumulatedWidth); 
        parentHeight = Math.Max(parentHeight, accumulatedHeight);
        return (new Size(parentWidth, parentHeight));
    }
    /// <summary> 
    /// DockPanel computes a position and final size for each of its children based upon their
    /// <see cref="System.Windows.Controls.Dock" /> enum and sizing properties. 
    /// </summary> 
    /// <param name="arrangeSize">Size that DockPanel will assume to position children.</param>
    protected override Size ArrangeOverride(Size arrangeSize) 
    {
        UIElementCollection children = InternalChildren;
        int totalChildrenCount = children.Count;
        int nonFillChildrenCount = totalChildrenCount - (LastChildFill ? 1 : 0); 
        double accumulatedLeft   = 0; 
        double accumulatedTop    = 0; 
        double accumulatedRight  = 0;
        double accumulatedBottom = 0; 
        for (int i = 0; i < totalChildrenCount; ++i)
        {
            UIElement child = children[i]; 
            if (child == null) { continue; }
            Size childDesiredSize = child.DesiredSize; 
            Rect rcChild = new Rect(
                accumulatedLeft, 
                accumulatedTop,
                Math.Max(0.0, arrangeSize.Width - (accumulatedLeft + accumulatedRight)),
                Math.Max(0.0, arrangeSize.Height - (accumulatedTop + accumulatedBottom))    );
            if (i < nonFillChildrenCount)
            
                switch (DockPanel.GetDock(child)) 
                {
                    case Dock.Left: 
                        accumulatedLeft += childDesiredSize.Width;
                        rcChild.Width = childDesiredSize.Width;
                        break;
                    case Dock.Right:
                        accumulatedRight += childDesiredSize.Width; 
                        rcChild.X = Math.Max(0.0, arrangeSize.Width - accumulatedRight); 
                        rcChild.Width = childDesiredSize.Width;
                        break
                    case Dock.Top:
                        accumulatedTop += childDesiredSize.Height;
                        rcChild.Height = childDesiredSize.Height; 
                        break;
                    case Dock.Bottom: 
                        accumulatedBottom += childDesiredSize.Height;
                        rcChild.Y = Math.Max(0.0, arrangeSize.Height - accumulatedBottom); 
                        rcChild.Height = childDesiredSize.Height;
                        break;
                }
            
            child.Arrange(rcChild); 
        
        return (arrangeSize); 
    }
    #endregion Protected Methods
    //-------------------------------------------------------------------
    // 
    //  Private Methods 
    //
    //------------------------------------------------------------------- 
    #region Private Methods
    internal static bool IsValidDock(object o) 
    {
        Dock dock = (Dock)o; 
        return (    dock == Dock.Left
                ||  dock == Dock.Top 
                ||  dock == Dock.Right
                ||  dock == Dock.Bottom);
    }
    //
    //  This property 
    //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject 
    //  2. This is a performance optimization
    // 
    internal override int EffectiveValuesInitialSize
    {
        get { return 9; }
    
    #endregion Private Methods 
}


RadDockPanel:
/// <summary>
/// Defines an area where you can arrange child elements either horizontally or vertically, relative to each other. 
/// </summary>
[DefaultProperty("LastChildFill")]
public class RadDockPanel : Panel
{
    /// <summary>
    /// Identifies the Dock attached property. 
    /// </summary>
    public static readonly DependencyProperty DockProperty =
        DependencyProperty.RegisterAttached("Dock",
        typeof(Dock),
        typeof(RadDockPanel),
        new System.Windows.PropertyMetadata(Dock.Left, RadDockPanel.OnDockChanged));
    /// <summary>
    /// Identifies the LastChildFill dependency property. 
    /// </summary>
    public static readonly DependencyProperty LastChildFillProperty =
        DependencyProperty.Register("LastChildFill",
        typeof(bool),
        typeof(RadDockPanel),
        new System.Windows.PropertyMetadata(true, RadDockPanel.OnLastChildFillChanged));
    /// <summary>
    /// Initializes a new instance of the <see cref="RadDockPanel"/> class.
    /// </summary>
    public RadDockPanel()
    {
        TelerikLicense.Verify(this);
    }
    /// <summary>
    /// Gets or sets a value that indicates whether the last child element within 
    /// a DockPanel stretches to fill the remaining available space. This is a dependency property.
    /// </summary>
    public bool LastChildFill
    {
        get
        {
            return (bool)GetValue(LastChildFillProperty);
        }
        set
        {
            SetValue(LastChildFillProperty, value);
        }
    }
    /// <summary>
    /// Gets the value of the Dock attached property for a specified UIElement.
    /// </summary>
    /// <param name="element">The element from which the property value is read.</param>
    /// <returns>The Dock property value for the element.</returns>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Dock should be used on UIElements only.")]
    public static Dock GetDock(UIElement element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        return (Dock)element.GetValue(DockProperty);
    }
    /// <summary>
    /// Sets the value of the Dock attached property to a specified element.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Dock should be used on UIElements only.")]
    public static void SetDock(UIElement element, Dock dock)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        element.SetValue(DockProperty, dock);
    }
    internal static bool IsValidDock(object o)
    {
        Dock dock = (Dock)o;
        if (((dock != Dock.Left) && (dock != Dock.Top)) && (dock != Dock.Right))
        {
            return dock == Dock.Bottom;
        }
        return true;
    }
    /// <summary>
    /// Provides the behavior for the "Arrange" pass of Silverlight layout. Classes can override this method to define their own arrange pass behavior.
    /// </summary>
    /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
    /// <returns>The actual size used.</returns>
    protected override Size ArrangeOverride(Size finalSize)
    {
        UIElementCollection internalChildren = Children;
        int count = internalChildren.Count;
        int num2 = count - (this.LastChildFill ? 1 : 0);
        double x = 0.0;
        double y = 0.0;
        double num5 = 0.0;
        double num6 = 0.0;
        for (int i = 0; i < count; i++)
        {
            UIElement element = internalChildren[i];
            if (element != null)
            {
                Size desiredSize = element.DesiredSize;
                Rect finalRect = new Rect(x, y, Math.Max((double)0.0, (double)(finalSize.Width - (x + num5))), Math.Max((double)0.0, (double)(finalSize.Height - (y + num6))));
                if (i < num2)
                {
                    switch (GetDock(element))
                    {
                        case Dock.Left:
                            x += desiredSize.Width;
                            finalRect.Width = desiredSize.Width;
                            break;
                        case Dock.Top:
                            y += desiredSize.Height;
                            finalRect.Height = desiredSize.Height;
                            break;
                        case Dock.Right:
                            num5 += desiredSize.Width;
                            finalRect.X = Math.Max((double)0.0, (double)(finalSize.Width - num5));
                            finalRect.Width = desiredSize.Width;
                            break;
                        case Dock.Bottom:
                            num6 += desiredSize.Height;
                            finalRect.Y = Math.Max((double)0.0, (double)(finalSize.Height - num6));
                            finalRect.Height = desiredSize.Height;
                            break;
                    }
                }
                element.Arrange(finalRect);
            }
        }
        return finalSize;
    }
    /// <summary>
    /// Provides the behavior for the "measure" pass of Silverlight layout. Classes can override this method to define their own measure pass behavior.
    /// </summary>
    /// <param name="availableSize">The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
    /// <returns>
    /// The size that this element determines it needs during layout, based on its calculations of child element sizes.
    /// </returns>
    protected override Size MeasureOverride(Size availableSize)
    {
        UIElementCollection internalChildren = Children;
        double num = 0.0;
        double num2 = 0.0;
        double num3 = 0.0;
        double num4 = 0.0;
        int num5 = 0;
        int count = internalChildren.Count;
        while (num5 < count)
        {
            UIElement element = internalChildren[num5];
            if (element != null)
            {
                Size remainingSize = new Size(Math.Max((double)0.0, (double)(availableSize.Width - num3)), Math.Max((double)0.0, (double)(availableSize.Height - num4)));
                element.Measure(remainingSize);
                Size desiredSize = element.DesiredSize;
                switch (GetDock(element))
                {
                    case Dock.Left:
                    case Dock.Right:
                        num2 = Math.Max(num2, num4 + desiredSize.Height);
                        num3 += desiredSize.Width;
                        break;
                    case Dock.Top:
                    case Dock.Bottom:
                        num = Math.Max(num, num3 + desiredSize.Width);
                        num4 += desiredSize.Height;
                        break;
                }
            }
            num5++;
        }
        num = Math.Max(num, num3);
        return new Size(num, Math.Max(num2, num4));
    }
    private static void OnDockChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!RadDockPanel.IsValidDock(e.NewValue))
        {
            throw new ArgumentException("Invalid Dock value");
        }
        FrameworkElement reference = d as FrameworkElement;
        if (reference != null)
        {
            RadDockPanel parent = reference.Parent as RadDockPanel;
            if (parent != null)
            {
                parent.InvalidateMeasure();
            }
        }
    }
    private static void OnLastChildFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        RadDockPanel panel = d as RadDockPanel;
        if (panel != null)
        {
            panel.InvalidateArrange();
        }
    }
}

in which cases should i use RadDockPanel?

1 Answer, 1 is accepted

Sort by
0
Accepted
Miroslav Nedyalkov
Telerik team
answered on 06 Sep 2010, 12:34 PM
Hello Igal,

 As you correctly noticed these panels are almost the same. The reason why we have created a panel that is almost the same as the standard WPF one, is that we wanted to provide all controls we have for Silverlight and we needed to create such a panel for Silverlight, because there is no standard one there. If you are going to build a WPF application (if you are not planning to port it to Silverlight), I would advise you to use the WPF DockPanel. If you are going to port the application to Silverlight, my advise is to use the RadDockPanel, because there is one in the RadControls for Silverlight as well and this will easy porting of the code and XAML.

Hope this answers your question.

Sincerely yours,
Miroslav Nedyalkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Tags
General Discussions
Asked by
igal a
Top achievements
Rank 1
Answers by
Miroslav Nedyalkov
Telerik team
Share this question
or