C# WinForms и WPF — простые окна

Приветствую! Здесь вы наверняка найдете, что ищете. Примеры в лаборатории рассчитаны на то, что мы разбираем что-то конкретное.

Текущая статья посвящена примерам: WinForms и WPF на C# с построчным разбором.

Поэтому за теорией по текущей теме вам — в энциклопедию. Если ещё не погружались, то маршрут прост:

  1. Основы
  2. Система и сеть
  3. Данные и разметка
  4. Код и разработка
  5. Языки
  6. Искусственный интеллект
  7. Проект
  8. Инфраструктура и безопасность
  9. Спин-офф

Обязательно пройдитесь.

А теперь приступим к нашему предмету.

Теория и соседние материалы

Обзор платформ — WinForms и WPF с нуля.

Рецепты по каждому элементу — справочник WinForms и справочник WPF.

Аналог на Python — Tkinter — окна и виджеты.

Синтаксис C# — первая программа.


Навигация по примерам

Раздел Тема
Каркас WinForms winforms program.cs пример, application.run c#, statthread winforms
Каркас WPF wpf mainwindow xaml пример, initializecomponent, startupuri
Окно с текстом winforms label пример, wpf textblock, как сделать окно c#
Кнопка и MessageBox winforms button click, messagebox.show c#, wpf button click event
Поле ввода и имя winforms textbox get text, wpf textbox x:name, форма ввода c#
Конвертер °C → °F конвертер температуры winforms, tryparse c# textbox, курсовая калькулятор c#
CheckBox и RadioButton winforms checkbox, wpf radiobutton groupname, настройки форма c#
Список задач winforms listbox add item, wpf listbox пример, todo list c# gui
Форма входа winforms tablelayoutpanel, wpf grid passwordbox, форма логин c#
Меню winforms menustrip, wpf menu menuitem, statusbar c#
OpenFileDialog openfiledialog c#, microsoft.win32.openfiledialog wpf
Привязка WPF wpf binding textbox, datacontext пример, binding mode
Частые ошибки окно сразу закрывается winforms, net8.0-windows, invoke ui thread

WinForms и WPF — что выбрать для учебного проекта

WinForms WPF
Разметка Код C# или визуальный Designer в Visual Studio XAML + code-behind
Отрисовка GDI+, «родные» окна Windows DirectX, векторный UI
Привязка данных Базовая {Binding}, MVVM
Шаблон проекта dotnet new winforms dotnet new wpf
Когда удобнее Быстрая утилита, CRUD, legacy Кастомный UI, стили, анимации

Для первого окна подойдут оба стека. WinForms проще «увидеть результат в одном .cs файле»; WPF учит XAML — это пригодится в практикуме WPF.


Создание проекта

WinForms:

dotnet new winforms -n MyDesktopApp -o MyDesktopApp
cd MyDesktopApp
dotnet run

WPF:

dotnet new wpf -n MyWpfApp -o MyWpfApp
cd MyWpfApp
dotnet run

Разбор команд

Команда Смысл
dotnet new winforms Шаблон с Program.cs, Form1.cs, флагом UseWindowsForms в .csproj
dotnet new wpf Шаблон с App.xaml, MainWindow.xaml, флагом UseWPF
-n MyDesktopApp Имя проекта и namespace по умолчанию
-o MyDesktopApp Папка на диске
dotnet run Сборка и запуск; откроется пустое окно

Появится пустое окно — шаблон уже рабочий. Примеры ниже можно заменить содержимое Program.cs (WinForms) или MainWindow.xaml + MainWindow.xaml.cs (WPF).


Из чего состоит десктоп-приложение на C#

В консольной программе всё крутится вокруг Main() и Console.ReadLine(). В WinForms и WPF точка входа та же, но вместо текста в консоли — окно и цикл сообщений, который ждёт клики и ввод.

flowchart LR
  A[Main / App.xaml] --> B[Создание окна Form или Window]
  B --> C[Контролы Label Button TextBox]
  C --> D[Application.Run или Show]
  D --> E{Событие?}
  E -->|Click KeyDown| F[Обработчик C#]
  E -->|Закрытие| G[Выход]
  F --> D
Часть WinForms WPF Роль
Точка входа Program.Main() App.xamlStartupUri Запуск приложения
Главное окно Form Window Рамка с заголовком и кнопкой закрытия
Элемент UI Label, Button, TextBox То же + TextBlock, PasswordBox То, что видит пользователь
Событие button.Click += .. Click="OnClick" в XAML Реакция на действие
Цикл Application.Run(form) Внутри Application Программа жива, пока окно открыто
Диалог MessageBox.Show(..) MessageBox.Show(..) Всплывающее сообщение поверх окна

Пока цикл работает, код после Application.Run не выполняется — как mainloop() в Tkinter.


Словарь элементов за 30 секунд

Элемент WinForms WPF Зачем Как прочитать значение
Окно Form Window Главная рамка
Надпись Label Label, TextBlock Статический текст label.Text / {Binding}
Кнопка Button Button Действие по клику Click / command
Поле ввода TextBox TextBox Одна строка textBox.Text
Пароль TextBox + UseSystemPasswordChar PasswordBox Скрытый ввод PasswordBox.Password
Галочка CheckBox CheckBox Вкл/выкл Checked / IsChecked
Переключатель RadioButton RadioButton Один из нескольких Checked + группа
Список ListBox ListBox To-do, выбор строки SelectedIndex, Items
Меню MenuStrip Menu Файл, Справка обработчик пункта
Диалог MessageBox.Show MessageBox.Show OK, Yes/No возвращаемое значение

Компоновка WinForms: Location + Size, Dock, Anchor, TableLayoutPanel.
Компоновка WPF: Grid, StackPanel, DockPanel — см. справочник XAML.


Обязательный каркас WinForms

Любой пример WinForms ниже повторяет эту структуру. Запомните её — как import tkinter и mainloop() в Tkinter.

Скопируйте в Program.cs целиком (после dotnet new winforms):

Разбор каркаса WinForms — по строкам

Строка / блок Смысл
using System.Drawing; Типы Point, Size, Font, Color — координаты и оформление
using System.Windows.Forms; Form, Button, Application, MessageBox
namespace MyDesktopApp; Имя проекта из шаблона dotnet new; должно совпадать с .csproj
[STAThread] Один UI-поток для COM и контролов Windows; без атрибута возможны странные ошибки
ApplicationConfiguration.Initialize() Настройка DPI и стилей (.NET 6+); вызывают один раз в начале Main
new Form { .. } Главное окно; Text — заголовок в строке заголовка ОС
ClientSize = new Size(400, 300) Ширина × высота рабочей области без рамки окна
StartPosition = CenterScreen Окно по центру монитора при старте
Application.Run(form) Цикл сообщений; без этой строки окно мелькает и сразу закроется

Файл проекта (шаблон создаёт сам):

<TargetFramework>net8.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>

Если указать net8.0 без -windows, типы Form и Application не найдутся при сборке.

Что попробовать: добавьте form.MaximizeBox = false; — исчезнет кнопка «развернуть».


Обязательный каркас WPF

WPF делит UI на разметку (XAML) и код (C#). Окно описывают в двух связанных файлах.

MainWindow.xaml — замените содержимое после dotnet new wpf:

<Window x:Class="MyWpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Моё приложение"
        Height="300" Width="400"
        WindowStartupLocation="CenterScreen">
    <!-- Label, Button, TextBox — между открывающим и закрывающим Window -->
</Window>

MainWindow.xaml.cs:

namespace MyWpfApp;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

App.xaml (шаблон, обычно не трогают):

<Application x:Class="MyWpfApp.App"
             StartupUri="MainWindow.xaml">
</Application>

Разбор каркаса WPF — по частям

Часть Смысл
x:Class="MyWpfApp.MainWindow" Связь XAML с классом MainWindow в MainWindow.xaml.cs; имя должно совпадать
xmlns / xmlns:x Пространства имён XML — стандартные для WPF
Title, Height, Width Заголовок и размер окна (в отличие от WinForms ClientSize)
WindowStartupLocation="CenterScreen" Центрирование — аналог FormStartPosition.CenterScreen
partial class MainWindow : Window Класс окна; partial — вторая часть генерируется из XAML
InitializeComponent() Загружает XAML и создаёт поля для x:Name; не удаляйте
StartupUri="MainWindow.xaml" Какое окно открыть при старте

Что попробуйте: смените Title и перезапустите dotnet run — заголовок окна изменится без правки C#.


Стартовые окна

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


Минимальное окно с меткой

Задача: показать, что C# на .NET умеет открыть окно с текстом — минимум для проверки установки SDK и сдачи отчёта «программа с GUI».

Что получится: окно по центру экрана с одной надписью «Окно работает!».

WinForms — полный Program.cs

Символ | разделяет пары «подпись — маска».

Стек Класс Успешный результат
WinForms System.Windows.Forms.OpenFileDialog DialogResult.OK
WPF Microsoft.Win32.OpenFileDialog true

4. Мини-калькулятор сложения (WinForms)

Задача: два TextBox, кнопка «=», результат в Label — связка ввода, события и TryParse.

Смысл: результат на форме, без MessageBox — пользователь видит ошибку «Ошибка» в том же окне. Расширение до -, *, / — один обработчик и switch по оператору.


5. Привязка данных в WPF (простой уровень)

Задача: текст «Привет, …!» обновляется сам, пока пользователь печатает в поле — задел под MVVM.

Models/Person.cs:

namespace MyWpfApp.Models;

public sealed class Person
{
    public string Name { get; set; } = "Гость";
}

MainWindow.xaml:

<StackPanel Margin="20">
    
    
</StackPanel>

MainWindow.xaml.cs:

using MyWpfApp.Models;

public MainWindow()
{
    InitializeComponent();
    DataContext = new Person();
}

Разбор Binding

Конструкция Смысл
DataContext = new Person() Объект-источник для всех &#123;Binding ..&#125; на окне
&#123;Binding Name&#125; Свойство Person.Name
StringFormat='Привет, {0}!' Шаблон отображения
UpdateSourceTrigger=PropertyChanged Модель обновляется на каждый символ, не только при потере фокуса
Два &#123;Binding Name&#125; Одно свойство — два контрола; WPF синхронизирует их
Дальше — MVVM

В учебных проектах достаточно `DataContext` и простого класса.

В курсовой и production свойства выносят во ViewModel с `INotifyPropertyChanged` — см. Первая форма WPF — XAML, стили и шаблоны и практикум MVVM.


6. Подтверждение при закрытии окна

WinForms:

form.FormClosing += (_, e) =>
{
    if (MessageBox.Show("Закрыть приложение?", "Выход",
            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
        e.Cancel = true;
};

WPF — атрибут Closing="OnClosing" на Window и в обработчике e.Cancel = true при ответе No.

Смысл: крестик в заголовке по умолчанию закрывает окно сразу; Cancel = true отменяет закрытие — нужно для «Сохранить изменения?».


7. Шаблоны для своих проектов

Окно по центру

WinForms: StartPosition = FormStartPosition.CenterScreen.
WPF: WindowStartupLocation="CenterScreen".

Логика отдельно от формы

// Services/GreetingService.cs
public static class GreetingService
{
    public static string Build(string name) =>
        string.IsNullOrWhiteSpace(name) ? "Введите имя" : $"Здравствуй, {name.Trim()}!";
}

Кнопка вызывает GreetingService.Build(entry.Text) — форма остаётся тонкой; логику можно проверить unit-тестом без GUI. Это плюс на защите курсовой.


Частые ошибки и как исправить

Симптом Причина Решение
Окно мелькает и закрывается Нет Application.Run(form) Добавьте в конец Main перед закрывающей }
«Не найден тип Form» TFM net8.0 без -windows В .csproj: net8.0-windows
Ошибка CS0246 Window / Form Нет UseWindowsForms / UseWPF Флаги в .csproj из шаблона dotnet new
Контрол не виден Нет Controls.Add Каждый контрол добавьте на form или в panel
Кнопка срабатывает при старте Вызвали метод вместо ссылки Click += Handler, не Click += Handler()
XAML: имя не существует x:Class не совпадает с namespace MyApp.MainWindow в XAML = namespace MyApp + class MainWindow
UI «завис» на 5 секунд Thread.Sleep или тяжёлый цикл в Click await Task.Run(..) — см. Особенности разработки десктопных приложений
InvalidOperationException Обновление UI из фонового потока WinForms: control.Invoke(() => ..); WPF: Dispatcher.Invoke
25,5 не парсится Локаль Windows .Replace(',', '.') + InvariantCulture в TryParse

Маршрут изучения

Шаг Пример в статье Зачем Дальше
1 Каркас WinForms Понять Application.Run Windows Forms (WinForms) — теория WinForms
2 Окно + кнопка События и MessageBox Справочник по WinForms — элементы UI — справочник UI
3 TextBox + конвертер Ввод, парсинг, формула Лабораторная «калькулятор»
4 ListBox to-do Коллекция на форме Курсовая «список задач»
5 WPF Binding XAML и данные Первая форма WPF — XAML, стили и шаблоны — WPF с нуля
6 Практикум MVVM Клиент-сервер TaskDesk

См. также