2014-01-08 58 views
0

我在數據輸入表單上有一組usercontrols。爲了最大限度地利用空間,這些用戶控件被放置在一個垂直擴展的wrappanel中。我的表單效果很好,但看起來並沒有打磨。我在移動設備上打字,因此無法發佈圖片,但請讓我描述一下。假設表單有3個usercontrols人口統計(寬度800),電話號碼(寬度300),地址(寬度600)。該表格本身是1000像素寬。帶LastChildFill的WrapPanel

現在,當這些用戶控件佈局(按上面列出的順序)時,人口統計信息將位於第一行,而另外兩個用戶控件位於下面的行中。

但是,人口統計信息控件將只能處理該行中可用1000像素的800個像素。最後一行同樣只會佔用900個像素。這使得表單看起來很醜。

我需要的是讓每一行中的最後一個孩子伸展其邊界bix(即其邊界)以佔據剩餘的空間。因此,在這種情況下,人口統計學邊界將延伸至1000個像素,地址邊界將延伸至700個像素。

usercontrol集合是動態的。用戶可以即時創建新表單並更改元素及其順序。

如果屏幕大小發生變化,拉伸的元素將恢復到其原始寬度,換行面板會重新排列元素,並且每行中的最後一個子元素會再次填充剩餘空間。

希望我能夠正確地解釋這種情況。謝謝你的時間。

+0

你的意思是有可能也只有一排與最後一個元素填充它,或三排,其中每個元素填滿整個行? – Clemens

+0

而且它是Silverlight還是WPF?它不能兼而有之。 – Clemens

+0

在上述場景中,有兩行。第1行包含人口統計信息,第2行包含手機和地址,前提是wrappanel的寬度爲1000像素,但表示面板縮小至800像素,則會有3行。一個fir每個用戶控件。在這種情況下,用戶控件的人口統計已經和wrappanel一樣寬,但其他兩個用戶控件需要被拉伸到800寬度。這是爲了silverlight。謝謝 – user559788

回答

1

結束寫我自己的自定義面板。在創建新行之前的MeasureOverride,jyst中,返回到最後一個處理的控件,並將其長度設置爲control.length +(maximumSize-lineSize)。

這似乎很好運行

+0

我想你的自定義Panel從WrapPanel繼承?看起來像MS很容易實現的一個很酷的功能,其適當的DependencyProperty ... – almulo

0

我已經爲此做了一個控制。我發表在:CodeProject

用法:

<wrapPanelWithFill:WrapPanelFill Grid.Row="3" Grid.Column="1"> 
     <TextBlock Text="Path: " TextWrapping="Wrap"></TextBlock> 
     <TextBox MinWidth="120" wrapPanelWithFill:WrapPanelFill.UseToFill="True">*</TextBox> 
     <Button>Browse...</Button> 
</wrapPanelWithFill:WrapPanelFill> 

代碼:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Windows; 
using System.Windows.Controls; 

namespace WrapPanelWithFill 
{ 
    public class WrapPanelFill : WrapPanel 
    { 
     // ****************************************************************** 
     public static readonly DependencyProperty UseToFillProperty = DependencyProperty.RegisterAttached("UseToFill", typeof(Boolean), 
      typeof(WrapPanelFill), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)); 

     // ****************************************************************** 
     public static void SetUseToFill(UIElement element, Boolean value) 
     { 
      element.SetValue(UseToFillProperty, value); 
     } 
     // ****************************************************************** 
     public static Boolean GetUseToFill(UIElement element) 
     { 
      return (Boolean)element.GetValue(UseToFillProperty); 
     } 

     // ****************************************************************** 
     const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */ 

     // ****************************************************************** 
     private static bool DoubleAreClose(double value1, double value2) 
     { 
      //in case they are Infinities (then epsilon check does not work) 
      if (value1 == value2) return true; 
      // This computes (|value1-value2|/(|value1| + |value2| + 10.0)) < DBL_EPSILON 
      double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON; 
      double delta = value1 - value2; 
      return (-eps < delta) && (eps > delta); 
     } 

     // ****************************************************************** 
     private static bool DoubleGreaterThan(double value1, double value2) 
     { 
      return (value1 > value2) && !DoubleAreClose(value1, value2); 
     } 

     // ****************************************************************** 
     private bool _atLeastOneElementCanHasItsWidthExpanded = false; 

     // ****************************************************************** 
     /// <summary> 
     /// <see cref="FrameworkElement.MeasureOverride"/> 
     /// </summary> 
     protected override Size MeasureOverride(Size constraint) 
     { 
      UVSize curLineSize = new UVSize(Orientation); 
      UVSize panelSize = new UVSize(Orientation); 
      UVSize uvConstraint = new UVSize(Orientation, constraint.Width, constraint.Height); 
      double itemWidth = ItemWidth; 
      double itemHeight = ItemHeight; 
      bool itemWidthSet = !Double.IsNaN(itemWidth); 
      bool itemHeightSet = !Double.IsNaN(itemHeight); 

      Size childConstraint = new Size(
       (itemWidthSet ? itemWidth : constraint.Width), 
       (itemHeightSet ? itemHeight : constraint.Height)); 

      UIElementCollection children = InternalChildren; 

      // EO 
      LineInfo currentLineInfo = new LineInfo(); // EO, the way it works it is always like we are on the current line 
      _lineInfos.Clear(); 
      _atLeastOneElementCanHasItsWidthExpanded = false; 

      for (int i = 0, count = children.Count; i < count; i++) 
      { 
       UIElement child = children[i] as UIElement; 
       if (child == null) continue; 

       //Flow passes its own constrint to children 
       child.Measure(childConstraint); 

       //this is the size of the child in UV space 
       UVSize sz = new UVSize(
        Orientation, 
        (itemWidthSet ? itemWidth : child.DesiredSize.Width), 
        (itemHeightSet ? itemHeight : child.DesiredSize.Height)); 

       if (DoubleGreaterThan(curLineSize.U + sz.U, uvConstraint.U)) //need to switch to another line 
       { 
        // EO 
        currentLineInfo.Size = curLineSize; 
        _lineInfos.Add(currentLineInfo); 

        panelSize.U = Math.Max(curLineSize.U, panelSize.U); 
        panelSize.V += curLineSize.V; 
        curLineSize = sz; 

        // EO 
        currentLineInfo = new LineInfo(); 
        var feChild = child as FrameworkElement; 
        if (GetUseToFill(feChild)) 
        { 
         currentLineInfo.ElementsWithNoWidthSet.Add(feChild); 
         _atLeastOneElementCanHasItsWidthExpanded = true; 
        } 

        if (DoubleGreaterThan(sz.U, uvConstraint.U)) //the element is wider then the constrint - give it a separate line 
        { 
         currentLineInfo = new LineInfo(); 

         panelSize.U = Math.Max(sz.U, panelSize.U); 
         panelSize.V += sz.V; 
         curLineSize = new UVSize(Orientation); 
        } 
       } 
       else //continue to accumulate a line 
       { 
        curLineSize.U += sz.U; 
        curLineSize.V = Math.Max(sz.V, curLineSize.V); 

        // EO 
        var feChild = child as FrameworkElement; 
        if (GetUseToFill(feChild)) 
        { 
         currentLineInfo.ElementsWithNoWidthSet.Add(feChild); 
         _atLeastOneElementCanHasItsWidthExpanded = true; 
        } 
       } 
      } 

      if (curLineSize.U > 0) 
      { 
       currentLineInfo.Size = curLineSize; 
       _lineInfos.Add(currentLineInfo); 
      } 

      //the last line size, if any should be added 
      panelSize.U = Math.Max(curLineSize.U, panelSize.U); 
      panelSize.V += curLineSize.V; 

      // EO 
      if (_atLeastOneElementCanHasItsWidthExpanded) 
      { 
       return new Size(constraint.Width, panelSize.Height); 
      } 

      //go from UV space to W/H space 
      return new Size(panelSize.Width, panelSize.Height); 
     } 

     // ************************************************************************ 
     private struct UVSize 
     { 
      internal UVSize(Orientation orientation, double width, double height) 
      { 
       U = V = 0d; 
       _orientation = orientation; 
       Width = width; 
       Height = height; 
      } 

      internal UVSize(Orientation orientation) 
      { 
       U = V = 0d; 
       _orientation = orientation; 
      } 

      internal double U; 
      internal double V; 
      private Orientation _orientation; 

      internal double Width 
      { 
       get { return (_orientation == Orientation.Horizontal ? U : V); } 
       set { if (_orientation == Orientation.Horizontal) U = value; else V = value; } 
      } 
      internal double Height 
      { 
       get { return (_orientation == Orientation.Horizontal ? V : U); } 
       set { if (_orientation == Orientation.Horizontal) V = value; else U = value; } 
      } 
     } 

     // ************************************************************************ 
     private class LineInfo 
     { 
      public List<UIElement> ElementsWithNoWidthSet = new List<UIElement>(); 
      //   public double SpaceLeft = 0; 
      //   public double WidthCorrectionPerElement = 0; 
      public UVSize Size; 
      public double Correction = 0; 
     } 

     private List<LineInfo> _lineInfos = new List<LineInfo>(); 

     // ************************************************************************ 
     /// <summary> 
     /// <see cref="FrameworkElement.ArrangeOverride"/> 
     /// </summary> 
     protected override Size ArrangeOverride(Size finalSize) 
     { 
      int lineIndex = 0; 
      int firstInLine = 0; 
      double itemWidth = ItemWidth; 
      double itemHeight = ItemHeight; 
      double accumulatedV = 0; 
      double itemU = (Orientation == Orientation.Horizontal ? itemWidth : itemHeight); 
      UVSize curLineSize = new UVSize(Orientation); 
      UVSize uvFinalSize = new UVSize(Orientation, finalSize.Width, finalSize.Height); 
      bool itemWidthSet = !Double.IsNaN(itemWidth); 
      bool itemHeightSet = !Double.IsNaN(itemHeight); 
      bool useItemU = (Orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet); 

      UIElementCollection children = InternalChildren; 

      for (int i = 0, count = children.Count; i < count; i++) 
      { 
       UIElement child = children[i] as UIElement; 
       if (child == null) continue; 

       UVSize sz = new UVSize(
        Orientation, 
        (itemWidthSet ? itemWidth : child.DesiredSize.Width), 
        (itemHeightSet ? itemHeight : child.DesiredSize.Height)); 

       if (DoubleGreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) //need to switch to another line 
       { 
        arrangeLine(lineIndex, accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU, uvFinalSize); 
        lineIndex++; 

        accumulatedV += curLineSize.V; 
        curLineSize = sz; 

        if (DoubleGreaterThan(sz.U, uvFinalSize.U)) //the element is wider then the constraint - give it a separate line 
        { 
         //switch to next line which only contain one element 
         arrangeLine(lineIndex, accumulatedV, sz.V, i, ++i, useItemU, itemU, uvFinalSize); 

         accumulatedV += sz.V; 
         curLineSize = new UVSize(Orientation); 
        } 
        firstInLine = i; 
       } 
       else //continue to accumulate a line 
       { 
        curLineSize.U += sz.U; 
        curLineSize.V = Math.Max(sz.V, curLineSize.V); 
       } 
      } 

      //arrange the last line, if any 
      if (firstInLine < children.Count) 
      { 
       arrangeLine(lineIndex, accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU, uvFinalSize); 
      } 

      return finalSize; 
     } 

     // ************************************************************************ 
     private void arrangeLine(int lineIndex, double v, double lineV, int start, int end, bool useItemU, double itemU, UVSize uvFinalSize) 
     { 
      double u = 0; 
      bool isHorizontal = (Orientation == Orientation.Horizontal); 

      Debug.Assert(lineIndex < _lineInfos.Count); 

      LineInfo lineInfo = _lineInfos[lineIndex]; 
      double lineSpaceAvailableForCorrection = Math.Max(uvFinalSize.U - lineInfo.Size.U, 0); 
      double perControlCorrection = 0; 
      if (lineSpaceAvailableForCorrection > 0 && lineInfo.Size.U > 0) 
      { 
       perControlCorrection = lineSpaceAvailableForCorrection/lineInfo.ElementsWithNoWidthSet.Count; 
       if (double.IsInfinity(perControlCorrection)) 
       { 
        perControlCorrection = 0; 
       } 
      } 
      int indexOfControlToAdjustSizeToFill = 0; 
      UIElement uIElementToAdjustNext = indexOfControlToAdjustSizeToFill < lineInfo.ElementsWithNoWidthSet.Count ? lineInfo.ElementsWithNoWidthSet[indexOfControlToAdjustSizeToFill] : null; 

      UIElementCollection children = InternalChildren; 
      for (int i = start; i < end; i++) 
      { 
       UIElement child = children[i] as UIElement; 
       if (child != null) 
       { 
        UVSize childSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); 
        double layoutSlotU = (useItemU ? itemU : childSize.U); 

        if (perControlCorrection > 0 && child == uIElementToAdjustNext) 
        { 
         layoutSlotU += perControlCorrection; 

         indexOfControlToAdjustSizeToFill++; 
         uIElementToAdjustNext = indexOfControlToAdjustSizeToFill < lineInfo.ElementsWithNoWidthSet.Count ? lineInfo.ElementsWithNoWidthSet[indexOfControlToAdjustSizeToFill] : null; 
        } 

        child.Arrange(new Rect(
         (isHorizontal ? u : v), 
         (isHorizontal ? v : u), 
         (isHorizontal ? layoutSlotU : lineV), 
         (isHorizontal ? lineV : layoutSlotU))); 
        u += layoutSlotU; 
       } 
      } 
     } 

     // ************************************************************************ 

    } 
} 
+0

不錯。代碼看起來比我的更乾淨:)我正在將代碼移植到Windows應用程序(來自Silverlight)。當我到達UI部分時,我會放棄這一點。謝謝 – user559788