2012-06-21 32 views
25

Tôi có một StackPanel trong ứng dụng WinRT C# Metro của tôi mà tôi muốn sử dụng như container cho một cặp nhãn/giá trị (TextBlockTextBox) như thế này:Hãy TextBox căng để điền vào chiều rộng trong StackPanel

<StackPanel Orientation="Horizontal" Width="400"> 
    <TextBlock Text="Label" Width="150" /> 
    <TextBox Text="Value" /> 
</StackPanel> 

Bây giờ những gì tôi muốn là để cho TextBox tự động lấp đầy không gian ngang còn lại của StackPanel. Điều này có thể theo bất kỳ cách nào? HorizontalAlignment/HorizontalContentAlignment không hoạt động.

Tôi biết rằng một giải pháp thay thế sẽ là xác định Grid cho điều đó. Vấn đề là tôi có cấu trúc này nhiều lần và muốn sử dụng nó theo định nghĩa Style. Tôi không muốn xác định định nghĩa của Grid với các hàng và cột x lần ...

Có lẽ cách khác là xác định điều khiển người dùng tùy chỉnh, nhưng tôi hy vọng sẽ có khả năng dễ dàng để có được TextBox .

Trả lời

23

Thật không may thay thế (DockPanel) không khả dụng cho Metro. Bạn có thể thử một WrapGrid, nhưng tôi không biết nếu nó sẽ giải quyết vấn đề của bạn (Ive không bao giờ sử dụng nó).

Cách thực chỉ để làm điều này là sử dụng một lưới như bạn mô tả:

<Grid Width="400"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto" /> 
     <ColumnDefinition /> 
    </Grid.ColumnDefinitions> 
    <TextBlock Text="Label" Width="150" /> 
    <TextBox Text="Value" Grid.Column="1" /> 
</Grid> 
4

Came qua câu hỏi này trong khi nhìn lên dù một WinRT DockPanel tồn tại.

Tôi đã kết thúc sửa đổi một chút DockPanel đi kèm với Bộ công cụ Silverlight và có vẻ như nó hoạt động.

Để sử dụng, thêm xmlns:toolkit="using:System.Windows.Controls" để phía trên, và dùng câu hỏi trên như kịch bản, chúng ta có thể viết:

<toolkit:DockPanel Width="400"> 
    <TextBlock Text="Label" Width="150" toolkit:DockPanel.Dock="Left" /> 
    <TextBox Text="Value" /> 
</toolkit:DockPanel> 

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, 
    } 

    /// <summary> 
    /// Arranges child elements around the edges of the panel. Optionally, 
    /// last added child element can occupy the remaining space. 
    /// </summary> 
    /// <QualityBand>Stable</QualityBand> 
    public class DockPanel : Panel 
    { 
     /// <summary> 
     /// 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. 
     /// </summary> 
     private static bool _ignorePropertyChange; 

     #region public bool LastChildFill 
     /// <summary> 
     /// Gets or sets a value indicating whether the last child element 
     /// added to a <see cref="T:System.Windows.Controls.DockPanel" /> 
     /// resizes to fill the remaining space. 
     /// </summary> 
     /// <value> 
     /// 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. 
     /// </value> 
     public bool LastChildFill 
     { 
      get { return (bool)GetValue(LastChildFillProperty); } 
      set { SetValue(LastChildFillProperty, value); } 
     } 

     /// <summary> 
     /// Identifies the 
     /// <see cref="P:System.Windows.Controls.DockPanel.LastChildFill" /> 
     /// dependency property. 
     /// </summary> 
     public static readonly DependencyProperty LastChildFillProperty = 
      DependencyProperty.Register(
       "LastChildFill", 
       typeof(bool), 
       typeof(DockPanel), 
       new PropertyMetadata(true, OnLastChildFillPropertyChanged)); 

     /// <summary> 
     /// LastChildFillProperty property changed handler. 
     /// </summary> 
     /// <param name="d">DockPanel that changed its LastChildFill.</param> 
     /// <param name="e">Event arguments.</param> 
     private static void OnLastChildFillPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      DockPanel source = d as DockPanel; 
      source.InvalidateArrange(); 
     } 
     #endregion public bool LastChildFill 

     #region public attached Dock Dock 
     /// <summary> 
     /// Gets the value of the 
     /// <see cref="P:System.Windows.Controls.DockPanel.Dock" /> attached 
     /// property for the specified element. 
     /// </summary> 
     /// <param name="element"> 
     /// The element from which the property value is read. 
     /// </param> 
     /// <returns> 
     /// The <see cref="P:System.Windows.Controls.DockPanel.Dock" /> property 
     /// value for the element. 
     /// </returns> 
     [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); 
     } 

     /// <summary> 
     /// Sets the value of the 
     /// <see cref="P:System.Windows.Controls.DockPanel.Dock" /> attached 
     /// property for the specified element to the specified dock value. 
     /// </summary> 
     /// <param name="element"> 
     /// The element to which the attached property is assigned. 
     /// </param> 
     /// <param name="dock"> 
     /// The dock value to assign to the specified element. 
     /// </param> 
     [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); 
     } 

     /// <summary> 
     /// Identifies the 
     /// <see cref="P:System.Windows.Controls.DockPanel.Dock" /> 
     /// attached property. 
     /// </summary> 
     public static readonly DependencyProperty DockProperty = 
      DependencyProperty.RegisterAttached(
       "Dock", 
       typeof(Dock), 
       typeof(DockPanel), 
       new PropertyMetadata(Dock.Left, OnDockPropertyChanged)); 

     /// <summary> 
     /// DockProperty property changed handler. 
     /// </summary> 
     /// <param name="d">UIElement that changed its Dock.</param> 
     /// <param name="e">Event arguments.</param> 
     [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 

     /// <summary> 
     /// Initializes a new instance of the 
     /// <see cref="T:System.Windows.Controls.DockPanel" /> class. 
     /// </summary> 
     public DockPanel() 
     { 
     } 

     /// <summary> 
     /// Measures the child elements of a 
     /// <see cref="T:System.Windows.Controls.DockPanel" /> in preparation 
     /// for arranging them during the 
     /// <see cref="M:System.Windows.Controls.DockPanel.ArrangeOverride(System.Windows.Size)" /> 
     /// pass. 
     /// </summary> 
     /// <param name="constraint"> 
     /// The area available to the 
     /// <see cref="T:System.Windows.Controls.DockPanel" />. 
     /// </param> 
     /// <returns> 
     /// The desired size of the 
     /// <see cref="T:System.Windows.Controls.DockPanel" />. 
     /// </returns> 
     [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); 
     } 

     /// <summary> 
     /// Arranges the child elements of the 
     /// <see cref="T:System.Windows.Controls.DockPanel" /> control. 
     /// </summary> 
     /// <param name="arrangeSize"> 
     /// The area in the parent element that the 
     /// <see cref="T:System.Windows.Controls.DockPanel" /> should use to 
     /// arrange its child elements. 
     /// </param> 
     /// <returns> 
     /// The actual size of the 
     /// <see cref="T:System.Windows.Controls.DockPanel" /> after the child 
     /// elements are arranged. The actual size should always equal 
     /// <paramref name="arrangeSize" />. 
     /// </returns> 
     [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; 
     } 
    } 
} 
+0

Tiếp theo điều này và nó hoạt động như một nhà vô địch. Thanh danh. Tài liệu hay về cách sử dụng dockpanel có tại đây - http://www.silverlightshow.net/items/Using-the-DockPanel-in-Silverlight-2.aspx. –

17

Tôi không chắc chắn yếu tố nào bạn đặt HorizontalAlignment vào, nhưng đây là những gì phù hợp với tôi:

<StackPanel> 
    <TextBlock Text="Title" Style="..."/> 
    <TextBlock Margin="0,0,0,10" Text="Description" Style="..."/> 
    <TextBox HorizontalAlignment="Stretch" /> 
    <Button Margin="0" Content="Save"/> 
</StackPanel> 

Điều này kéo dài TextBox tới toàn bộ chiều rộng của StackPanel.

+0

Tôi nghĩ rằng đây là câu trả lời chính xác, chỉ cần sử dụng VerticalAlignment = "Stretch" hoặc HorizontalAlignment = "Stretch", dựa trên định hướng StackPanel của bạn –

+0

Hoạt động .. Cảm ơn bạn –

0

tôi đi qua sa mạc này trong 10 phút hoặc giờ, và đã tìm ra rằng sự kiểm soát nguồn gốc tốt nhất để neast nội dung là giao diện lưới tại snipet tôi rằng hoạt động tốt:

<Grid > 
    <TextBox x:Name="txtCountry" Margin="0,8,41,8" /> 
    <Button x:Name="btnGetCountry" Content="..." Margin="0,8,0,8" HorizontalAlignment="Right" Click="btnGetCountry_Click"> </Button> 
</Grid> 

này sẽ tạo ra một đẹp bố cục có thể điều chỉnh với một hộp văn bản steching và một butoon ở bên đó duy trì khía cạnh của mình

Các vấn đề liên quan