Общие сведения о панелях

Обновлен: Ноябрь 2007

Элементы Panel являются компонентами, которые управляют отображением элементов — их размер и измерения, их положение и расположение их дочернего содержимого. Windows Presentation Foundation (WPF) предоставляет ряд стандартных элементов Panel элементов, а также возможность создания пользовательских элементов Panel.

В этом разделе содержатся следующие подразделы.

  • Класс Panel

  • Общие члены элемента Panel

  • Производные элементы Panel

  • Панели пользовательского интерфейса

  • Вложенные элементы Panel

  • Пользовательские элементы Panel

  • Поддержка локализации/глобализации

  • См. также

Класс Panel

Panel является базовым классом для всех элементов, поддерживающих макет приложения Windows Presentation Foundation (WPF). Производные элементы Panel используются для размещения и упорядочивания UIElements в Язык XAML (Extensible Application Markup Language) и коде.

WPF включает полный набор реализаций производной панели, позволяющий множество сложных макетов. Эти производные классы предоставляют свойства и методы, допускающие наиболее стандартные сценарии пользовательский интерфейс. Разработчики, которым не удается найти дочернее упорядочение поведение, удовлетворяющее их требованиям, могут создать новый макет, переопределив методы ArrangeOverride и MeasureOverride. Дополнительные сведения о поведении пользовательского макета содержатся в разделе Пользовательские элементы Panel.

XAMLPad

XAMLPad — это средство, которое облегчает разработку пользовательских интерфейсов, основанных на Язык XAML (Extensible Application Markup Language), путем разбора разметки в режиме реального времени и отображения результатов в окне. Данное средство очень полезно при проведении экспериментов с макетом. Может потребоваться приложение, открытое для просмотра результатов различных примеров Язык XAML (Extensible Application Markup Language), содержащихся в этом разделе. Дополнительные сведения см. в разделе XAMLPad.

Общие члены Panel

Все элементы Panel поддерживают базовые изменения размеров и положения свойств, определенные в FrameworkElement, в том числе Height, Width, HorizontalAlignment, VerticalAlignment, Margin и LayoutTransform. Дополнительные сведения о позиционировании свойств, определенных в FrameworkElement, содержатся в разделе Общие сведения о свойствах Alignment, Margin, Padding.

Panel предоставляет дополнительные свойства, которые очень важны в понимании и использовании макета. Свойство Background используется для заполнения области между границами производного элемента панели с Brush. Children представляет дочернюю коллекцию UIElements, из которых состоит Panel. InternalChildren представляет содержимое коллекции Children плюс элементы, созданные связыванием данных. Оба состоят из UIElementCollection дочерних элементов, расположенных внутри родительского элемента Panel.

Панель также предоставляет свойство ZIndex, которое может быть использовано для достижения многоуровневого порядка в производном Panel. Члены коллекции Children панели с более высоким значением ZIndex отображаются перед членами с более низким значением ZIndex. Это полезно для таких панелей, как Canvas и Grid, позволяющих потомкам совместно использовать одно и то же пространство координат.

Panel также определяет метод OnRender, который может использоваться для переопределения поведения представления Panel по умолчанию.

Вложенные свойства зависимостей

Производные элементы панели широко используют вложенные свойства. Вложенное свойство представляет собой особую форму свойства зависимости, у которого нет обычной «оболочки» свойства среда CLR (common language runtime). Вложенные свойства имеют специализированный синтаксис в Язык XAML (Extensible Application Markup Language), который можно увидеть в следующих нескольких примерах.

Одним из предназначений вложенного свойства является разрешение дочерним элементам хранения уникальных значений свойства, фактически определенного родительским элементом. Приложение этой функциональности содержит дочерние элементы, информирующие родителей, как они должны быть представлены в пользовательский интерфейс, что очень полезно для макета приложения. Дополнительные сведения см. в разделе Общие сведения о вложенных свойствах зависимостей.

Производные элементы Panel

Многие объекты являются производными от Panel, но не все из них предназначены для использования в качестве поставщиков корневого макета. Существует шесть определенных классов панелей (Canvas, DockPanelGrid, StackPanel, VirtualizingStackPanel и WrapPanel), которые предназначены специально для создания приложений Пользовательский интерфейс.

Каждый элемент панели инкапсулирует свои собственные специальные функциональные возможности, как показано в следующей таблице.

Имя элемента

Панель пользовательского интерфейса?

Описание

Canvas

Да

Определяет область, внутри которой можно явным образом разместить дочерние элементы при помощи относительных координат в области Canvas.

DockPanel

Да

Определяет область, внутри которой можно упорядочить дочерние элементы по горизонтали или по вертикали друг относительно друга.

Grid

Да

Определяет гибкую область сетки, состоящей из строк и столбцов. Дочерние элементы Grid могут быть расположены с помощью свойства Margin.

StackPanel

Да

Располагает дочерние элементы в одну строку, которая может быть ориентирована горизонтально или вертикально.

TabPanel

Нет

Обрабатывает макет кнопок вкладки в TabControl.

ToolBarOverflowPanel

Нет

Выравнивает содержимое элемента управления ToolBar.

UniformGrid

Нет

UniformGrid используется для упорядочивания дочерних элементов в сетке со ячейками одинакового размера.

VirtualizingPanel

Нет

Предоставляет базовый класс для панелей, который может «виртуализировать» их дочернюю коллекцию.

VirtualizingStackPanel

Да

Упорядочивает и виртуализирует содержимое в отдельной строке, ориентированной горизонтально или вертикально.

WrapPanel

Да

WrapPanel размещает дочерние элементы в последовательности слева направо, перенося содержимое на следующую строку на границе содержащего поля. Дельнейшее упорядочивание происходит последовательно сверху вниз или справа налево в зависимости от значения свойства Orientation.

Панели пользовательского интерфейса

Существуют шесть классов панелей, доступных в WPF которые оптимизированы для поддержки сценариев Пользовательский интерфейсCanvas, DockPanel, Grid, StackPanel, VirtualizingStackPanel, и WrapPanel: Эти элементы панели являются простыми в использовании, универсальными и достаточно расширяемыми для большинства приложений.

Каждый производный элемент Panel рассматривает ограничения размеров по-разному. Понимание того, как Panel обрабатывает ограничения в горизонтальном или вертикальном направлении, может сделать макет более прогнозируемым.

Имя панели

Размерность x

Размерность y

Canvas

Ограничения содержимого

Ограничения содержимого

DockPanel

Ограниченный.

Ограниченный.

StackPanel (вертикальная ориентация)

Ограниченный.

Ограничения содержимого

StackPanel (горизонтальная ориентация)

Ограничения содержимого

Ограниченный.

Grid

Ограниченный.

Ограниченные, кроме случаев, когда Auto применяется к строкам и столбцам

WrapPanel

Ограничения содержимого

Ограничения содержимого

Более подробное описание и примеры использования каждого из этих элементов можно найти ниже.

Canvas

Элемент Canvas позволяет размещение содержимого в соответствие с абсолютными x и y координатами. Элементы могут быть нарисованы в уникальном месте; или, если элементы занимают те же координаты, порядок, в котором они появляются в разметке, определяет порядок, в котором элементы отображаются.

Canvas предоставляет самый гибкий макет поддержки любых Panel. Свойства высоты и ширины используются для определения области canvas, и элементам внутри назначаются абсолютные координаты относительно области родительского Canvas. Четыре вложенных свойства, Left, Top, Right и Bottom, допускают точное управление расположением объекта в Canvas, позволяемому разработчику поместить и расположить элементы на экране.

ClipToBounds в пределах Canvas

Canvas может поместить дочерние элементы в любое положение на экране, даже с координатами, находящимися за пределами определенных Height и Width. Кроме того, на Canvas не влияет размер его дочерних элементов. В результате имеется возможность для дочернего элемента перерисовывать другие элементы за пределами ограничивающего прямоугольника родительского Canvas. Поведением Canvas по умолчанию является разрешение прорисовки потомков вне границ родительского Canvas. Если такое поведение нежелательно, значение свойства ClipToBounds может быть установлено в true. В результате, Canvas обрезается до собственного размера. Canvas является единственным элементом макета, который позволяет прорисовку потомков вне его границ.

Такое поведение графически показано в Пример сравнения свойств ширины.

Определение и использование Canvas

Canvas может быть легко создан с помощью Язык XAML (Extensible Application Markup Language) или в коде. В следующем примере демонстрируется использование Canvas для абсолютного расположения содержимого. Этот код формирует три 100-точечных квадрата. Первый квадрат красный и его положение слева вверху (x, y) указано как (0, 0). Второй квадрат зеленый, и его положение слева вверху имеет координаты (100, 100), только ниже и правее первого квадрата. Третий квадрат — синий, и координаты его левого верхнего угла равны (50, 50), таким образом, он перекрывает правый нижний квадрант первого квадрата и левый верхний квадрант второго. Так как третий накладывается последним, он расположен поверх других двух квадратов — следовательно, перекрывающиеся фрагменты принимают цвет третьего квадрата.

WindowTitle = "Canvas Sample"
'Create a Canvas as the root Panel
Dim myParentCanvas As New Canvas()
myParentCanvas.Width = 400
myParentCanvas.Height = 400

' Define child Canvas elements
Dim myCanvas1 As New Canvas()
myCanvas1.Background = Brushes.Red
myCanvas1.Height = 100
myCanvas1.Width = 100
Canvas.SetTop(myCanvas1, 0)
Canvas.SetLeft(myCanvas1, 0)

Dim myCanvas2 As New Canvas()
myCanvas2.Background = Brushes.Green
myCanvas2.Height = 100
myCanvas2.Width = 100
Canvas.SetTop(myCanvas2, 100)
Canvas.SetLeft(myCanvas2, 100)

Dim myCanvas3 As New Canvas()
myCanvas3.Background = Brushes.Blue
myCanvas3.Height = 100
myCanvas3.Width = 100
Canvas.SetTop(myCanvas3, 50)
Canvas.SetLeft(myCanvas3, 50)

' Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1)
myParentCanvas.Children.Add(myCanvas2)
myParentCanvas.Children.Add(myCanvas3)

' Add the parent Canvas as the Content of the Window Object
Me.Content = myParentCanvas
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "Canvas Sample";

// Create the Canvas
myParentCanvas = new Canvas();
myParentCanvas.Width = 400;
myParentCanvas.Height = 400;

// Define child Canvas elements
myCanvas1 = new Canvas();
myCanvas1.Background = Brushes.Red;
myCanvas1.Height = 100;
myCanvas1.Width = 100;
Canvas.SetTop(myCanvas1, 0);
Canvas.SetLeft(myCanvas1, 0);

myCanvas2 = new Canvas();
myCanvas2.Background = Brushes.Green;
myCanvas2.Height = 100;
myCanvas2.Width = 100;
Canvas.SetTop(myCanvas2, 100);
Canvas.SetLeft(myCanvas2, 100);

myCanvas3 = new Canvas();
myCanvas3.Background = Brushes.Blue;
myCanvas3.Height = 100;
myCanvas3.Width = 100;
Canvas.SetTop(myCanvas3, 50);
Canvas.SetLeft(myCanvas3, 50);

// Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1);
myParentCanvas.Children.Add(myCanvas2);
myParentCanvas.Children.Add(myCanvas3);

// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myParentCanvas;
mainWindow.Show ();

<Page WindowTitle="Canvas Sample" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Canvas Height="400" Width="400">
    <Canvas Height="100" Width="100" Top="0" Left="0" Background="Red"/>
    <Canvas Height="100" Width="100" Top="100" Left="100" Background="Green"/>
    <Canvas Height="100" Width="100" Top="50" Left="50" Background="Blue"/>
  </Canvas>
</Page>

Скомпилированное приложение возвращает новый Пользовательский интерфейс, выглядящий следующим образом.

Обычный элемент холста.

DockPanel

Элемент DockPanel использует вложенное свойство Dock для расположения содержимого по краям контейнера. Когда Dock имеет значение Top или Bottom, она располагает дочерние элементы выше или ниже друг друга. Когда Dock установлена в значение Left или Right, она размещает дочерние элементы слева или справа относительно друг друга. Свойство LastChildFill определяет положение окончательного элемента, добавляемого в качестве дочернего элемента DockPanel.

Можно использовать DockPanel для размещения группы связанных элементов управления, например, набора кнопок. Кроме того, можно использовать его для создания в «разделенного» Пользовательский интерфейс, аналогично, найденному в Microsoft Outlook.

Изменение размеров в зависимости от содержимого

Если свойства Height и Width элемента управления DockPanel не указаны, она подстраивается по размеру к содержимому. Размер может увеличиваться или уменьшаться, чтобы вместить дочерние элементы. Однако, если заданы эти свойства и больше нет свободного места для следующего указанного дочернего элемента, DockPanel не отображает этот дочерний элемент или последующие дочерние элементы и не принимает размер последующих дочерних элементов.

LastChildFill

По умолчанию, последний дочерний элемент DockPanel заполняет оставшееся незанятое пространство. Если такое поведение не требуется, присвойте свойству LastChildFill значение false.

Определение и использование DockPanel

В следующем примере демонстрируется разделение пространства с помощью DockPanel. Пять элементов Border добавляются в качестве дочерних элементов родительской DockPanel. Каждый использует свое свойство размещения DockPanel для разделения пространства. Последний элемент «заполняет» оставшееся, незанятое пространство.

WindowTitle = "DockPanel Sample"
'Create a DockPanel as the root Panel
Dim myDockPanel As New DockPanel()
myDockPanel.LastChildFill = True

' Define the child content
Dim myBorder1 As New Border()
myBorder1.Height = 25
myBorder1.Background = Brushes.SkyBlue
myBorder1.BorderBrush = Brushes.Black
myBorder1.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder1, Dock.Top)
Dim myTextBlock1 As New TextBlock()
myTextBlock1.Foreground = Brushes.Black
myTextBlock1.Text = "Dock = Top"
myBorder1.Child = myTextBlock1

Dim myBorder2 As New Border()
myBorder2.Height = 25
myBorder2.Background = Brushes.SkyBlue
myBorder2.BorderBrush = Brushes.Black
myBorder2.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder2, Dock.Top)
Dim myTextBlock2 As New TextBlock()
myTextBlock2.Foreground = Brushes.Black
myTextBlock2.Text = "Dock = Top"
myBorder2.Child = myTextBlock2

Dim myBorder3 As New Border()
myBorder3.Height = 25
myBorder3.Background = Brushes.LemonChiffon
myBorder3.BorderBrush = Brushes.Black
myBorder3.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder3, Dock.Bottom)
Dim myTextBlock3 As New TextBlock()
myTextBlock3.Foreground = Brushes.Black
myTextBlock3.Text = "Dock = Bottom"
myBorder3.Child = myTextBlock3

Dim myBorder4 As New Border()
myBorder4.Width = 200
myBorder4.Background = Brushes.PaleGreen
myBorder4.BorderBrush = Brushes.Black
myBorder4.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder4, Dock.Left)
Dim myTextBlock4 As New TextBlock()
myTextBlock4.Foreground = Brushes.Black
myTextBlock4.Text = "Dock = Left"
myBorder4.Child = myTextBlock4

Dim myBorder5 As New Border()
myBorder5.Background = Brushes.White
myBorder5.BorderBrush = Brushes.Black
myBorder5.BorderThickness = New Thickness(1)
Dim myTextBlock5 As New TextBlock()
myTextBlock5.Foreground = Brushes.Black
myTextBlock5.Text = "This content will Fill the remaining space"
myBorder5.Child = myTextBlock5

' Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1)
myDockPanel.Children.Add(myBorder2)
myDockPanel.Children.Add(myBorder3)
myDockPanel.Children.Add(myBorder4)
myDockPanel.Children.Add(myBorder5)
Me.Content = myDockPanel
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "DockPanel Sample";

// Create the DockPanel
DockPanel myDockPanel = new DockPanel();
myDockPanel.LastChildFill = true;

// Define the child content
Border myBorder1 = new Border();
myBorder1.Height = 25;
myBorder1.Background = Brushes.SkyBlue;
myBorder1.BorderBrush = Brushes.Black;
myBorder1.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder1, Dock.Top);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.Foreground = Brushes.Black;
myTextBlock1.Text = "Dock = Top";
myBorder1.Child = myTextBlock1;

Border myBorder2 = new Border();
myBorder2.Height = 25;
myBorder2.Background = Brushes.SkyBlue;
myBorder2.BorderBrush = Brushes.Black;
myBorder2.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder2, Dock.Top);
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Foreground = Brushes.Black;
myTextBlock2.Text = "Dock = Top";
myBorder2.Child = myTextBlock2;

Border myBorder3 = new Border();
myBorder3.Height = 25;
myBorder3.Background = Brushes.LemonChiffon;
myBorder3.BorderBrush = Brushes.Black;
myBorder3.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder3, Dock.Bottom);
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Foreground = Brushes.Black;
myTextBlock3.Text = "Dock = Bottom";
myBorder3.Child = myTextBlock3;

Border myBorder4 = new Border();
myBorder4.Width = 200;
myBorder4.Background = Brushes.PaleGreen;
myBorder4.BorderBrush = Brushes.Black;
myBorder4.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder4, Dock.Left);
TextBlock myTextBlock4 = new TextBlock();
myTextBlock4.Foreground = Brushes.Black;
myTextBlock4.Text = "Dock = Left";
myBorder4.Child = myTextBlock4;

Border myBorder5 = new Border();
myBorder5.Background = Brushes.White;
myBorder5.BorderBrush = Brushes.Black;
myBorder5.BorderThickness = new Thickness(1);
TextBlock myTextBlock5 = new TextBlock();
myTextBlock5.Foreground = Brushes.Black;
myTextBlock5.Text = "This content will Fill the remaining space";
myBorder5.Child = myTextBlock5;


// Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1);
myDockPanel.Children.Add(myBorder2);
myDockPanel.Children.Add(myBorder3);
myDockPanel.Children.Add(myBorder4);
myDockPanel.Children.Add(myBorder5);

// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myDockPanel;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="DockPanel Sample">
  <DockPanel LastChildFill="True">
    <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
      <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
    </Border>
    <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
      <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
    </Border>
    <Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
      <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock>
    </Border>
    <Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
      <TextBlock Foreground="Black">Dock = "Left"</TextBlock>
    </Border>
    <Border Background="White" BorderBrush="Black" BorderThickness="1">
      <TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock>
    </Border>
  </DockPanel>
</Page>

Скомпилированное приложение возвращает новый Пользовательский интерфейс, выглядящий следующим образом.

Обычный сценарий DockPanel.

Сетка

Элемент Grid объединяет возможности абсолютного позиционирования и управления табличными данными. Grid позволяет легко расположить и стилизовать элементы. Grid позволяет определить гибкую группировку строк и столбцов и даже предоставляет механизм для обмена данными между несколькими элементами Grid.

Чем сетка отличается от таблицы?

Table и Grid совместно используют некоторые общие функциональные возможности, но каждый наилучшим образом подходит для различных сценариев. Table предназначена для использования внутри содержимого потока (см. раздел Общие сведения о документе нефиксированного формата для получения дополнительных сведений о содержимом потока). Сетку лучше всего использовать внутри форм (главным образом, где-либо вне содержимого потока). Внутри FlowDocument элемент Table поддерживает такие возможности, как разбиение на страницы, обратный порядок столбцов и выделение содержимого, в то время как Grid их не поддерживает. С другой стороны элемент Grid лучше всего использовать вне FlowDocument по многим причинам, включая то, что Grid добавляет элементы на основе индексов строки и столбца, в то время как Table ― нет. Элемент Grid позволяет послойно размещать дочернее содержимое, что дает возможность разместить в одной «ячейке» несколько элементов. Table не поддерживает послойное размещение. Дочерние элементы Grid могут быть абсолютно расположенными относительно границы « ячейки ».Table не поддерживает этой возможности. Наконец, Grid является легковеснее, чем Table.

Изменение размера столбцов и строк

Столбцы и строки, определенные в Grid, могут воспользоваться преимуществами изменения размера Star, чтобы пропорционально распределить оставшееся пространство. При выборе Star в качестве высота или ширина строки или столбца, столбец или строка получает взвешенные пропорции оставшегося доступного пространства. В этом заключается отличие от Auto, при котором распределение пространства будет равномерным, в зависимости от содержимого столбца или строки. Данный параметр измеряется как * или 2* при использовании Язык XAML (Extensible Application Markup Language). В первом случае строка или столбец получают однократное доступное пространство, во втором случае — двукратное и т.д. Дополнительные сведения об изменения размеров звезды содержатся в примере Пример использования Star для изменения размеров. При объединении этой методики пропорционального распределения пространства с установками HorizontalAlignment и VerticalAlignment свойства Stretch появляется возможность разделения пространства макета в процентах от пространства экрана. Элемент управления Grid является единственной панелью макета, которая может распределять пространство таким образом.

Определение и использование сетки

В следующем примере демонстрируется построение Пользовательский интерфейс, аналогичного обнаруженному в диалоговом окне Run, доступном через меню Windows Пуск.

'Create a Grid as the root Panel element.
Dim myGrid As New Grid()
myGrid.Height = 165
myGrid.Width = 425
myGrid.Background = Brushes.Gainsboro
myGrid.ShowGridLines = True
myGrid.HorizontalAlignment = Windows.HorizontalAlignment.Left
myGrid.VerticalAlignment = Windows.VerticalAlignment.Top

' Define and Add the Rows and Columns.
Dim colDef1 As New ColumnDefinition
colDef1.Width = New GridLength(1, GridUnitType.Auto)
Dim colDef2 As New ColumnDefinition
colDef2.Width = New GridLength(1, GridUnitType.Star)
Dim colDef3 As New ColumnDefinition
colDef3.Width = New GridLength(1, GridUnitType.Star)
Dim colDef4 As New ColumnDefinition
colDef4.Width = New GridLength(1, GridUnitType.Star)
Dim colDef5 As New ColumnDefinition
colDef5.Width = New GridLength(1, GridUnitType.Star)
myGrid.ColumnDefinitions.Add(colDef1)
myGrid.ColumnDefinitions.Add(colDef2)
myGrid.ColumnDefinitions.Add(colDef3)
myGrid.ColumnDefinitions.Add(colDef4)
myGrid.ColumnDefinitions.Add(colDef5)

Dim rowDef1 As New RowDefinition
rowDef1.Height = New GridLength(1, GridUnitType.Auto)
Dim rowDef2 As New RowDefinition
rowDef2.Height = New GridLength(1, GridUnitType.Auto)
Dim rowDef3 As New Controls.RowDefinition
rowDef3.Height = New GridLength(1, GridUnitType.Star)
Dim rowDef4 As New RowDefinition
rowDef4.Height = New GridLength(1, GridUnitType.Auto)
myGrid.RowDefinitions.Add(rowDef1)
myGrid.RowDefinitions.Add(rowDef2)
myGrid.RowDefinitions.Add(rowDef3)
myGrid.RowDefinitions.Add(rowDef4)

' Add the Image.
Dim img1 As New Image
img1.Source = New System.Windows.Media.Imaging.BitmapImage(New Uri("runicon.png", UriKind.Relative))
Grid.SetRow(img1, 0)
Grid.SetColumn(img1, 0)
myGrid.Children.Add(img1)

' Add the main application dialog.
Dim txt1 As New TextBlock
txt1.Text = "Type the name of a program, document, or Internet resource, and Windows will open it for you."
txt1.TextWrapping = TextWrapping.Wrap
Grid.SetColumnSpan(txt1, 4)
Grid.SetRow(txt1, 0)
Grid.SetColumn(txt1, 1)
myGrid.Children.Add(txt1)

' Add the second TextBlock Cell to the Grid.
Dim txt2 As New TextBlock
txt2.Text = "Open:"
Grid.SetRow(txt2, 1)
Grid.SetColumn(txt2, 0)
myGrid.Children.Add(txt2)

' Add the TextBox control.
Dim tb1 As New TextBox
Grid.SetRow(tb1, 1)
Grid.SetColumn(tb1, 1)
Grid.SetColumnSpan(tb1, 5)
myGrid.Children.Add(tb1)

' Add the Button controls.
Dim button1 As New Button
Dim button2 As New Button
Dim button3 As New Button
button1.Content = "OK"
button1.Margin = New Thickness(10, 0, 10, 15)
button2.Content = "Cancel"
button2.Margin = New Thickness(10, 0, 10, 15)
button3.Content = "Browse ..."
button3.Margin = New Thickness(10, 0, 10, 15)

Grid.SetRow(button1, 3)
Grid.SetColumn(button1, 2)
Grid.SetRow(button2, 3)
Grid.SetColumn(button2, 3)
Grid.SetRow(button3, 3)
Grid.SetColumn(button3, 4)
myGrid.Children.Add(button1)
myGrid.Children.Add(button2)
myGrid.Children.Add(button3)

Me.Content = myGrid
// Create the Grid.
grid1 = new Grid ();
grid1.Background = Brushes.Gainsboro;
grid1.HorizontalAlignment = HorizontalAlignment.Left;
grid1.VerticalAlignment = VerticalAlignment.Top;
grid1.ShowGridLines = true;
grid1.Width = 425;
grid1.Height = 165;

// Define the Columns.
colDef1 = new ColumnDefinition();
colDef1.Width = new GridLength(1, GridUnitType.Auto);
colDef2 = new ColumnDefinition();
colDef2.Width = new GridLength(1, GridUnitType.Star);
colDef3 = new ColumnDefinition();
colDef3.Width = new GridLength(1, GridUnitType.Star);
colDef4 = new ColumnDefinition();
colDef4.Width = new GridLength(1, GridUnitType.Star);
colDef5 = new ColumnDefinition();
colDef5.Width = new GridLength(1, GridUnitType.Star);
grid1.ColumnDefinitions.Add(colDef1);
grid1.ColumnDefinitions.Add(colDef2);
grid1.ColumnDefinitions.Add(colDef3);
grid1.ColumnDefinitions.Add(colDef4);
grid1.ColumnDefinitions.Add(colDef5);

// Define the Rows.
rowDef1 = new RowDefinition();
rowDef1.Height = new GridLength(1, GridUnitType.Auto);
rowDef2 = new RowDefinition();
rowDef2.Height = new GridLength(1, GridUnitType.Auto);
rowDef3 = new RowDefinition();
rowDef3.Height = new GridLength(1, GridUnitType.Star);
rowDef4 = new RowDefinition();
rowDef4.Height = new GridLength(1, GridUnitType.Auto);
grid1.RowDefinitions.Add(rowDef1);
grid1.RowDefinitions.Add(rowDef2);
grid1.RowDefinitions.Add(rowDef3);
grid1.RowDefinitions.Add(rowDef4);

// Add the Image.
img1 = new Image();
img1.Source = new System.Windows.Media.Imaging.BitmapImage(new Uri("runicon.png", UriKind.Relative));
Grid.SetRow(img1, 0);
Grid.SetColumn(img1, 0);

// Add the main application dialog.
txt1 = new TextBlock();
txt1.Text = "Type the name of a program, folder, document, or Internet resource, and Windows will open it for you.";
txt1.TextWrapping = TextWrapping.Wrap;
Grid.SetColumnSpan(txt1, 4);
Grid.SetRow(txt1, 0);
Grid.SetColumn(txt1, 1);

// Add the second text cell to the Grid.
txt2 = new TextBlock();
txt2.Text = "Open:";
Grid.SetRow(txt2, 1);
Grid.SetColumn(txt2, 0);

// Add the TextBox control.
tb1 = new TextBox();
Grid.SetRow(tb1, 1);
Grid.SetColumn(tb1, 1);
Grid.SetColumnSpan(tb1, 5);

// Add the buttons.
button1 = new Button();
button2 = new Button();
button3 = new Button();
button1.Content = "OK";
button2.Content = "Cancel";
button3.Content = "Browse ...";
Grid.SetRow(button1, 3);
Grid.SetColumn(button1, 2);
button1.Margin = new Thickness(10, 0, 10, 15);
button2.Margin = new Thickness(10, 0, 10, 15);
button3.Margin = new Thickness(10, 0, 10, 15);
Grid.SetRow(button2, 3);
Grid.SetColumn(button2, 3);
Grid.SetRow(button3, 3);
Grid.SetColumn(button3, 4);

grid1.Children.Add(img1);
grid1.Children.Add(txt1);
grid1.Children.Add(txt2);
grid1.Children.Add(tb1);
grid1.Children.Add(button1);
grid1.Children.Add(button2);
grid1.Children.Add(button3);

mainWindow.Content = grid1;
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      WindowTitle="Grid Run Dialog Sample" 
      WindowWidth="425" 
      WindowHeight="225">
  <Grid Background="#DCDCDC"
        Width="425"
        Height="165"
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        ShowGridLines="True">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Image Grid.Column="0" Grid.Row="0" Source="RunIcon.png" />
    <TextBlock Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="0" TextWrapping="Wrap">
      Type the name of a program, folder, document, or
      Internet resource, and Windows will open it for you.
    </TextBlock>
    <TextBlock Grid.Column="0" Grid.Row="1">Open:</TextBlock>
    <TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="5" />
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="2">OK</Button>
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="3">Cancel</Button>
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="4">Browse ...</Button>
  </Grid>
</Page>

Скомпилированное приложение возвращает новый Пользовательский интерфейс, выглядящий следующим образом.

Обычный элемент сетки.

StackPanel

StackPanel позволяет «выстраивать» элементы в определенном направлении. По умолчанию, направление стека является вертикальным. Свойство Orientation может использоваться для потока содержимого элемента управления.

StackPanel и DockPanel

Несмотря на то, что DockPanel может также содержать дочерние элементы, DockPanel и StackPanel не дают аналогичных результатов в некоторых случаях использования. Например, последовательность дочерних элементов может повлиять на их размер в DockPanel, но не в StackPanel. Это происходит потому, что StackPanel имеет размер, зависящий от направлении стека на PositiveInfinity, тогда как DockPanel обладает только доступным размером.

Следующий пример демонстрирует ключевые различия.

'Add root Grid
Dim myGrid As New Grid
myGrid.Width = 175
myGrid.Height = 150
Dim myRowDef1 As New RowDefinition
Dim myRowDef2 As New RowDefinition
myGrid.RowDefinitions.Add(myRowDef1)
myGrid.RowDefinitions.Add(myRowDef2)

'Define the DockPanel
Dim myDockPanel As New DockPanel
Grid.SetRow(myDockPanel, 0)

'Define an Image and Source.
Dim myImage As New Image
Dim bi As New BitmapImage
bi.BeginInit()
bi.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi.EndInit()
myImage.Source = bi

Dim myImage2 As New Image
Dim bi2 As New BitmapImage
bi2.BeginInit()
bi2.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi2.EndInit()
myImage2.Source = bi2

Dim myImage3 As New Image
Dim bi3 As New BitmapImage
bi3.BeginInit()
bi3.UriSource = New Uri("smiley_stackpanel.PNG", UriKind.Relative)
bi3.EndInit()
myImage3.Stretch = Stretch.Fill
myImage3.Source = bi3

'Add the images to the parent DockPanel.
myDockPanel.Children.Add(myImage)
myDockPanel.Children.Add(myImage2)
myDockPanel.Children.Add(myImage3)

'Define a StackPanel.
Dim myStackPanel As New StackPanel
myStackPanel.Orientation = Orientation.Horizontal
Grid.SetRow(myStackPanel, 1)

Dim myImage4 As New Image
Dim bi4 As New BitmapImage
bi4.BeginInit()
bi4.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi4.EndInit()
myImage4.Source = bi4

Dim myImage5 As New Image
Dim bi5 As New BitmapImage
bi5.BeginInit()
bi5.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi5.EndInit()
myImage5.Source = bi5

Dim myImage6 As New Image
Dim bi6 As New BitmapImage
bi6.BeginInit()
bi6.UriSource = New Uri("smiley_stackpanel.PNG", UriKind.Relative)
bi6.EndInit()
myImage6.Stretch = Stretch.Fill
myImage6.Source = bi6

'Add the images to the parent StackPanel.
myStackPanel.Children.Add(myImage4)
myStackPanel.Children.Add(myImage5)
myStackPanel.Children.Add(myImage6)

'Add the layout panels as children of the Grid
myGrid.Children.Add(myDockPanel)
myGrid.Children.Add(myStackPanel)

// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "StackPanel vs. DockPanel";

// Add root Grid
myGrid = new Grid();
myGrid.Width = 175;
myGrid.Height = 150;
RowDefinition myRowDef1 = new RowDefinition();
RowDefinition myRowDef2 = new RowDefinition();
myGrid.RowDefinitions.Add(myRowDef1);
myGrid.RowDefinitions.Add(myRowDef2);

// Define the DockPanel
myDockPanel = new DockPanel();
Grid.SetRow(myDockPanel, 0);

//Define an Image and Source
Image myImage = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi.EndInit();
myImage.Source = bi;

Image myImage2 = new Image();
BitmapImage bi2 = new BitmapImage();
bi2.BeginInit();
bi2.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi2.EndInit();
myImage2.Source = bi2;

Image myImage3 = new Image();
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
bi3.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi3.EndInit();
myImage3.Stretch = Stretch.Fill;
myImage3.Source = bi3;

// Add the images to the parent DockPanel
myDockPanel.Children.Add(myImage);
myDockPanel.Children.Add(myImage2);
myDockPanel.Children.Add(myImage3);

//Define a StackPanel
myStackPanel = new StackPanel();
myStackPanel.Orientation = Orientation.Horizontal;
Grid.SetRow(myStackPanel, 1);

Image myImage4 = new Image();
BitmapImage bi4 = new BitmapImage();
bi4.BeginInit();
bi4.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi4.EndInit();
myImage4.Source = bi4;

Image myImage5 = new Image();
BitmapImage bi5 = new BitmapImage();
bi5.BeginInit();
bi5.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi5.EndInit();
myImage5.Source = bi5;

Image myImage6 = new Image();
BitmapImage bi6 = new BitmapImage();
bi6.BeginInit();
bi6.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi6.EndInit();
myImage6.Stretch = Stretch.Fill;
myImage6.Source = bi6;

// Add the images to the parent StackPanel
myStackPanel.Children.Add(myImage4);
myStackPanel.Children.Add(myImage5);
myStackPanel.Children.Add(myImage6);

// Add the layout panels as children of the Grid
myGrid.Children.Add(myDockPanel);
myGrid.Children.Add(myStackPanel);

// Add the Grid as the Content of the Parent Window Object
mainWindow.Content = myGrid;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      WindowTitle="StackPanel vs. DockPanel">
  <Grid Width="175" Height="150">
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>

    <DockPanel Grid.Column="0" Grid.Row="0">
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" Stretch="Fill"/>
    </DockPanel>

    <StackPanel Grid.Column="0" Grid.Row="1"  Orientation="Horizontal">
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" Stretch="Fill"/>
    </StackPanel>
    </Grid>
</Page>

Разница в поведении при отображении показана на этом рисунке.

Снимок экрана: сравнение снимков экранов StackPanel и DockPanel

Определение и использование StackPanel

В следующем примере демонстрируется использование StackPanel для создания набора вертикально расположенных кнопок. Для горизонтального расположения присвойте свойству Orientation значение Horizontal.

WindowTitle = "StackPanel Sample"
' Define the StackPanel
Dim myStackPanel As New StackPanel()
myStackPanel.HorizontalAlignment = Windows.HorizontalAlignment.Left
myStackPanel.VerticalAlignment = Windows.VerticalAlignment.Top

' Define child content
Dim myButton1 As New Button()
myButton1.Content = "Button 1"
Dim myButton2 As New Button()
myButton2.Content = "Button 2"
Dim myButton3 As New Button()
myButton3.Content = "Button 3"

' Add child elements to the parent StackPanel
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myStackPanel.Children.Add(myButton3)

Me.Content = myStackPanel
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "StackPanel Sample";

// Define the StackPanel
myStackPanel = new StackPanel();
myStackPanel.HorizontalAlignment = HorizontalAlignment.Left;
myStackPanel.VerticalAlignment = VerticalAlignment.Top;

// Define child content
Button myButton1 = new Button();
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.Content = "Button 3";

// Add child elements to the parent StackPanel
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myStackPanel.Children.Add(myButton3);           

// Add the StackPanel as the Content of the Parent Window Object
mainWindow.Content = myStackPanel;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="StackPanel Sample">
    <StackPanel HorizontalAlignment="Left"
                VerticalAlignment="Top">
        <Button>Button 1</Button>
        <Button>Button 2</Button>
        <Button>Button 3</Button>
    </StackPanel>
</Page>

Скомпилированное приложение возвращает новый Пользовательский интерфейс, выглядящий следующим образом.

Обычный элемент StackPanel.

VirtualizingStackPanel

WPF также предоставляет разновидность элемента StackPanel, который автоматически «делает виртуальным» содержимое дочернего элемента, привязанного к данным. В данном контексте слово «виртуализация» означает способ, с помощью которого подмножество UIElements создается из большого количества элементов данных на основе видимых на экране элементов. Как для памяти, так и для процессора затратно создавать большое число элементов пользовательского интерфейса, при том что только несколько из них могут отображаться на экране одновременно. VirtualizingStackPanel (с помощью функций, предоставляемых VirtualizingPanel) вычисляет видимые элементы и работает с ItemContainerGenerator из ItemsControl (например, ListBox или ListView) только для создания UIElements для видимых элементов.

Элемент VirtualizingStackPanel автоматически устанавливается в качестве ведущего элемента для элементов управления, например ListBox. При размещении присоединенной коллекции данных содержимое будет автоматически виртуализировано, пока содержимое находится в пределах ScrollViewer. Это значительно повышает быстродействие при размещении большого числа дочерних элементов.

Следующая разметка демонстрируется использование VirtualizingStackPanel в качестве узла элементов. IsVirtualizing вложенное свойство должно быть установлено в True (по умолчанию) для осуществления виртуализации.

<StackPanel DataContext="{Binding Source={StaticResource Leagues}}">
    <TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="18" Foreground="Black"/>
        <ListBox VirtualizingStackPanel.IsVirtualizing="True" 
                 ItemsSource="{Binding XPath=Team}" 
                 ItemTemplate="{DynamicResource NameDataStyle}"/>      
</StackPanel>

WrapPanel

WrapPanel используется для расположения дочерних элементов в последовательную слева направо, разрывая содержимое для перехода на следующую строку при достижении границы родительского контейнера. Содержимое может быть ориентированным горизонтально или вертикально. WrapPanel используется для простых поточных сценариев пользовательский интерфейс. Она может также использоваться для установления единого размера для всех дочерних элементов.

В следующем примере демонстрируется создание WrapPanel для отображения элементов управления Button, которые переносятся при достижении границы контейнера.

WindowTitle = "WrapPanel Sample"

' Instantiate a new WrapPanel and set properties
Dim myWrapPanel As New WrapPanel()
myWrapPanel.Background = Brushes.Azure
myWrapPanel.Orientation = Orientation.Horizontal
myWrapPanel.ItemHeight = 25

myWrapPanel.ItemWidth = 75
myWrapPanel.Width = 150
myWrapPanel.HorizontalAlignment = Windows.HorizontalAlignment.Left
myWrapPanel.VerticalAlignment = Windows.VerticalAlignment.Top

' Define 3 button elements. Each button is sized at width of 75, so the third button wraps to the next line.
Dim btn1 As New Button()
btn1.Content = "Button 1"
Dim btn2 As New Button()
btn2.Content = "Button 2"
Dim btn3 As New Button()
btn3.Content = "Button 3"

' Add the buttons to the parent WrapPanel using the Children.Add method.
myWrapPanel.Children.Add(btn1)
myWrapPanel.Children.Add(btn2)
myWrapPanel.Children.Add(btn3)

' Add the WrapPanel to the Page as Content
Me.Content = myWrapPanel

            // Create the application's main window
            mainWindow = new System.Windows.Window();
            mainWindow.Title = "WrapPanel Sample";


            // Instantiate a new WrapPanel and set properties
            myWrapPanel = new WrapPanel();
            myWrapPanel.Background = System.Windows.Media.Brushes.Azure;
            myWrapPanel.Orientation = Orientation.Horizontal;
            myWrapPanel.ItemHeight = 25;

            myWrapPanel.ItemWidth = 75;
            myWrapPanel.Width = 150;
            myWrapPanel.HorizontalAlignment = HorizontalAlignment.Left;
            myWrapPanel.VerticalAlignment = VerticalAlignment.Top;

            // Define 3 button elements. Each button is sized at width of 75, so the third button wraps to the next line.
            btn1 = new Button();
            btn1.Content = "Button 1";
            btn2 = new Button();
            btn2.Content = "Button 2";
            btn3 = new Button();
            btn3.Content = "Button 3";

            // Add the buttons to the parent WrapPanel using the Children.Add method.
            myWrapPanel.Children.Add(btn1);
            myWrapPanel.Children.Add(btn2);
            myWrapPanel.Children.Add(btn3);

            // Add the WrapPanel to the MainWindow as Content
            mainWindow.Content = myWrapPanel;
            mainWindow.Show();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="WrapPanel Sample">
  <Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2">
        <WrapPanel Background="LightBlue" Width="200" Height="100">
            <Button Width="200">Button 1</Button>
            <Button>Button 2</Button>
            <Button>Button 3</Button>
            <Button>Button 4</Button>
        </WrapPanel>
  </Border>    
</Page>

Скомпилированное приложение возвращает новый Пользовательский интерфейс, выглядящий следующим образом.

Обычный элемент WrapPanel.

Вложенные элементы Panel

Элементы Panel могут быть вложены друг в друга для возможности создания сложных макетов. Это может быть очень полезным в ситуациях, когда одна Panel идеально подходит для фрагмента Пользовательский интерфейс, но не может удовлетворить потребности различных частей Пользовательский интерфейс.

Практически не существует ограничений в объема вложения, которое приложение может поддерживать, однако лучше всего ограничить приложение использованием только тех панелей, которые действительно необходимы для макета. В большинстве случаев элемент Grid может использоваться вместо вложенных панелей из-за его гибкости в качестве контейнера макета. Это может повысить производительность в приложении, убирая ненужные элементы из дерева.

В следующем примере демонстрируется создание Пользовательский интерфейс, использующего преимущества вложенных элементов Panel, чтобы добиться определенного макета. В этом конкретном случае элемент DockPanel используется для предоставления структуры Пользовательский интерфейс, и вложенные элементы StackPanel, Grid и Canvas используются для размещения дочерних элементов внутри родительской DockPanel.

Dim myDockPanel As New DockPanel()

Dim myBorder2 As New Border()
myBorder2.BorderThickness = New Thickness(1)
myBorder2.BorderBrush = Brushes.Black
DockPanel.SetDock(myBorder2, Dock.Left)
Dim myStackPanel As New StackPanel()
Dim myButton1 As New Button()
myButton1.Content = "Left Docked"
myButton1.Margin = New Thickness(5)
Dim myButton2 As New Button()
myButton2.Content = "StackPanel"
myButton2.Margin = New Thickness(5)
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myBorder2.Child = myStackPanel

Dim myBorder3 As New Border()
myBorder3.BorderThickness = New Thickness(1)
myBorder3.BorderBrush = Brushes.Black
DockPanel.SetDock(myBorder3, Dock.Top)
Dim myGrid As New Grid()
myGrid.ShowGridLines = True
Dim myRowDef1 As New RowDefinition()
Dim myRowDef2 As New RowDefinition()
Dim myColDef1 As New ColumnDefinition()
Dim myColDef2 As New ColumnDefinition()
Dim myColDef3 As New ColumnDefinition()
myGrid.ColumnDefinitions.Add(myColDef1)
myGrid.ColumnDefinitions.Add(myColDef2)
myGrid.ColumnDefinitions.Add(myColDef3)
myGrid.RowDefinitions.Add(myRowDef1)
myGrid.RowDefinitions.Add(myRowDef2)
Dim myTextBlock1 As New TextBlock()
myTextBlock1.FontSize = 20
myTextBlock1.Margin = New Thickness(10)
myTextBlock1.Text = "Grid Element Docked at the Top"
Grid.SetRow(myTextBlock1, 0)
Grid.SetColumnSpan(myTextBlock1, 3)
Dim myButton3 As New Button()
myButton3.Margin = New Thickness(5)
myButton3.Content = "A Row"
Grid.SetColumn(myButton3, 0)
Grid.SetRow(myButton3, 1)
Dim myButton4 As New Button()
myButton4.Margin = New Thickness(5)
myButton4.Content = "of Button"
Grid.SetColumn(myButton4, 1)
Grid.SetRow(myButton4, 1)
Dim myButton5 As New Button()
myButton5.Margin = New Thickness(5)
myButton5.Content = "Elements"
Grid.SetColumn(myButton5, 2)
Grid.SetRow(myButton5, 1)
myGrid.Children.Add(myTextBlock1)
myGrid.Children.Add(myButton3)
myGrid.Children.Add(myButton4)
myGrid.Children.Add(myButton5)
myBorder3.Child = myGrid

Dim myBorder4 As New Border()
myBorder4.BorderBrush = Brushes.Black
myBorder4.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder4, Dock.Bottom)
Dim myStackPanel2 As New StackPanel()
myStackPanel2.Orientation = Orientation.Horizontal
Dim myTextBlock2 As New TextBlock()
myTextBlock2.Text = "This StackPanel is Docked to the Bottom"
myTextBlock2.Margin = New Thickness(5)
myStackPanel2.Children.Add(myTextBlock2)
myBorder4.Child = myStackPanel2

Dim myBorder5 As New Border()
myBorder5.BorderBrush = Brushes.Black
myBorder5.BorderThickness = New Thickness(1)
Dim myCanvas As New Canvas()
myCanvas.ClipToBounds = True
Dim myTextBlock3 As New TextBlock()
myTextBlock3.Text = "Content in the Canvas will Fill the remaining space."
Canvas.SetTop(myTextBlock3, 50)
Canvas.SetLeft(myTextBlock3, 50)
Dim myEllipse As New Ellipse()
myEllipse.Height = 100
myEllipse.Width = 125
myEllipse.Fill = Brushes.CornflowerBlue
myEllipse.Stroke = Brushes.Aqua
Canvas.SetTop(myEllipse, 100)
Canvas.SetLeft(myEllipse, 150)
myCanvas.Children.Add(myTextBlock3)
myCanvas.Children.Add(myEllipse)
myBorder5.Child = myCanvas

myDockPanel.Children.Add(myBorder2)
myDockPanel.Children.Add(myBorder3)
myDockPanel.Children.Add(myBorder4)
myDockPanel.Children.Add(myBorder5)
// Define the DockPanel.
myDockPanel = new DockPanel();

// Add the Left Docked StackPanel
Border myBorder2 = new Border();
myBorder2.BorderThickness = new Thickness(1);
myBorder2.BorderBrush = Brushes.Black;
DockPanel.SetDock(myBorder2, Dock.Left);
StackPanel myStackPanel = new StackPanel();
Button myButton1 = new Button();
myButton1.Content = "Left Docked";
myButton1.Margin = new Thickness(5);
Button myButton2 = new Button();
myButton2.Content = "StackPanel";
myButton2.Margin = new Thickness(5);
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myBorder2.Child = myStackPanel;

// Add the Top Docked Grid.
Border myBorder3 = new Border();
myBorder3.BorderThickness = new Thickness(1);
myBorder3.BorderBrush = Brushes.Black;
DockPanel.SetDock(myBorder3, Dock.Top);
Grid myGrid = new Grid();
myGrid.ShowGridLines = true;
RowDefinition myRowDef1 = new RowDefinition();
RowDefinition myRowDef2 = new RowDefinition();
ColumnDefinition myColDef1 = new ColumnDefinition();
ColumnDefinition myColDef2 = new ColumnDefinition();
ColumnDefinition myColDef3 = new ColumnDefinition();
myGrid.ColumnDefinitions.Add(myColDef1);
myGrid.ColumnDefinitions.Add(myColDef2);
myGrid.ColumnDefinitions.Add(myColDef3);
myGrid.RowDefinitions.Add(myRowDef1);
myGrid.RowDefinitions.Add(myRowDef2);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.FontSize = 20;
myTextBlock1.Margin = new Thickness(10);
myTextBlock1.Text = "Grid Element Docked at the Top";
Grid.SetRow(myTextBlock1, 0);
Grid.SetColumnSpan(myTextBlock1, 3);
Button myButton3 = new Button();
myButton3.Margin = new Thickness(5);
myButton3.Content = "A Row";
Grid.SetColumn(myButton3, 0);
Grid.SetRow(myButton3, 1);
Button myButton4 = new Button();
myButton4.Margin = new Thickness(5);
myButton4.Content = "of Button";
Grid.SetColumn(myButton4, 1);
Grid.SetRow(myButton4, 1);
Button myButton5 = new Button();
myButton5.Margin = new Thickness(5);
myButton5.Content = "Elements";
Grid.SetColumn(myButton5, 2);
Grid.SetRow(myButton5, 1);
myGrid.Children.Add(myTextBlock1);
myGrid.Children.Add(myButton3);
myGrid.Children.Add(myButton4);
myGrid.Children.Add(myButton5);
myBorder3.Child = myGrid;

// Add the Bottom Docked StackPanel.
Border myBorder4 = new Border();
myBorder4.BorderBrush = Brushes.Black;
myBorder4.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder4, Dock.Bottom);
StackPanel myStackPanel2 = new StackPanel();
myStackPanel2.Orientation = Orientation.Horizontal;
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Text = "This StackPanel is Docked to the Bottom";
myTextBlock2.Margin = new Thickness(5);
myStackPanel2.Children.Add(myTextBlock2);
myBorder4.Child = myStackPanel2;

// Add the Canvas, that fills remaining space.
Border myBorder5 = new Border();
myBorder4.BorderBrush = Brushes.Black;
myBorder5.BorderThickness = new Thickness(1);
Canvas myCanvas = new Canvas();
myCanvas.ClipToBounds = true;
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Text = "Content in the Canvas will Fill the remaining space.";
Canvas.SetTop(myTextBlock3, 50);
Canvas.SetLeft(myTextBlock3, 50);
Ellipse myEllipse = new Ellipse();
myEllipse.Height = 100;
myEllipse.Width = 125;
myEllipse.Fill = Brushes.CornflowerBlue;
myEllipse.Stroke = Brushes.Aqua;
Canvas.SetTop(myEllipse, 100);
Canvas.SetLeft(myEllipse, 150);
myCanvas.Children.Add(myTextBlock3);
myCanvas.Children.Add(myEllipse);
myBorder5.Child = myCanvas;

// Add child elements to the parent DockPanel.
myDockPanel.Children.Add(myBorder2);
myDockPanel.Children.Add(myBorder3);
myDockPanel.Children.Add(myBorder4);
myDockPanel.Children.Add(myBorder5);
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="Nested Panels">
  <Border Background="AliceBlue" 
          Width="400" 
          Height="300" 
          BorderBrush="DarkSlateBlue" 
          BorderThickness="2"
          HorizontalAlignment="Left" 
          VerticalAlignment="Top">
    <DockPanel>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
        <StackPanel>
          <Button Margin="5">Left Docked</Button>
          <Button Margin="5">StackPanel</Button>
        </StackPanel>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
        <Grid ShowGridLines="True">
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <TextBlock FontSize="20" Margin="10" Grid.ColumnSpan="3" Grid.Row="0">Grid Element Docked to the Top.</TextBlock>
          <Button Grid.Row="1" Grid.Column="0" Margin="5">A Row</Button>
          <Button Grid.Row="1" Grid.Column="1" Margin="5">of Button</Button>
          <Button Grid.Row="1" Grid.Column="2" Margin="5">Elements</Button>
        </Grid>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
        <StackPanel Orientation="Horizontal">
          <TextBlock Margin="5">This StackPanel is Docked to the Bottom.</TextBlock>
        </StackPanel>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1">
        <Canvas ClipToBounds="True">
          <TextBlock Canvas.Top="50" Canvas.Left="50">
            Content in the Canvas will Fill the remaining Space.
          </TextBlock>
          <Ellipse Height="100" Width="125" Fill="CornflowerBlue" Stroke="Aqua" Canvas.Top="100" Canvas.Left="150"/>
        </Canvas>
      </Border>
    </DockPanel>
  </Border>
</Page>

Скомпилированное приложение возвращает новый Пользовательский интерфейс, выглядящий следующим образом.

Пользовательский интерфейс, использующий вложенные панели.

Пользовательские элементы Panel

В то время как WPF предоставляет массив гибкий элементов управления макетом, поведение пользовательского макета также можно достичь путем переопределения методов ArrangeOverride и MeasureOverride. Пользовательские изменения размеров и положения могут быть выполнены путем определения нового поведения размещения в этих переопределенных методах.

Аналогично, поведение пользовательского макета, основанное на производных классах (например, Canvas или Grid), может быть задано путем переопределения их методов ArrangeOverride и MeasureOverride.

Следующая разметка демонстрирует способы создания пользовательского элемента Panel с помощью C#. Эта новая Panel, определенная как PlotPanel, поддерживает размещение дочерних элементов с использованием жестко закодированных координат x и y. В этом примере элемент Rectangle (не показано) находится в точке с координатами 50 ( x) и 50 ( y ).

Public Class PlotPanel
    Inherits Panel
    'Override the default Measure method of Panel.

    Protected Overrides Function MeasureOverride(ByVal availableSize As System.Windows.Size) As System.Windows.Size
        Dim childSize As Size = CType(availableSize, Size)
        For Each child As UIElement In InternalChildren
            child.Measure(childSize)
        Next
        Return MyBase.MeasureOverride(availableSize)
    End Function
    Protected Overrides Function ArrangeOverride(ByVal finalSize As System.Windows.Size) As System.Windows.Size
        For Each child As UIElement In InternalChildren
            Dim x As Double = 50
            Dim y As Double = 50
            child.Arrange(New Rect(New System.Windows.Point(x, y), child.DesiredSize))
        Next
        Return MyBase.ArrangeOverride(finalSize)
    End Function
End Class
public class PlotPanel : Panel
{
    // Default public constructor
    public PlotPanel()
        : base()
    {
    }

    // Override the default Measure method of Panel
    protected override Size MeasureOverride(Size availableSize)
    {
        Size panelDesiredSize = new Size();

        // In our example, we just have one child. 
        // Report that our panel requires just the size of its only child.
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
            panelDesiredSize = child.DesiredSize;
        }

        return panelDesiredSize ;
    }
    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement child in InternalChildren)
        {
            double x = 50;
            double y = 50;

            child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
        }
        return finalSize; // Returns the final Arranged size
    }
}

Полный пример содержится в разделе Пример создания простой пользовательской панели.

Реализация более сложной пользовательской панели представлен в Пример создания пользовательской панели с переносом содержимого.

Поддержка локализации/глобализации

WPF поддерживает ряд возможностей для создании локализуемого Пользовательский интерфейс.

Все элементы panel изначально поддерживают свойство FlowDirection, которое может использоваться для динамического содержимого, основанного на параметрах локализации или языка пользователя. Дополнительные сведения см. в разделе FlowDirection.

Свойство SizeToContent предоставляет механизм, позволяющий разработчикам приложений предвидеть потребности локализованного Пользовательский интерфейс. С использованием значения WidthAndHeight этого свойства родительское Window всегда изменяет свой размер динамически по размеру содержимого и не ограничивается искусственно высотой или шириной.

DockPanel, Grid и StackPanel являются хорошими вариантами для локализуемого Пользовательский интерфейс. Canvas не является хорошим вариантом, однако, поскольку его расположение содержимого абсолютно, это затрудняет локализацию.

Дополнительные сведения о создании приложений WPF с локализуемыми Пользовательские интерфейсы содержатся в разделе Обзор использования автоматической разметки.

См. также

Задачи

Пример отображения галереи макетов WPF

Пример отображения галереи элементов управления WPF

Пример создания пользовательской панели с переносом содержимого

Основные понятия

Введение в Windows Presentation Foundation

Система макета

Общие сведения о свойствах Alignment, Margin, Padding

Общие сведения о вложенных свойствах зависимостей

Обзор использования автоматической разметки

Оптимизация производительности: разметка и разработка