2011-11-08 19 views
2

レイアウトにサイズ変更可能なコンテナコントロールがあります。レイアウトパネル上のXAMLレイアウト中心のアイテム

Desired layout

私はあなたのアイデアを持っている願っています:それは(サイズ変更もあり、常に3 * 2今のところ)、次のように私のユーザーコントロールの任意の数を含める必要があります。 StackPanelを使用しようとしましたが、失敗しました。それは私のために要素を中心にしていませんでした。

XAMLを使用して希望するレイアウトを取得するにはどうすればよいですか?私は結果を共有しなければならないと考えてい

:うまくいけば

...私がなってしまったCODEを可能な限り避けるコーディング。私はこの答えWPF - How can I center all items in a WrapPanel?からコードを取り出し、子コントロールのサイズを変更しました。

private Size elementFinalSize = new Size(0, 0); 

    private Size MeasureDesiredSize(Size containerSize) 
    { 
     if (base.InternalChildren.Count == 0) 
     { 
      return new Size(0, 0); 
     } 

     // NB!: We assume all the items in the panel are of the same size. 
     var child = base.InternalChildren[0]; 
     double elementAspectRatio = child.DesiredSize.Height == 0 ? 2.0/3.0 : child.DesiredSize.Width/child.DesiredSize.Height; 
     Size finalElementSize = new Size(0, 0); 
     Size newElementSize = finalElementSize; 
     for (int possibleRowsNumber = 1; ; possibleRowsNumber++) 
     { 
      int numberOfElementInRow = this.GetElementsNumberInRow(base.InternalChildren.Count, possibleRowsNumber); 
      double maxElementHeight = containerSize.Height/possibleRowsNumber; 
      double maxElementWidth = containerSize.Width/numberOfElementInRow; 
      if (maxElementWidth/elementAspectRatio > maxElementHeight) 
      { 
       // So many elements is more in width than container size, thus use Height. 
       newElementSize = new Size(maxElementHeight * elementAspectRatio, maxElementHeight); 
      } 
      else 
      { 
       // The element Height is greater than container row size, thus use Width. 
       newElementSize = new Size(maxElementWidth, maxElementWidth/elementAspectRatio); 
      } 

      if (newElementSize.Height > finalElementSize.Height) 
      { 
       // With such number of row a single element would be bigger than with previous number of rows. 
       finalElementSize = newElementSize; 
      } 
      else 
      { 
       // With such number of rows a single element is less than the previous biggest one, thus stop searching. 
       break; 
      } 
     } 

     return finalElementSize; 
    } 

    private int GetElementsNumberInRow(int elementsCount, int rowsNumber) 
    { 
     int x = elementsCount % rowsNumber; 
     if (x == 0) 
     { 
      return elementsCount/rowsNumber; 
     } 

     int maxPossibleElementsCount = elementsCount + rowsNumber - x; 
     return maxPossibleElementsCount/rowsNumber; 
    } 

    protected override Size MeasureOverride(Size constraint) 
    { 
     // This MeasureOverride functions is called the first of the three overridden. 
     // We need to understand the best (maximum) size for future element and arrange items accordingly. 

     // Drop the desired size to zero in order to recalculate it as soon as necessary. 
     this.elementFinalSize = new Size(0, 0); 

     Size curLineSize = new Size(); 
     Size panelSize = new Size(); 

     UIElementCollection children = base.InternalChildren; 

     for (int i = 0; i < children.Count; i++) 
     { 
      UIElement child = children[i] as UIElement; 

      // Flow passes its own constraint to children 
      if (this.elementFinalSize.Height == 0) 
      { 
       child.Measure(constraint); 
       this.elementFinalSize = this.MeasureDesiredSize(constraint); 
       child.InvalidateMeasure(); 
      } 

      if (curLineSize.Width + this.elementFinalSize.Width > constraint.Width) //need to switch to another line 
      { 
       panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width); 
       panelSize.Height += curLineSize.Height; 
       curLineSize = this.elementFinalSize; 

       if (this.elementFinalSize.Width > constraint.Width) // if the element is wider then the constraint - give it a separate line      
       { 
        panelSize.Width = Math.Max(this.elementFinalSize.Width, panelSize.Width); 
        panelSize.Height += this.elementFinalSize.Height; 
        curLineSize = new Size(); 
       } 
      } 
      else //continue to accumulate a line 
      { 
       curLineSize.Width += this.elementFinalSize.Width; 
       curLineSize.Height = Math.Max(this.elementFinalSize.Height, curLineSize.Height); 
      } 
     } 

     foreach (UIElement child in children) 
     { 
      child.Measure(this.elementFinalSize); 
     } 

     // the last line size, if any need to be added 
     panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width); 
     panelSize.Height += curLineSize.Height; 

     return panelSize; 
    } 

    protected override Size ArrangeOverride(Size arrangeBounds) 
    { 
     int firstInLine = 0; 
     Size curLineSize = new Size(); 
     double accumulatedHeight = 0; 
     UIElementCollection children = this.InternalChildren; 

     for (int i = 0; i < children.Count; i++) 
     { 
      if (curLineSize.Width + this.elementFinalSize.Width > arrangeBounds.Width) //need to switch to another line 
      { 
       ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, i); 

       accumulatedHeight += curLineSize.Height; 
       curLineSize = this.elementFinalSize; 

       if (this.elementFinalSize.Width > arrangeBounds.Width) //the element is wider then the constraint - give it a separate line      
       { 
        ArrangeLine(accumulatedHeight, this.elementFinalSize, arrangeBounds.Width, i, ++i); 
        accumulatedHeight += this.elementFinalSize.Height; 
        curLineSize = new Size(); 
       } 
       firstInLine = i; 
      } 
      else //continue to accumulate a line 
      { 
       curLineSize.Width += this.elementFinalSize.Width; 
       curLineSize.Height = Math.Max(this.elementFinalSize.Height, curLineSize.Height); 
      } 
     } 

     if (firstInLine < children.Count) 
      ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, children.Count); 

     return arrangeBounds; 
    } 

    private void ArrangeLine(double y, Size lineSize, double boundsWidth, int start, int end) 
    { 
     double x = 0; 
     if (this.HorizontalContentAlignment == HorizontalAlignment.Center) 
     { 
      x = (boundsWidth - lineSize.Width)/2; 
     } 
     else if (this.HorizontalContentAlignment == HorizontalAlignment.Right) 
     { 
      x = (boundsWidth - lineSize.Width); 
     } 

     UIElementCollection children = InternalChildren; 
     for (int i = start; i < end; i++) 
     { 
      UIElement child = children[i]; 
      child.Arrange(new Rect(x, y, this.elementFinalSize.Width, this.elementFinalSize.Height)); 
      x += this.elementFinalSize.Width; 
     } 
    } 
+0

あなたは、パネル内のすべての要素は、「センター」に水平/ VerticalAlignmentをを入れてみましたか? – stijn

+0

私は今日それを試みます。 –

+0

WrapPanelを試してみてください.3 * 2の意味もありますか? –

答えて

5

以下は、ほぼ同じ効果が生成されます。

<Grid> 
    <WrapPanel HorizontalAlignment="Center" VerticalAlignment="Center" > 
     <Rectangle Stroke="Red" StrokeThickness="2" Width="200" Height="200"/> 
     <Rectangle Stroke="Red" StrokeThickness="2" Width="200" Height="200"/> 
     <Rectangle Stroke="Red" StrokeThickness="2" Width="200" Height="200"/> 
    </WrapPanel> 
</Grid> 

が、アイテムをあなたの最後のスクリーンショットが左に整列下の四角形を示すだろうあなたのケースでて左詰めされています。これを修正するには、create a custom implementation of WrapPanel just for that purpose

編集:もちろんこれは矩形とすべてを含む単なるダミーの例ですが、通常はListView/ListBox/ItemContainer(シナリオによって異なる)を作成し、ItemsPanelをWrapPanelにします:

<ListView> 
    <ListView.ItemsPanel> 
     <ItemsPanelTemplate> 
      <WrapPanel .../> 
     </ItemsPanelTemplate> 
    </ListView.ItemsPanel> 
</ListView> 
+0

+1、素敵なリンク... –

+0

明示的な矩形のサイズ変更を避ける方法を理解できませんか?長方形のサイズを扱うためのコンテナが必要です。 –

+1

これは、カスタムコンテナ(WrapPanelのサブクラスなど)でMeasureOverrideメソッドとArrangeOverrideメソッドをオーバーライドすることで可能です。そこには、子どものサイズをプログラムで設定できます。 – edvaldig

関連する問題