Let TextBox stretch to fill width in StackPanel

后端 未结 5 671
清歌不尽
清歌不尽 2021-01-01 09:58

I have a StackPanel in my WinRT C# Metro app that I want to use as container for a label/value pair (TextBlock and TextBox) like this:

5条回答
  •  温柔的废话
    2021-01-01 10:27

    Came across this question while looking up whether a WinRT DockPanel existed.

    I ended up slightly modifying the DockPanel that comes with the Silverlight Toolkit, and it seems to work.

    To use, add xmlns:toolkit="using:System.Windows.Controls" to the top, and taking the question above as the scenario, we could write:

    
        
        
    
    

    DockPanel.cs:

    // (c) Copyright Microsoft Corporation.
    // This source is subject to the Microsoft Public License (Ms-PL).
    // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
    // All other rights reserved.
    
    // Modified slightly for Windows Runtime support.
    
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    
    namespace System.Windows.Controls
    {
        public enum Dock
        {
            // Summary:
            //     Specifies that the control should be positioned on the left of the control.
            Left = 0,
            //
            // Summary:
            //     Specifies that the control should be positioned on top of the control.
            Top = 1,
            //
            // Summary:
            //     Specifies that the control should be positioned on the right of the control.
            Right = 2,
            //
            // Summary:
            //     Specifies that the control should be positioned at the bottom of the control.
            Bottom = 3,
        }
    
        /// 
        /// Arranges child elements around the edges of the panel.  Optionally, 
        /// last added child element can occupy the remaining space.
        /// 
        /// Stable
        public class DockPanel : Panel
        {
            /// 
            /// A value indicating whether a dependency property change handler
            /// should ignore the next change notification.  This is used to reset
            /// the value of properties without performing any of the actions in
            /// their change handlers.
            /// 
            private static bool _ignorePropertyChange;
    
            #region public bool LastChildFill
            /// 
            /// Gets or sets a value indicating whether the last child element
            /// added to a 
            /// resizes to fill the remaining space.
            /// 
            /// 
            /// True if the last element added resizes to fill the remaining space,
            /// false to indicate the last element does not resize. The default is
            /// true.
            /// 
            public bool LastChildFill
            {
                get { return (bool)GetValue(LastChildFillProperty); }
                set { SetValue(LastChildFillProperty, value); }
            }
    
            /// 
            /// Identifies the
            /// 
            /// dependency property.
            /// 
            public static readonly DependencyProperty LastChildFillProperty =
                DependencyProperty.Register(
                    "LastChildFill",
                    typeof(bool),
                    typeof(DockPanel),
                    new PropertyMetadata(true, OnLastChildFillPropertyChanged));
    
            /// 
            /// LastChildFillProperty property changed handler.
            /// 
            /// DockPanel that changed its LastChildFill.
            /// Event arguments.
            private static void OnLastChildFillPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                DockPanel source = d as DockPanel;
                source.InvalidateArrange();
            }
            #endregion public bool LastChildFill
    
            #region public attached Dock Dock
            /// 
            /// Gets the value of the
            ///  attached
            /// property for the specified element.
            /// 
            /// 
            /// The element from which the property value is read.
            /// 
            /// 
            /// The  property
            /// value for the element.
            /// 
            [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "DockPanel only has UIElement children")]
            public static Dock GetDock(UIElement element)
            {
                if (element == null)
                {
                    throw new ArgumentNullException("element");
                }
                return (Dock)element.GetValue(DockProperty);
            }
    
            /// 
            /// Sets the value of the
            ///  attached
            /// property for the specified element to the specified dock value.
            /// 
            /// 
            /// The element to which the attached property is assigned.
            /// 
            /// 
            /// The dock value to assign to the specified element.
            /// 
            [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "DockPanel only has UIElement children")]
            public static void SetDock(UIElement element, Dock dock)
            {
                if (element == null)
                {
                    throw new ArgumentNullException("element");
                }
                element.SetValue(DockProperty, dock);
            }
    
            /// 
            /// Identifies the
            /// 
            /// attached property.
            /// 
            public static readonly DependencyProperty DockProperty =
                DependencyProperty.RegisterAttached(
                    "Dock",
                    typeof(Dock),
                    typeof(DockPanel),
                    new PropertyMetadata(Dock.Left, OnDockPropertyChanged));
    
            /// 
            /// DockProperty property changed handler.
            /// 
            /// UIElement that changed its Dock.
            /// Event arguments.
            [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "Almost always set from the attached property CLR setter.")]
            private static void OnDockPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                // Ignore the change if requested
                if (_ignorePropertyChange)
                {
                    _ignorePropertyChange = false;
                    return;
                }
    
                UIElement element = (UIElement)d;
                Dock value = (Dock)e.NewValue;
    
                // Validate the Dock property
                if ((value != Dock.Left) &&
                    (value != Dock.Top) &&
                    (value != Dock.Right) &&
                    (value != Dock.Bottom))
                {
                    // Reset the property to its original state before throwing
                    _ignorePropertyChange = true;
                    element.SetValue(DockProperty, (Dock)e.OldValue);
    
                    string message = string.Format(
                        CultureInfo.InvariantCulture,
                        "InvalidValue",
                        value);
                    throw new ArgumentException(message, "value");
                }
    
                // Cause the DockPanel to update its layout when a child changes
                DockPanel panel = VisualTreeHelper.GetParent(element) as DockPanel;
                if (panel != null)
                {
                    panel.InvalidateMeasure();
                }
            }
            #endregion public attached Dock Dock
    
            /// 
            /// Initializes a new instance of the
            ///  class.
            /// 
            public DockPanel()
            {
            }
    
            /// 
            /// Measures the child elements of a
            ///  in preparation
            /// for arranging them during the
            /// 
            /// pass.
            /// 
            /// 
            /// The area available to the
            /// .
            /// 
            /// 
            /// The desired size of the
            /// .
            /// 
            [SuppressMessage("Microsoft.Naming", "CA1725:ParameterNamesShouldMatchBaseDeclaration", MessageId = "0#", Justification = "Compat with WPF.")]
            protected override Size MeasureOverride(Size constraint)
            {
                double usedWidth = 0.0;
                double usedHeight = 0.0;
                double maximumWidth = 0.0;
                double maximumHeight = 0.0;
    
                // Measure each of the Children
                foreach (UIElement element in Children)
                {
                    // Get the child's desired size
                    Size remainingSize = new Size(
                        Math.Max(0.0, constraint.Width - usedWidth),
                        Math.Max(0.0, constraint.Height - usedHeight));
                    element.Measure(remainingSize);
                    Size desiredSize = element.DesiredSize;
    
                    // Decrease the remaining space for the rest of the children
                    switch (GetDock(element))
                    {
                        case Dock.Left:
                        case Dock.Right:
                            maximumHeight = Math.Max(maximumHeight, usedHeight + desiredSize.Height);
                            usedWidth += desiredSize.Width;
                            break;
                        case Dock.Top:
                        case Dock.Bottom:
                            maximumWidth = Math.Max(maximumWidth, usedWidth + desiredSize.Width);
                            usedHeight += desiredSize.Height;
                            break;
                    }
                }
    
                maximumWidth = Math.Max(maximumWidth, usedWidth);
                maximumHeight = Math.Max(maximumHeight, usedHeight);
                return new Size(maximumWidth, maximumHeight);
            }
    
            /// 
            /// Arranges the child elements of the
            ///  control.
            /// 
            /// 
            /// The area in the parent element that the
            ///  should use to
            /// arrange its child elements.
            /// 
            /// 
            /// The actual size of the
            ///  after the child
            /// elements are arranged. The actual size should always equal
            /// .
            /// 
            [SuppressMessage("Microsoft.Naming", "CA1725:ParameterNamesShouldMatchBaseDeclaration", MessageId = "0#", Justification = "Compat with WPF.")]
            protected override Size ArrangeOverride(Size arrangeSize)
            {
                double left = 0.0;
                double top = 0.0;
                double right = 0.0;
                double bottom = 0.0;
    
                // Arrange each of the Children
                UIElementCollection children = Children;
                int dockedCount = children.Count - (LastChildFill ? 1 : 0);
                int index = 0;
                foreach (UIElement element in children)
                {
                    // Determine the remaining space left to arrange the element
                    Rect remainingRect = new Rect(
                        left,
                        top,
                        Math.Max(0.0, arrangeSize.Width - left - right),
                        Math.Max(0.0, arrangeSize.Height - top - bottom));
    
                    // Trim the remaining Rect to the docked size of the element
                    // (unless the element should fill the remaining space because
                    // of LastChildFill)
                    if (index < dockedCount)
                    {
                        Size desiredSize = element.DesiredSize;
                        switch (GetDock(element))
                        {
                            case Dock.Left:
                                left += desiredSize.Width;
                                remainingRect.Width = desiredSize.Width;
                                break;
                            case Dock.Top:
                                top += desiredSize.Height;
                                remainingRect.Height = desiredSize.Height;
                                break;
                            case Dock.Right:
                                right += desiredSize.Width;
                                remainingRect.X = Math.Max(0.0, arrangeSize.Width - right);
                                remainingRect.Width = desiredSize.Width;
                                break;
                            case Dock.Bottom:
                                bottom += desiredSize.Height;
                                remainingRect.Y = Math.Max(0.0, arrangeSize.Height - bottom);
                                remainingRect.Height = desiredSize.Height;
                                break;
                        }
                    }
    
                    element.Arrange(remainingRect);
                    index++;
                }
    
                return arrangeSize;
            }
        }
    }
    

提交回复
热议问题