Сегодня узнаем о всех типах контейнеров WPF:
Panel (абстрактный класс) ├── Grid ⭐⭐⭐⭐⭐ (самый популярный) ├── StackPanel ⭐⭐⭐⭐ ├── WrapPanel ⭐⭐⭐ ├── DockPanel ⭐⭐⭐ ├── Canvas ⭐⭐ ├── VirtualizingPanel ⭐⭐⭐⭐ (для производительности) │ ├── VirtualizingStackPanel │ └── VirtualizingWrapPanel └── UniformGrid ⭐⭐
<Grid>
<!-- Определяем строки -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- По содержимому -->
<RowDefinition Height="*"/> <!-- Занять всё свободное место -->
<RowDefinition Height="2*"/> <!-- В 2 раза больше -->
<RowDefinition Height="50"/> <!-- Фиксированная высота -->
</Grid.RowDefinitions>
<!-- Определяем столбцы -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<!-- Элементы -->
<Label Grid.Row="0" Grid.Column="0" Content="Имя:"/>
<TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"/>
<Button Grid.Row="1" Grid.Column="1" Content="OK"/>
</Grid>
<!-- Размеры строк -->
Row 0: Auto (по содержимому)
Row 1: * (занимает доступное место)
Row 2: 2* (в 2 раза больше)
Row 3: 50 (фиксированная)
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Имя:" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="5"/>
<Label Grid.Row="1" Grid.Column="0" Content="Email:" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="5"/>
<Label Grid.Row="2" Grid.Column="0" Content="Пароль:" VerticalAlignment="Center"/>
<PasswordBox Grid.Row="2" Grid.Column="1" Margin="5"/>
<Label Grid.Row="3" Grid.Column="0" Content="О себе:" VerticalAlignment="Top"/>
<TextBox Grid.Row="3" Grid.Column="1" Height="80" TextWrapping="Wrap" Margin="5"/>
<CheckBox Grid.Row="4" Grid.Column="1" Content="Согласен с условиями" Margin="5"/>
<Button Grid.Row="5" Grid.Column="1" Content="Зарегистрироваться"
Height="40" Width="150" HorizontalAlignment="Left" Margin="5"/>
</Grid>
Создай форму входа (Login) с помощью Grid: Поля "Логин", "Пароль", кнопка "Войти", ссылка "Забыли пароль?".
<StackPanel>
<Button Content="Кнопка 1"/>
<Button Content="Кнопка 2"/>
<Button Content="Кнопка 3"/>
</StackPanel><StackPanel Orientation="Horizontal">
<Button Content="1"/>
<Button Content="2"/>
<Button Content="3"/>
</StackPanel><!-- Горизонтальное меню -->
<StackPanel Orientation="Horizontal" Background="#333">
<Button Content="Главная" Style="{StaticResource MenuButton}"/>
<Button Content="О нас" Style="{StaticResource MenuButton}"/>
<Button Content="Контакты" Style="{StaticResource MenuButton}"/>
</StackPanel>
<!-- Боковая панель с инструментами -->
<StackPanel Background="#f0f0f0" Width="200">
<Button Content="✏️ Рисовать" Margin="5"/>
<Button Content="📷 Вставить картинку" Margin="5"/>
<Button Content="💾 Сохранить" Margin="5"/>
<Separator Margin="5"/>
<Button Content="🗑️ Удалить" Margin="5"/>
</StackPanel>
<!-- Форма (вертикально) -->
<StackPanel>
<Label Content="Имя:"/>
<TextBox/>
<Label Content="Возраст:"/>
<TextBox/>
<Button Content="Отправить"/>
</StackPanel>
<WrapPanel Orientation="Horizontal">
<Button Content="Элемент 1" Width="120" Height="40"/>
<Button Content="Элемент 2" Width="120" Height="40"/>
<Button Content="Элемент 3" Width="120" Height="40"/>
<Button Content="Элемент 4" Width="120" Height="40"/>
<Button Content="Элемент 5" Width="120" Height="40"/>
<Button Content="Элемент 6" Width="120" Height="40"/>
</WrapPanel>
<DockPanel LastChildFill="True">
<!-- Последний элемент заполняет оставшееся место -->
<Button Content="Верх" DockPanel.Dock="Top" Height="40"/>
<Button Content="Низ" DockPanel.Dock="Bottom" Height="40"/>
<Button Content="Лево" DockPanel.Dock="Left" Width="150"/>
<Button Content="Право" DockPanel.Dock="Right" Width="100"/>
<Button Content="Центр (заполняет всё)"/>
</DockPanel>
<Canvas Background="LightGray" Width="400" Height="300">
<Button Content="Кнопка 1" Canvas.Left="50" Canvas.Top="30"/>
<Button Content="Кнопка 2" Canvas.Left="200" Canvas.Top="30"/>
<Button Content="Кнопка 3" Canvas.Left="50" Canvas.Top="100"/>
<Button Content="Кнопка 4" Canvas.Left="200" Canvas.Top="100"/>
<!-- Рисование -->
<Rectangle Fill="Red" Width="50" Height="50" Canvas.Left="300" Canvas.Top="200"/>
<Ellipse Fill="Blue" Width="40" Height="40" Canvas.Left="10" Canvas.Top="250"/>
</Canvas>
<UniformGrid Rows="3" Columns="3">
<Button Content="1"/> <Button Content="2"/> <Button Content="3"/>
<Button Content="4"/> <Button Content="5"/> <Button Content="6"/>
<Button Content="7"/> <Button Content="8"/> <Button Content="9"/>
</UniformGrid>
<!-- Или проще: без Rows/Columns -- сам определит -->
<UniformGrid>
<Button Content="A"/> <Button Content="B"/> <Button Content="C"/>
<Button Content="D"/> <Button Content="E"/> <Button Content="F"/>
</UniformGrid>
| Контейнер | Гибкость | Сложность | Когда использовать |
|---|---|---|---|
| Grid | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | Сложные формы, привязка к позиции |
| StackPanel | ⭐⭐⭐ | ⭐ | Списки, меню, простые формы |
| WrapPanel | ⭐⭐⭐⭐ | ⭐ | Облака тегов, адаптивные панели |
| DockPanel | ⭐⭐⭐⭐ | ⭐⭐ | IDE, главные окна с панелями |
| Canvas | ⭐ | ⭐ | Рисование, анимация, игры |
| UniformGrid | ⭐⭐⭐ | ⭐ | Каталоги, калькуляторы |
<!-- Главный Grid -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- Заголовок -->
<RowDefinition Height="*"/> <!-- Контент -->
<RowDefinition Height="Auto"/> <!-- Подвал -->
</Grid.RowDefinitions>
<!-- Верхняя панель (StackPanel) -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#333">
<Button Content="Главная"/>
<Button Content="Новости"/>
<Button Content="Контакты"/>
</StackPanel>
<!-- Основной контент (Grid внутри Grid) -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Левая панель (WrapPanel) -->
<WrapPanel Grid.Column="0" Background="#f0f0f0">
<Button Content="Инструмент 1" Width="180" Margin="5"/>
<Button Content="Инструмент 2" Width="180" Margin="5"/>
<Button Content="Инструмент 3" Width="180" Margin="5"/>
</WrapPanel>
<!-- Правая панель (DockPanel) -->
<DockPanel Grid.Column="1">
<TextBox DockPanel.Dock="Top" Height="30" Margin="5"/>
<ListBox/>
</DockPanel>
</Grid>
<!-- Подвал (DockPanel) -->
<StatusBar Grid.Row="2">
<StatusBarItem Content="Готов"/>
</StatusBar>
</Grid>
Создай типичный макет приложения с помощью контейнеров:
🎨 Используй разные цвета для наглядности.
<!-- VirtualizingStackPanel используется по умолчанию в ListBox -->
<ListBox ItemsSource="{Binding BigList}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VirtualizationMode="Recycling"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<!-- Отключить виртуализацию (не рекомендуется для больших списков) -->
<ListBox VirtualizingPanel.IsVirtualizing="False" .../>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="5"/> <!-- Место для Splitter -->
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Левая панель -->
<ListBox Grid.Column="0" Background="#f0f0f0"/>
<!-- Разделитель -->
<GridSplitter Grid.Column="1" Width="5"
HorizontalAlignment="Stretch"
Background="Gray"
ResizeDirection="Columns"
ResizeBehavior="PreviousAndNext"/>
<!-- Правая панель (изменяемый размер) -->
<TextBox Grid.Column="2"/>
</Grid>
<!-- WrapPanel с прокруткой -->
<ScrollViewer Height="300">
<WrapPanel>
<!-- Много элементов -->
<Button Content="1" Width="100" Height="50" Margin="5"/>
<Button Content="2" Width="100" Height="50" Margin="5"/>
<!-- ... 50 элементов -->
</WrapPanel>
</ScrollViewer>
<!-- StackPanel с прокруткой -->
<ScrollViewer>
<StackPanel>
<TextBox Height="500"/>
<TextBox Height="500"/>
<TextBox Height="500"/>
</StackPanel>
</ScrollViewer>
<Border Background="LightBlue"
BorderBrush="Blue"
BorderThickness="2"
CornerRadius="10"
Padding="10">
<StackPanel>
<Label Content="Заголовок" FontWeight="Bold"/>
<TextBox Text="Содержимое"/>
<Button Content="OK"/>
</StackPanel>
</Border>
<!-- Viewbox автоматически масштабирует содержимое -->
<Viewbox Width="200" Height="200">
<Button Content="Кнопка" Width="100" Height="30"/>
</Viewbox>
<!-- Масштабирование с сохранением пропорций -->
<Viewbox Stretch="Uniform">
<Canvas Width="100" Height="100">
<Rectangle Fill="Red" Width="100" Height="100"/>
<Ellipse Fill="Blue" Width="80" Height="80" Canvas.Left="10" Canvas.Top="10"/>
</Canvas>
</Viewbox>
<Grid><StackPanel><WrapPanel><DockPanel>... (сложно читать)<Grid>
<Button/> <!-- Окажется в Row=0, Col=0 -->
<Button Grid.Row="1"/> <!-- Ошибка: нет Column -->
</Grid><Canvas><Button Canvas.Left="50" Canvas.Top="30"/></Canvas><ListBox VirtualizingPanel.IsVirtualizing="False"/>Требования:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Верхнее меню -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#333">
<Button Content="Файл" Foreground="White" Background="Transparent"/>
<Button Content="Правка" Foreground="White" Background="Transparent"/>
<Button Content="Вид" Foreground="White" Background="Transparent"/>
</StackPanel>
<!-- Основная область -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<!-- Левая панель -->
<StackPanel Grid.Column="0" Background="#f0f0f0">
<Button Content="Инструмент 1" Margin="5"/>
<Button Content="Инструмент 2" Margin="5"/>
<Button Content="Инструмент 3" Margin="5"/>
</StackPanel>
<GridSplitter Grid.Column="1" Width="5" Background="Gray"/>
<!-- Центр с прокруткой -->
<ScrollViewer Grid.Column="2">
<StackPanel>
<TextBox Height="200"/>
<ListBox Height="200"/>
</StackPanel>
</ScrollViewer>
<GridSplitter Grid.Column="3" Width="5" Background="Gray"/>
<!-- Правая панель -->
<WrapPanel Grid.Column="4" Background="#e8f4f8">
<CheckBox Content="Опция 1" Margin="5"/>
<CheckBox Content="Опция 2" Margin="5"/>
<CheckBox Content="Опция 3" Margin="5"/>
</WrapPanel>
</Grid>
<!-- Нижняя панель -->
<StatusBar Grid.Row="2" Background="#ddd">
<StatusBarItem Content="Готов"/>
<Separator/>
<StatusBarItem Content="Пользователь: Admin"/>
</StatusBar>
</Grid>
Что вы узнали:
🙏 Вопросы?