BoxPanel, 예제 사용자 지정 패널BoxPanel, an example custom panel

ArrangeOverrideMeasureOverride 메서드를 구현하고 Children 속성을 사용하는 사용자 지정 Panel 클래스에 대한 코드를 작성하는 방법을 알아봅니다.Learn to write code for a custom Panel class, implementing ArrangeOverride and MeasureOverride methods, and using the Children property.

중요 API: Panel, ArrangeOverride,MeasureOverrideImportant 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. ArrangeOverrideMeasureOverride 메서드를 재정의하고 자식 요소를 측정 및 정렬하는 논리를 제공하여 패널에 대한 동작을 제공합니다.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, ArrangeOverrideMeasureOverride 메서드에서 시작하는 경우 시작 동작이 없습니다.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.

클래스 템플릿 파일은 구체적으로 Windows 앱용으로 지정되지 않기 때문에 많은 using 문으로 시작하지 않습니다.The template file for a class doesn't start with many using statements because it's not specifically for Windows 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
{
}

클래스 수준에서 여러 논리 함수가 공유하지만 공용 API로 노출할 필요가 없는 intdouble 값을 몇 개 정의합니다.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. 예제에서는 maxrc, rowcount, colcount, cellwidth, cellheight, maxcellheight, aspectratio로 이름이 지정됩니다.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;
}

이제부터 멤버 정의(멤버 재정의 또는 종속성 속성 등의 지원 항목)를 한 번에 하나씩 보여드리겠습니다.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. 때때로 정사각형의 행 또는 열 하나는 필요하지 않으므로 삭제되며, 행 : 열 비율 측면에서 패널이 정사각형이 아니라 직사각형이 됩니다.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가 호출된 경우의 논리는 DesiredSizeMeasure에 전달된 값 또는 명시적으로 설정된 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은 자식의 Measure에 무한대 차원 값을 전달하여 방향 차원에 자식에 대한 제약 조건이 없음을 나타냅니다.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와 측정값에서 이미 알려진 SizeRect를 구성하는 두 개의 구성 요소로 사용됩니다.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.LeftCanvas.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.

일반적으로 입력 finalSizeArrangeOverride 구현에서 반환하는 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. 그러나 구체화를 하나 더 추가하겠습니다.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. 그러나 셀 모양에 대한 제어를 강화하기 위해 패널 자체의 가로 세로 비율이 "세로"인 경우에도 3x4 대신 4x3 셀 집합을 선택하는 것이 좋습니다.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. 실제로는 rowcountcolcountmaxrc에서 파생되는 방법과 실제 가로 세로 비율만 변경하며, 이 때문에 각 셀에 해당 크기 차이가 있습니다.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에 대한 특정 시나리오는 공간을 나누는 방법의 주요 결정자 중 하나가 자식 항목 수를 알고 패널에 사용 가능한 알려진 공간을 나누는 것인 패널입니다.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.RowGrid.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개 항목은 3x3 정사각형에 들어갑니다.For example, 9 items would fit in a 3x3 square. 10 개 항목에는 4x4 정사각형이 필요합니다.10 items require a 4x4 square. 그러나 공간을 절약하기 위해 시작 정사각형의 행이나 열을 하나 제거하고 항목을 맞출 수도 있습니다.However, you can often fit items while still removing one row or column of the starting square, to save space. 개수=10 예제에서는 4x3 또는 3x4 직사각형에 들어갑니다.In the count=10 example, that fits in a 4x3 or 3x4 rectangle.

패널에서 10개 항목에 대해 5x2를 선택하지 않는 이유가 궁금할 수도 있습니다. 이렇게 하면 항목 수에 정확히 맞기 때문입니다.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. 최소 정사각형 기법은 일반적인 레이아웃 모양에서 제대로 작동하도록 크기 조정 논리를 보정하고 셀 모양의 가로 세로 비율이 특이한 크기 조정을 권장하지 않는 방법입니다.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