Перейти к основному содержимому

Справочник по WPF — элементы UI


Назначение

Пошаговые рецепты WPF — в первую очередь XAML + при необходимости code-behind. Практикум — 119.md, платформа — 116.md. Синтаксис XAML — справочник XAML. Общие имена элементов — Архитектура десктопных приложений; UI-поток — 112.md. Язык C# — раздел C#.


Как пользоваться

  1. Создайте проект WPF (<UseWPF>true</UseWPF>).
  2. Разметку добавляйте в MainWindow.xaml внутри корневого контейнера (Grid, StackPanel).
  3. Логику — в ViewModel с {Binding} или в *.xaml.cs для простых обработчиков.
  4. Обновление UI из фона — Dispatcher.Invoke или await после Task.Run.

Главное окно (Window)

MainWindow.xaml:

<Window x:Class="App.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Моё приложение"
Height="480" Width="640"
MinWidth="400" MinHeight="300">
<!-- контент ниже -->
</Window>

App.xaml.csStartupUri="MainWindow.xaml" или OnStartup с new MainWindow().Show().


Контейнер (Grid / StackPanel)

<Grid Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>

<StackPanel Orientation="Vertical" Margin="12" Spacing="8">
<!-- дочерние элементы -->
</StackPanel>

<DockPanel LastChildFill="True">
<Menu DockPanel.Dock="Top"/>
<StatusBar DockPanel.Dock="Bottom"/>
<Grid><!-- центр --></Grid>
</DockPanel>

Label (метка)

<Label Content="Имя пользователя:" VerticalAlignment="Center"/>
<TextBlock Text="Статический текст" TextWrapping="Wrap"/>

Code-behind:

StatusLabel.Content = "Сохранено";

Привязка:

<Label Content="{Binding StatusText}"/>

TextBox — однострочный

<TextBox x:Name="NameBox"
Width="240"
MaxLength="100"
Text="по умолчанию"/>
string value = NameBox.Text;
NameBox.Clear();
NameBox.Text = "новое";

// Enter
NameBox.KeyDown += (s, e) => { if (e.Key == Key.Enter) Submit(); };

Привязка (MVVM):

<TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}"/>

TextBox — многострочный

<TextBox AcceptsReturn="True"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
Height="120"/>

Поле пароля

<PasswordBox x:Name="PwdBox" Width="200"/>
string pwd = PwdBox.Password;

Button (кнопка)

<Button Content="Сохранить"
Width="100"
IsDefault="True"
Click="Save_Click"/>
private void Save_Click(object sender, RoutedEventArgs e) { /* ... */ }

Команда (MVVM):

<Button Content="Сохранить" Command="{Binding SaveCommand}"/>

CheckBox (флажок)

<CheckBox Content="Уведомления" IsChecked="True"/>
<CheckBox Content="Согласен" IsChecked="{Binding IsAgreed}"/>

RadioButton (переключатель)

<StackPanel>
<RadioButton Content="Пользователь" GroupName="Role" IsChecked="True"/>
<RadioButton Content="Админ" GroupName="Role"/>
</StackPanel>

ComboBox (выпадающий список)

<ComboBox Width="180" SelectedIndex="0">
<ComboBoxItem Content="Работа"/>
<ComboBoxItem Content="Личное"/>
</ComboBox>

Привязка к коллекции:

<ComboBox ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedCategory}"
DisplayMemberPath="Name"/>

ListBox (список)

<ListBox ItemsSource="{Binding Items}"
SelectedItem="{Binding CurrentItem}"
Height="160"/>

Шаблон элемента — DataTemplate (см. 119.md).


DataGrid (таблица)

<DataGrid ItemsSource="{Binding People}"
AutoGenerateColumns="True"
IsReadOnly="True"
CanUserAddRows="False"/>

Явные колонки:

<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Имя" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Возраст" Binding="{Binding Age}"/>
</DataGrid.Columns>
</DataGrid>

ProgressBar (индикатор прогресса)

<ProgressBar Minimum="0" Maximum="100" Value="50" Height="20"/>
<ProgressBar IsIndeterminate="True" Height="20"/>
<ProgressBar Value="{Binding ProgressPercent}"/>

Slider (ползунок)

<Slider Minimum="0" Maximum="100" Value="{Binding Volume}" TickFrequency="10"/>

Поле поиска (фильтр)

ViewModel фильтрует коллекцию при изменении SearchText:

<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,8"/>
<ListBox ItemsSource="{Binding FilteredItems}"/>
public string SearchText
{
get => _search;
set { _search = value; OnPropertyChanged(); UpdateFilter(); }
}

TabControl (вкладки)

<TabControl>
<TabItem Header="Общее">
<TextBlock Text="Содержимое" Margin="8"/>
</TabItem>
<TabItem Header="Настройки">
<CheckBox Content="Опция" Margin="8"/>
</TabItem>
</TabControl>

<Menu DockPanel.Dock="Top">
<MenuItem Header="_Файл">
<MenuItem Header="Открыть" Click="Open_Click"/>
<Separator/>
<MenuItem Header="Выход" Click="Exit_Click"/>
</MenuItem>
</Menu>

ToolBar (панель инструментов)

<ToolBar Tray="Top">
<Button Content="Новый" Click="New_Click"/>
<Separator/>
<Button Content="Сохранить" Click="Save_Click"/>
</ToolBar>

StatusBar (строка состояния)

<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="{Binding StatusText}"/>
</StatusBar>

ScrollViewer (прокрутка)

<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- длинный контент -->
</StackPanel>
</ScrollViewer>

Диалоги

MessageBox.Show("Готово", "Информация", MessageBoxButton.OK, MessageBoxImage.Information);
var ok = MessageBox.Show("Удалить?", "Подтверждение", MessageBoxButton.YesNo) == MessageBoxResult.Yes;

var dlg = new OpenFileDialog { Filter = "Текст|*.txt|Все|*.*" };
if (dlg.ShowDialog() == true) { var path = dlg.FileName; }

var save = new SaveFileDialog { DefaultExt = ".txt" };
if (save.ShowDialog() == true) { /* записать */ }

(Microsoft.Win32OpenFileDialog, SaveFileDialog.)


ToolTip (подсказка)

<Button Content="?" ToolTip="Сохранить документ на диск"/>

ContextMenu (контекстное меню)

<ListBox>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Копировать" Click="Copy_Click"/>
<MenuItem Header="Вставить" Click="Paste_Click"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>

Дочернее окно (модальное)

var dialog = new SettingsWindow { Owner = this };
if (dialog.ShowDialog() == true) { /* применить */ }

SettingsWindow.xaml — отдельный Window с ResizeMode="NoResize".


Общие ресурсы (Style)

App.xaml:

<Application.Resources>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="0,0,0,8"/>
<Setter Property="Padding" Value="4,2"/>
</Style>
<Style x:Key="PrimaryButton" TargetType="Button">
<Setter Property="Background" Value="#2563eb"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Padding" Value="12,6"/>
</Style>
</Application.Resources>
<Button Content="OK" Style="{StaticResource PrimaryButton}"/>

Привязка данных (кратко)

XAMLНазначение
{Binding Path}свойство DataContext
{Binding Name, Mode=TwoWay}двусторонняя
{Binding Count, StringFormat=N0}формат
{RelativeSource Self, Path=ActualWidth}к самому элементу

DataContext задают на Window или корневом Grid: DataContext="{Binding MainViewModel}".


Фоновая работа

await Task.Run(() => LongWork());
StatusText = "Готово";

// или явно
Dispatcher.Invoke(() => ProgressBar.Value = 50);

Частые ошибки

СимптомПричина
Binding не работаетНет DataContext, свойство без INotifyPropertyChanged
Окно пустоеЭлемент вне видимой области, Height=0
Cross-threadUI не через Dispatcher
XAML не собираетсяНеверный xmlns, опечатка в теге

См. также


См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").