BoxPanel、カスタム パネルの例BoxPanel, an example custom panel

カスタム Panel クラスのコードの記述、ArrangeOverride メソッドと MeasureOverride メソッドの実装、Children プロパティの使用について説明します。Learn to write code for a custom Panel class, implementing ArrangeOverride and MeasureOverride methods, and using the Children property.

重要な API:パネル ArrangeOverrideMeasureOverrideImportant APIs: Panel, ArrangeOverride,MeasureOverride

コード例ではカスタム パネルの実装を示しますが、さまざまなレイアウト シナリオのパネルのカスタマイズ方法に影響を与えるレイアウトの概念については、詳しく説明していません。The example code shows a custom panel implementation, but we don't devote a lot of time explaining the layout concepts that influence how you can customize a panel for different layout scenarios. このようなレイアウトの概念や、自分の特定のレイアウト シナリオへの適用方法に関する詳細情報が必要な場合は、「XAML カスタム パネルの概要」をご覧ください。If you want more info about these layout concepts and how they might apply to your particular layout scenario, see XAML custom panels overview.

パネルは、XAML レイアウト システムが実行されて、アプリの UI が表示されるときに、含まれている子要素のレイアウト動作を提供するオブジェクトです。A panel is an object that provides a layout behavior for child elements it contains, when the XAML layout system runs and your app UI is rendered. Panel クラスからカスタム クラスを派生させて、XAML レイアウトのカスタム パネルを定義できます。You can define custom panels for XAML layout by deriving a custom class from the Panel class. パネルの動作は、ArrangeOverride メソッドと MeasureOverride メソッドをオーバーライドすることで子要素を評価して配置するロジックを提供して実行します。You provide behavior for your panel by overriding the ArrangeOverride and MeasureOverride methods, supplying logic that measures and arranges the child elements. この例は、Panel から派生しています。This example derives from Panel. Panel から開始した場合、ArrangeOverride メソッドと MeasureOverride メソッドには起動動作がありません。When you start from Panel, ArrangeOverride and MeasureOverride methods don't have a starting behavior. コードが提供するゲートウェイによって、子要素が XAML レイアウト システムに認識され、UI に表示されます。Your code is providing the gateway by which child elements become known to the XAML layout system and get rendered in the UI. したがって、コードがすべての子要素について説明し、レイアウト システムが想定しているパターンに従うことが実際に重要です。So, it's really important that your code accounts for all child elements and follows the patterns the layout system expects.

レイアウト シナリオYour layout scenario

カスタム パネルを定義することは、レイアウト シナリオを定義することです。When you define a custom panel, you're defining a layout scenario.

レイアウト シナリオは、次によって表現されます。A layout scenario is expressed through:

  • 子要素が作成されたときのパネルの動作What the panel will do when it has child elements
  • パネル自体のスペースが制約されるタイミングWhen the panel has constraints on its own space
  • 最終的に子要素の UI レイアウトとして描画される測定値、配置、サイズのすべてを、パネルのロジックが決定する方法How the logic of the panel determines all the measurements, placement, positions, and sizings that eventually result in a rendered UI layout of children

この点を考慮して、特定のシナリオが使用する BoxPanel を次に示します。With that in mind, the BoxPanel shown here is for a particular scenario. この例でコードを最優先するために、ここではシナリオを詳しくは説明しません。その代わり、必要な手順とコーディング パターンについて重点的に説明します。In the interest of keeping the code foremost in this example, we won't explain the scenario in detail yet, and instead concentrate on the steps needed and the coding patterns. 最初にシナリオについて詳しく知りたい場合は、この後にある「BoxPanel のシナリオ」を参照した後、コードの説明に戻ってください。If you want to know more about the scenario first, skip ahead to "The scenario for BoxPanel", and then come back to the code.

Panel からの派生で開始するStart by deriving from Panel

まず、Panel からカスタム クラスを派生させます。Start by deriving a custom class from Panel. このために最も簡単と思われる方法は、このクラスのための別のコード ファイルを定義することです。これには、Microsoft Visual Studio のソリューション エクスプローラーでプロジェクトに対してコンテキスト メニューの [追加] | [新しい項目] | [クラス] をクリックします。Probably the easiest way to do this is to define a separate code file for this class, using the Add | New Item | Class context menu options for a project from the Solution Explorer in Microsoft Visual Studio. このクラス (とファイル) に、BoxPanel という名前を付けます。Name the class (and file) BoxPanel.

クラスのテンプレート ファイルが、多くの using ステートメントで始まることはありません。このステートメントは、特にユニバーサル Windows プラットフォーム (UWP) アプリ用ではないためです。The template file for a class doesn't start with many using statements because it's not specifically for Universal Windows Platform (UWP) apps. まず、using ステートメントを追加します。So first, add using statements. また、テンプレート ファイルはいくつかの using ステートメントで始まっていますが、おそらく不要と思われるため、削除することができます。The template file also starts with a few using statements that you probably don't need, and can be deleted. 次に示すのは、一般的なカスタム パネル コードに必要となる型を解決できる using ステートメントの候補の一覧です。Here's a suggested list of using statements that can resolve types you'll need for typical custom panel code:

using System;
using System.Collections.Generic; // if you need to cast IEnumerable for iteration, or define your own collection properties
using Windows.Foundation; // Point, Size, and Rect
using Windows.UI.Xaml; // DependencyObject, UIElement, and FrameworkElement
using Windows.UI.Xaml.Controls; // Panel
using Windows.UI.Xaml.Media; // if you need Brushes or other utilities

これで Panel を解決できるので、これを BoxPanel の基底クラスにします。Now that you can resolve Panel, make it the base class of BoxPanel. また、BoxPanel を公開します。Also, make BoxPanel public:

public class BoxPanel : Panel
{
}

クラス レベルでは、複数の論理関数で共有される int 値と double 値をいくつか定義しますが、これらは、パブリック API として公開する必要はありません。At the class level, define some int and double values that will be shared by several of your logic functions, but which won't need to be exposed as public API. 例では、これらの名前は maxrcrowcountcolcountcellwidthcellheightmaxcellheightaspectratio です。In the example, these are named: maxrc, rowcount, colcount, cellwidth, cellheight, maxcellheight, aspectratio.

これを行った後、コード ファイル全体は次のようになります (ここにある理由はわかっているので、using のコメントは削除します)。After you've done this, the complete code file looks like this (removing comments on using, now that you know why we have them):

using System;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

public class BoxPanel : Panel 
{
    int maxrc, rowcount, colcount;
    double cellwidth, cellheight, maxcellheight, aspectratio;
}

これ以降は、メソッドのオーバーライド、依存関係プロパティなどのサポートするものなどのメンバー定義を 1 つずつ示します。From here on out, we'll be showing you one member definition at a time, be that a method override or something supporting such as a dependency property. これらは、上に示したスケルトンに任意の順序で追加できます。最終的なコードを示すまで、スニペットでは、using ステートメントとクラス スコープの定義のいずれも再び示すことはありません。You can add these to the skeleton above in any order, and we won't be showing the using statements or the definition of the class scope again in the snippets until we show the final code.

MeasureOverrideMeasureOverride

protected override Size MeasureOverride(Size availableSize)
{
    Size returnSize;
    // Determine the square that can contain this number of items.
    maxrc = (int)Math.Ceiling(Math.Sqrt(Children.Count));
    // Get an aspect ratio from availableSize, decides whether to trim row or column.
    aspectratio = availableSize.Width / availableSize.Height;

    // Now trim this square down to a rect, many times an entire row or column can be omitted.
    if (aspectratio > 1)
    {
        rowcount = maxrc;
        colcount = (maxrc > 2 && Children.Count < maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
    } 
    else 
    {
        rowcount = (maxrc > 2 && Children.Count < maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
        colcount = maxrc;
    }

    // Now that we have a column count, divide available horizontal, that's our cell width.
    cellwidth = (int)Math.Floor(availableSize.Width / colcount);
    // Next get a cell height, same logic of dividing available vertical by rowcount.
    cellheight = Double.IsInfinity(availableSize.Height) ? Double.PositiveInfinity : availableSize.Height / rowcount;
           
    foreach (UIElement child in Children)
    {
        child.Measure(new Size(cellwidth, cellheight));
        maxcellheight = (child.DesiredSize.Height > maxcellheight) ? child.DesiredSize.Height : maxcellheight;
    }
    return LimitUnboundedSize(availableSize);
}

MeasureOverride の実装に必要なパターンは、Panel.Children の各要素のループ処理です。The necessary pattern of a MeasureOverride implementation is the loop through each element in Panel.Children. これらの要素のそれぞれで、Measure メソッドを必ず呼び出します。Always call the Measure method on each of these elements. Measure には、型 Size のパラメーターがあります。Measure has a parameter of type Size. ここで渡しているのは、この特定の子要素が表示できるようにパネルがコミットしているサイズです。What you're passing here is the size that your panel is committing to have available for that particular child element. したがって、ループ処理を行い、Measure の呼び出しを開始する前に、各セルが使用可能なスペースの量を知る必要があります。So, before you can do the loop and start calling Measure, you need to know how much space each cell can devote. MeasureOverride メソッド自体には、availableSize 値があります。From the MeasureOverride method itself, you have the availableSize value. これは、最初に呼び出されたこの MeasureOverride のトリガーであった Measure を呼び出したときにパネルの親が使用したサイズです。That is the size that the panel's parent used when it called Measure, which was the trigger for this MeasureOverride being called in the first place. そのため、一般的なロジックは、各子要素がパネルの availableSize 全体のスペースを分割するためのスキームを作成することです。So a typical logic is to devise a scheme whereby each child element divides the space of the panel's overall availableSize. そして、サイズの各部分を各子要素の Measure に渡します。You then pass each division of size to Measure of each child element.

BoxPanel でのサイズの分割方法は、非常に簡単です。多数のボックスにスペースを分割しますが、これは、主に項目の数で制御されます。How BoxPanel divides size is fairly simple: it divides its space into a number of boxes that's largely controlled by the number of items. ボックスのサイズは、行と列の数、および使用可能なサイズに基づいて設定されます。Boxes are sized based on row and column count and the available size. 正方形の 1 行または 1 列は不要な場合があるため、破棄され、行と列の割合から見ると、パネルは正方形ではなく四角形になります。Sometimes one row or column from a square isn't needed, so it's dropped and the panel becomes a rectangle rather than square in terms of its row : column ratio. このロジックに到達する過程の詳細については、この後の「BoxPanel のシナリオ」をご覧ください。For more info about how this logic was arrived at, skip ahead to "The scenario for BoxPanel".

それでは、測定パスでは何が行われるのでしょうか。So what does the measure pass do? ここでは、Measure が呼び出された各要素に読み取り専用の DesiredSize プロパティの値が設定されます。It sets a value for the read-only DesiredSize property on each element where Measure was called. DesiredSize 値があることは、配置パスに到達した後に重要になる可能性があります。なぜなら、DesiredSize によって、配置の際や最終的な描画で可能または必要なサイズが伝えられるためです。Having a DesiredSize value is possibly important once you get to the arrange pass, because the DesiredSize communicates what the size can or should be when arranging and in the final rendering. 自分のロジックで DesiredSize を使用しない場合でも、システムでは必要になります。Even if you don't use DesiredSize in your own logic, the system still needs it.

このパネルが、availableSize の高さコンポーネントが無限である場合に使われる可能性があります。It's possible for this panel to be used when the height component of availableSize is unbounded. これに該当する場合、パネルには、分割するための既知の高さがありません。If that's true, the panel doesn't have a known height to divide. この場合、測定パスのロジックは、有限の高さがまだないことを各子要素に知らせます。In this case, the logic for the measure pass informs each child that it doesn't have a bounded height, yet. 知らせるには、Size.Height が無限である子の Measure 呼び出しに Size を渡します。It does so by passing a Size to the Measure call for children where Size.Height is infinite. これは適正な動作です。That's legal. Measure が呼び出されるときのロジックは、DesiredSize が、Measure に渡されたものの最小値、または、明示的に設定された HeightWidth などの要因からのその要素の自然なサイズの最小値として設定されていることです。When Measure is called, the logic is that the DesiredSize is set as the minimum of these: what was passed to Measure, or that element's natural size from factors such as explicitly-set Height and Width.

注意

内部ロジック StackPanel この動作があります。StackPanelに無限のディメンション値が渡されたメジャー 向きディメンション内の子に制約がないことを示す子にします。The internal logic of StackPanel also has this behavior: StackPanel passes an infinite dimension value to Measure on children, indicating that there is no constraint on children in the orientation dimension. StackPanel は、通常、動的にサイズ設定され、そのサイズ内で拡大されるスタックにすべての子が配置されます。StackPanel typically sizes itself dynamically, to accommodate all children in a stack that grows in that dimension.

ただし、パネル自体は、MeasureOverride から、無限値を持つ Size を返すことができません。返すと、レイアウト時に例外がスローされます。However, the panel itself can't return a Size with an infinite value from MeasureOverride; that throws an exception during layout. したがって、ロジックの一部は、子が要求する最大の高さを調べ、それが既にパネル自体のサイズ制約によるものでない場合は、その高さをセルの高さとして使うことです。So, part of the logic is to find out the maximum height that any child requests, and use that height as the cell height in case that isn't coming from the panel's own size constraints already. 次に示すのは、前のコードで参照されるヘルパー関数 LimitUnboundedSize です。これは、このセルの最大の高さを受け取り、これを使って、返すことができる有限の高さをパネルに与えます。また、配置パスの開始前に cellheight が有限数であることを確認します。Here's the helper function LimitUnboundedSize that was referenced in previous code, which then takes that maximum cell height and uses it to give the panel a finite height to return, as well as assuring that cellheight is a finite number before the arrange pass is initiated:

// This method is called only if one of the availableSize dimensions of measure is infinite.
// That can happen to height if the panel is close to the root of main app window.
// In this case, base the height of a cell on the max height from desired size
// and base the height of the panel on that number times the #rows.

Size LimitUnboundedSize(Size input)
{
    if (Double.IsInfinity(input.Height))
    {
        input.Height = maxcellheight * colcount;
        cellheight = maxcellheight;
    }
    return input;
}

ArrangeOverrideArrangeOverride

protected override Size ArrangeOverride(Size finalSize)
{
     int count = 1
     double x, y;
     foreach (UIElement child in Children)
     {
          x = (count - 1) % colcount * cellwidth;
          y = ((int)(count - 1) / colcount) * cellheight;
          Point anchorPoint = new Point(x, y);
          child.Arrange(new Rect(anchorPoint, child.DesiredSize));
          count++;
     }
     return finalSize;
}

ArrangeOverride の実装に必要なパターンは、Panel.Children の各要素のループ処理です。The necessary pattern of an ArrangeOverride implementation is the loop through each element in Panel.Children. これらの要素のそれぞれで、Arrange メソッドを必ず呼び出します。Always call the Arrange method on each of these elements.

MeasureOverride の場合ほど、計算が多くないことに注意してください。これが一般的です。Note how there aren't as many calculations as in MeasureOverride; that's typical. 子のサイズは、パネル自体の MeasureOverride ロジックから、または測定パスで設定された各子要素の DesiredSize 値から既にわかっています。The size of children is already known from the panel's own MeasureOverride logic, or from the DesiredSize value of each child set during the measure pass. ただし、各子要素が表示されるパネル内の場所を決定する必要がまだあります。However, we still need to decide the location within the panel where each child will appear. 一般的なパネルでは、各子要素が別の場所に描画されます。In a typical panel, each child should render at a different position. 要素の重なりを作成するパネルは、一般的なシナリオとして好ましくありません (ただし、実際に意図したシナリオである場合は、意図的な重なりがあるパネルを作成することは問題外ではありません)。A panel that creates overlapping elements isn't desirable for typical scenarios (although it's not out of the question to create panels that have purposeful overlaps, if that's really your intended scenario).

このパネルは、行と列の概念で配置されます。This panel arranges by the concept of rows and columns. 行と列の数は既に計算されています (測定値に必要であったため)。The number of rows and columns was already calculated (it was necessary for measurement). したがって、行と列の図形、および各セルの既知のサイズが、このパネルに含まれる各要素の描画位置 (anchorPoint) の定義のロジックに使用されます。So now the shape of the rows and columns plus the known sizes of each cell contribute to the logic of defining a rendering position (the anchorPoint) for each element that this panel contains. Point は、測定により既にわかっている Size と共に、Rect を作成する 2 つのコンポーネントとして使われます。That Point, along with the Size already known from measure, are used as the two components that construct a Rect. RectArrange の入力タイプです。Rect is the input type for Arrange.

パネルでは、そのコンテンツのクリップが必要な場合があります。Panels sometimes need to clip their content. クリップが必要な場合、クリップされたサイズは、DesiredSize にあるサイズです。これは、Measure ロジックがこのサイズを、Measure に渡された最小値、またはその他の自然なサイズの要因として設定するためです。If they do, the clipped size is the size that's present in DesiredSize, because the Measure logic sets it as the minimum of what was passed to Measure, or other natural size factors. したがって、Arrange では、特にクリップを確認する必要はありません。クリップは、各 Arrange 呼び出しを介して DesiredSize を渡すことに基づいて発生するだけです。So you don't typically need to specifically check for clipping during Arrange; the clipping just happens based on passing the DesiredSize through to each Arrange call.

描画位置を定義するために必要なすべての情報が他の方法でわかっている場合は、ループ処理中に常に数を数える必要はありません。You don't always need a count while going through the loop if all the info you need for defining the rendering position is known by other means. たとえば、Canvas レイアウト ロジックで、Children コレクションでの位置は重要ではありません。For example, in Canvas layout logic, the position in the Children collection doesn't matter. Canvas の各要素の位置を決定するために必要なすべての情報は、配置ロジックの一部として子の Canvas.Left 値と Canvas.Top 値を読み取ることで得られるためです。All the info needed to position each element in a Canvas is known by reading Canvas.Left and Canvas.Top values of children as part of the arrange logic. ただし、BoxPanel のロジックでは、新しい行の開始と、y 値のオフセットのタイミングを知るために、数を数えて colcount と比較する必要があります。The BoxPanel logic happens to need a count to compare to the colcount so it's known when to begin a new row and offset the y value.

入力 finalSize と、ArrangeOverride の実装から返す Size が同じであることは一般的です。It's typical that the input finalSize and the Size you return from a ArrangeOverride implementation are the same. その理由について詳しくは、「XAML カスタム パネルの概要」の「ArrangeOverride」セクションをご覧ください。For more info about why, see "ArrangeOverride" section of XAML custom panels overview.

改良: 行と列の数の制御A refinement: controlling the row vs. column count

このパネルは、コンパイルして、そのまま使用できます。You could compile and use this panel just as it is now. ただし、もう 1 つ改良を加えます。However, we'll add one more refinement. ここで示したコードで、ロジックは、縦横比で最も長い側に、追加の行または列を設定しています。In the code just shown, the logic puts the extra row or column on the side that's longest in aspect ratio. ただし、セルの形状をさらに制御するには、パネル自体の縦横比が "縦長" であっても、3×4 ではなく、4×3 のセル セットを選択する方が適切である場合があります。But for greater control over the shapes of cells, it might be desirable to choose a 4x3 set of cells instead of 3x4 even if the panel's own aspect ratio is "portrait." そのため、その動作を制御するためにパネルのユーザーが設定できる、オプションの依存関係プロパティを追加します。So we'll add an optional dependency property that the panel consumer can set to control that behavior. この依存関係プロパティ定義は、次に示すように、非常に基本的です。Here's the dependency property definition, which is very basic:

public static readonly DependencyProperty UseOppositeRCRatioProperty =
   DependencyProperty.Register("UseOppositeRCRatio", typeof(bool), typeof(BoxPanel), null);

public bool UseSquareCells
{
    get { return (bool)GetValue(UseOppositeRCRatioProperty); }
    set { SetValue(UseOppositeRCRatioProperty, value); }
}

次に、UseOppositeRCRatio の使用が測定ロジックに与える影響を説明します。And here's how using UseOppositeRCRatio impacts the measure logic. 実際に行われていることは、rowcountcolcount が、maxrc と実際の縦横比から派生しているしくみの変更だけです。このために、対応するサイズの違いが各セルにあります。Really all it's doing is changing how rowcount and colcount are derived from maxrc and the true aspect ratio, and there are corresponding size differences for each cell because of that. UseOppositeRCRatiotrue である場合は、行と列を数えるために使う前に実際の縦横比の値が逆になります。When UseOppositeRCRatio is true, it inverts the value of the true aspect ratio before using it for row and column counts.

if (UseOppositeRCRatio) { aspectratio = 1 / aspectratio;}

BoxPanel のシナリオThe scenario for BoxPanel

BoxPanel の特定のシナリオは、子項目の数がわかっており、パネルで使用できるとわかっているスペースを分割することが、スペースの分割方法の主な決定要因の 1 つであるパネルです。The particular scenario for BoxPanel is that it's a panel where one of the main determinants of how to divide space is by knowing the number of child items, and dividing the known available space for the panel. パネルの形状は本質的に四角形です。Panels are innately rectangle shapes. 多くのパネルは、その四角形のスペースをさらに四角形に分割して動作します。これは、セルに対する Grid の動作です。Many panels operate by dividing that rectangle space into further rectangles; that's what Grid does for its cells. Grid の場合は、セルのサイズが ColumnDefinitionRowDefinition の値によって設定され、これらの値が使用される正確なセルが要素によって、Grid.Row 添付プロパティと Grid.Column 添付プロパティで宣言されます。In Grid's case, the size of the cells is set by ColumnDefinition and RowDefinition values, and elements declare the exact cell they go into with Grid.Row and Grid.Column attached properties. Grid から適切なレイアウトを取得するには、通常、子要素の数を事前に知っている必要があります。これは、セルの数が十分であり、各子要素がそのセル サイズに収まるように自身の添付プロパティを設定する必要があるためです。Getting good layout from a Grid usually requires knowing the number of child elements beforehand, so that there are enough cells and each child element sets its attached properties to fit into its own cell.

では、子の数が動的な場合はどうでしょうか。But what if the number of children is dynamic? これは、確実にあり得ます。アプリ コードは、UI を更新する価値があるだけ重要であると考えられる動的ランタイム状態に対応して、コレクションに項目を追加できます。That's certainly possible; your app code can add items to collections, in response to any dynamic run-time condition you consider to be important enough to be worth updating your UI. コレクション/ビジネス オブジェクトのバッキングにデータ バインドを使っている場合は、このような更新プログラムの取得と UI の更新が自動的に処理されます。これは、多くの場合、優先して使われる手法です (「データ バインディングの詳細」をご覧ください)。If you're using data binding to backing collections/business objects, getting such updates and updating the UI is handled automatically, so that's often the preferred technique (see Data binding in depth).

ただし、アプリのすべてのシナリオがデータ バインディングに対応しているわけではありません。But not all app scenarios lend themselves to data binding. 場合によっては、新しい UI 要素を実行時に作成し、表示されるようにする必要があります。Sometimes, you need to create new UI elements at runtime and make them visible. BoxPanel は、このようなシナリオで役立ちます。BoxPanel is for this scenario. 子項目の数が変わることは、BoxPanel では問題になりません。子の数を使って計算し、既存と新規の両方の子要素がすべて、新しいレイアウトに収まるように調整するためです。A changing number of child items is no problem for BoxPanel because it's using the child count in calculations, and adjusts both the existing and new child elements into a new layout so they all fit.

BoxPanel をさらに拡張する高度なシナリオ (ここでは示されていません) では、動的な子に対応すると同時に、より強力な要因として子の DesiredSize を使って個々のセルのサイズを設定することができます。An advanced scenario for extending BoxPanel further (not shown here) could both accommodate dynamic children and use a child's DesiredSize as a stronger factor for the sizing of individual cells. そして、可変サイズの行または列、または非グリッド形状を使って、「無駄な」スペースを減らすことができます。This scenario might use varying row or column sizes or non-grid shapes so that there's less "wasted" space. これには、黄金比と最小サイズの両方の場合に、さまざまなサイズと縦横比の複数の四角形をすべて、それらを含む四角形に収めるための方法が必要です。This requires a strategy for how multiple rectangles of various sizes and aspect ratios can all fit into a containing rectangle both for aesthetics and smallest size. BoxPanel では、このような方法ではなく、スペースを分割するための単純な手法を使用しています。BoxPanel doesn't do that; it's using a simpler technique for dividing space. BoxPanel の手法は、子の数より多い、最小の正方形を決定することです。BoxPanel's technique is to determine the least square number that's greater than the child count. たとえば、9 個の項目は、3×3 の正方形に収まります。For example, 9 items would fit in a 3x3 square. 10 個の項目には、4×4 の正方形が必要です。10 items require a 4x4 square. ただし、多くの場合、項目を収めると同時に、最初の正方形の 1 行または 1 列を削除して、スペースを節約できます。However, you can often fit items while still removing one row or column of the starting square, to save space. 10 個の項目の例では、4×3 または 3×4 の長方形に収まります。In the count=10 example, that fits in a 4x3 or 3x4 rectangle.

10 項目の場合にパネルが、ちょうど収まる 5×2 を選択しないのは不思議に思われます。You might wonder why the panel wouldn't instead choose 5x2 for 10 items, because that fits the item number neatly. ただし、実際には、向きがはっきりした縦横比の四角形としてパネルがサイズ設定されることは稀です。However, in practice, panels are sized as rectangles that seldom have a strongly oriented aspect ratio. 最小正方形の手法は、サイズ設定ロジックを偏らせて、一般的なレイアウトの図形を適切に処理し、セルの形状が極端な縦横比になるサイズ設定を防ぐための 1 つの方法です。The least-squares technique is a way to bias the sizing logic to work well with typical layout shapes and not encourage sizing where the cell shapes get odd aspect ratios.

リファレンスReference

概念Concepts