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

Первое приложение с .NET CLI

Последнее обновление: 25.11.2023

Для создания графических интерфейсов с помощью платформы .NET применяются разные технологии — Window Forms, WPF, UWP.
Однако наиболее простой и удобной платформой до сих пор остается Window Forms или сокращенно WinForms. Данное руководство ставит своей целью дать понимание принципов создания графических интерфейсов с помощью технологии WinForms
и работы основных элементов управления.

Создадим первое приложение на C# и Windows Forms. Что нам для этого потребуется? Прежде всего необходим текстовый редактор для написания кода программы.
Можно взять любой понравившийся текстовый редактор, например, Visual Studio Code

Также для компиляции и запуска программы нам потребуется .NET SDK. Для его установки перейдем на официальный сайт по ссылке
.NET SDK

После установки .NET SDK для первого проекта определим какую-нибудь папку. Например, в моем случае это будет папка C:\dotnet\winforms\helloapp.
Откроем терминал/командную строку и перейдем к созданной папке проекта с помощью команды cd

cd C:\dotnet\winforms\helloapp

В данном случае мы для создания и запуска проекта мы будем использовать встроенную инфраструктуру .NET CLI, которая устанавливается вместе с .NET SDK.

Для создания проекта в .NET CLI применяется команда dotnet new, после которой указывается тип проWindows Formsекта. Для создания проекта
Windows Forms применяется шаблон — winforms. Поэтому введем в терминале команду dotnet new winforms

C:\Users\eugen>cd C:\dotnet\winforms\helloapp

C:\dotnet\winforms\helloapp>dotnet new winforms
Шаблон "Приложение Windows Forms" успешно создан.

Идет обработка действий после создания...
Восстановление C:\dotnet\winforms\helloapp\helloapp.csproj:
  Определение проектов для восстановления...
  Восстановлен C:\dotnet\winforms\helloapp\helloapp.csproj (за 1,04 sec).
Восстановление выполнено.



C:\dotnet\winforms\helloapp>

После выполнения этой команды у нас будет создан следующий проект:

Структура проекта Windows Forms

Рассмотрим базовую структуру простейшего стандартного проекта Windows Forms:

  • helloapp.csproj: стандартный файл проекта C#, который соответствует назанию проекта (по умолчанию названию каталога) и описывает все его настройки.

  • helloapp.csproj.user: дополнительный файл проекта C#, который хранит специфичные для текущего пользователя настройки.

  • Form1.cs: содержит класс формы, которая по умолчанию запускается при старте приложения

  • Form1.Designer.cs: он содержит определение компонентов формы, добавленных
    на форму в графическом дизайнере (графический дизайнер Windows Forms на данный момент официально доступен только в Visual Studio)

  • Program.cs: определяет класс Program, который запускается при старте приложения и запускает форму Form1

Например, посмотрим на содержимое файла helloapp.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

</Project>

Для компиляции приложения Windows Forms указаны следующие настройки:

  • OutputType: определяет выходной тип проекта. Должен иметь значение WinExe — то есть выполняемое приложение с
    расширением exe под Windows

  • TargetFramework: определяет применяемую для компиляции версию фреймворка .NET. Поскольку при создании проекта
    была выбрана версия .NET 8, а сам проект зависит от компонентов Windows, то здесь должно быть значение net7.0-windows

  • Nullable: подключает в проект функционалность ссылочных nullable-типов

  • UseWindowsForms: указывает, будет ли проект использовать Windows Forms (для этого устанавливается значение true)

  • ImplicitUsings: подключает в проект функциональность неявно подключаемых глобальных пространств имен

Запуск проекта

Проект по умолчанию не представляет какой-то грандиозной функциональности, тем не менее этот проект мы уже можем запустить. Итак, запустим проект. Для этого выполним команду
dotnet run

C:\dotnet\winforms\helloapp>dotnet run

При запуске запускается графическая форма, код которой определяет класс Form1:

Первое приложение на Windows Forms на С# с .NET CLI

Запуск приложения

Файл Program.cs определяет точку входа в приложение:

namespace helloapp;

static class Program
{
    [STAThread]
    static void Main()
    {
        ApplicationConfiguration.Initialize();
        Application.Run(new Form1());
    }    
}

Метод Main снабжен атрибутом [STAThread]. Этот атрибут, грубого говоря,
необходим для корректной работы компонентов Windows. В самом методе сначала вызывается метод

ApplicationConfiguration.Initialize()

который устанавливает некоторую базовую конфигурацию приложения

Затем вызывается метод

Application.Run(new Form1());

в который передается объект отображаемой по умолчанию на экране формы.

То есть, когда мы запустим приложение, сработает метод Main, в котором будет вызван метод Application.Run(new Form1()),
благодаря чему мы увидим форму Form1 на экране.

Определение формы

Теперь посмотрим на определение формы и немного изменим его. Для этого откроем файл Form1.cs в текстовом редакторе. По умолчанию он выглядит следующим образом:

namespace helloapp;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
}

Класс формы — Form1 представляет графическую форму — фактически то окно, которое мы увидим на экране при запуске проекта.

Этот класс определяется как частичный (с модификатором partial) и наследуется от встроенного класса Form,
который содержит базовую функциональность форм.

В самом классе Form1 определен по умолчанию только конструктор, где вызывается метод InitializeComponent(), который выполняет инициализацию компонентов формы из файла дизайнера
Form1.Designer.cs. По сути именно код этого файла передается выше через вызов InitializeComponent()

Теперь изменим его код следующим образом:

namespace helloapp;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        // определяем кнопку
        Button button = new Button();
        // текст кнопки
        button.Text ="Click";
        // положение кнопки
        button.Location = new Point(50, 50);
        // размер кнопки
        button.Size = new Size { Width = 80, Height = 30 };
        // обработчик нажатия кнопки
        button.Click += (o, e) => MessageBox.Show("Hello METANIT.COM!");
        // добавление кнопки на форму
        this.Controls.Add(button);
    }
}

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

Первое приложение на Windows Forms на С#

Введение

Разработка оконных приложений – это создание программ с графическим интерфейсом пользователя (GUI), которые запускаются на операционной системе Windows. C# (произносится как «си-шарп») — мощный, типобезопасный объектно-ориентированный язык программирования, разработанный Microsoft, который отлично подходит для создания разнообразных приложений, включая настольные.

Выбор инструментария

Для разработки настольных приложений в C# обычно используются:

  • Windows Forms (WinForms): Подходит для традиционных настольных приложений с богатым пользовательским интерфейсом. Легко осваивается новичками.
  • Windows Presentation Foundation (WPF): Предлагает более современный подход к созданию GUI с развитыми возможностями по работе с графикой, анимацией и стилями.

Основы Windows Forms

Windows Forms — это библиотека классов в .NET Framework, предназначенная для быстрой разработки приложений с графическим интерфейсом. Она предлагает большое количество готовых элементов управления (кнопки, текстовые поля, метки и т.д.), что упрощает создание классических настольных приложений.

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

  1. Установка Visual Studio: Сначала установите Visual Studio. Выберите рабочую нагрузку “.NET desktop development”.
  2. Создание нового проекта: Откройте Visual Studio и выберите “Создать новый проект”. Выберите “Windows Forms App (.NET Framework)” и нажмите “Далее”.
  3. Настройка проекта: Введите имя и расположение проекта. Нажмите “Создать”.

Работа с формой

После создания проекта перед вами откроется главная форма приложения (Form1). Это основное окно вашего приложения.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
}

Добавление элементов управления

  1. Инструменты: На боковой панели “Инструменты” найдите элементы, такие как Button, Label, TextBox и перетащите их на форму.
  2. Настройка свойств: Выберите элемент на форме и настройте его свойства в окне “Свойства”. Например, измените текст кнопки или метки.

Пример: Создание простого приложения

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

  1. Добавление элементов: Добавьте на форму Button и Label.
  2. Изменение свойств: Измените свойство Text кнопки на “Нажми меня” и метки на “Привет, мир!”.
  3. Добавление события: Дважды кликните по кнопке в дизайнере. Это создаст событие click для кнопки.
private void button1_Click(object sender, EventArgs e)
{
    label1.Text = "Привет, C#!";
}

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

Компиляция и запуск

Чтобы запустить приложение, нажмите кнопку “Запуск” (зеленый треугольник) на панели инструментов. Окно вашего приложения отобразится, и вы сможете взаимодействовать с элементами управления.

Windows Presentation Foundation (WPF)

Введение в WPF

WPF — это современная система для создания настольных приложений Windows с расширенной поддержкой графики, связывания данных и многих других функций. WPF использует XAML (eXtensible Application Markup Language) для определения интерфейса, что обеспечивает разделение логики приложения и его визуальной части.

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

  1. Создание проекта: Аналогично WinForms, выберите “Создать новый проект”, но на этот раз выберите “WPF App (.NET Framework)”.
  2. Работа с XAML: В основном окне проекта (обычно MainWindow.xaml) вы увидите XAML-код. Это язык разметки, используемый для создания интерфейса в WPF.
<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <!-- Элементы интерфейса -->
    </Grid>
</Window>

Основные компоненты интерфейса в WPF

В XAML элементы интерфейса организуются в древовидной структуре. Вы можете добавлять кнопки, метки, текстовые поля и другие элементы управления, а также устанавливать их свойства прямо в XAML.

Пример: Создание интерактивного интерфейса в WPF

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

при нажатии на кнопку.

  1. Добавление элементов в XAML:
    <Grid>
     <Button x:Name="myButton" Content="Нажми меня" Click="myButton_Click" />
     <TextBlock x:Name="myTextBlock" Text="Привет, мир!" />
    </Grid>
    
  2. Обработка событий:
    В коде C# (например, в файле MainWindow.xaml.cs) добавьте обработчик события для кнопки.
private void myButton_Click(object sender, RoutedEventArgs e)
{
    myTextBlock.Text = "Привет, WPF!";
}

Здесь, при нажатии на кнопку, метод myButton_Click вызывается, и текст в TextBlock изменяется.

Стилизация и макет

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

Продвинутые техники в WPF

Привязка данных (Data Binding)

Привязка данных — ключевая особенность WPF, позволяющая устанавливать соединения между элементами UI и логикой приложения (например, классами данных).

Основы привязки данных

В XAML привязка данных осуществляется с помощью синтаксиса {Binding}. Например, если у вас есть класс Person с свойством Name, вы можете привязать это свойство к TextBox таким образом:

<TextBox Text="{Binding Name}" />

Для работы привязки необходимо задать контекст данных (DataContext) — обычно это делается в коде C#:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new Person() { Name = "Алиса" };
    }
}

public class Person
{
    public string Name { get; set; }
}

Использование Ресурсов и Стилей

Ресурсы в WPF — это определения объектов, которые можно использовать в нескольких местах приложения. Стили в WPF позволяют определять внешний вид и поведение элементов управления.

Пример стиля
<Window.Resources>
    <Style x:Key="MyButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="Navy"/>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Padding" Value="10"/>
        <Setter Property="Margin" Value="5"/>
    </Style>
</Window.Resources>
<Button Style="{StaticResource MyButtonStyle}">Кнопка</Button>

Архитектура MVVM

MVVM (Model-View-ViewModel) — это шаблон проектирования, идеально подходящий для WPF. Он разделяет приложение на три основные части:

  • Модель (Model): Классы данных и логики приложения.
  • Представление (View): XAML-код интерфейса.
  • ViewModel: Посредник между View и Model, обрабатывает логику интерфейса и привязку данных.
Пример использования MVVM
  1. ViewModel: Создайте класс ViewModel с необходимыми свойствами и командами.
    public class MainViewModel : INotifyPropertyChanged
    {
        private string _name;
        public string Name
        {
            get => _name;
            set
            {
                _name = value;
                OnPropertyChanged(nameof(Name));
            }
        }
    
        // Реализация INotifyPropertyChanged...
    }
    
  2. Привязка в XAML:
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <TextBox Text="{Binding Name}" />
    </Grid>
    

Интеграция с другими технологиями

Разработка оконных приложений на C# не ограничивается только созданием интерфейса. Часто требуется интеграция с базами данных, веб-сервисами, файловыми системами и другими приложениями.

Работа с базами данных

  • Entity Framework: Популярный ORM (Object-Relational Mapping) фреймворк для интеграции с базами данных.
  • ADO.NET: Более низкоуровневый способ работы с базами данных для тех случаев, когда требуется больше контроля над процессом.

Сетевое взаимодействие

  • HttpClient: Для выполнения HTTP-запросов к веб-сервисам.
  • SignalR: Для реализации веб-сокетов и двустороннего общения между клиентом и сервером.

Заключение

Разработка оконных приложений в C# — это глубокая и многогранная область, включающая в себя различные подходы и технологии. От WinForms, идеально подходящих для простых и традиционных приложений, до WPF с его расширенными возможностями по созданию динамичных и визуально привлекательных интерфейсов. Понимание архитектуры MVVM, привязки данных и стилей поможет вам в создании мощных и легко поддерживаемых приложений. Интеграция с базами данных, веб-сервисами и использование различных библиотек и фреймворков откроют перед вами практически неограниченные возможности для создания качественных настольных приложений.

C# и его экосистема постоянно развиваются, поэтому всегда есть новые вещи, которые можно изучить и применить в своих проектах. Счастливого кодирования!

Время чтения: 5 минут

Превью к статье о создании C++ Windows Forms проекта

Windows Forms — интерфейс программирования приложений, отвечающий за графический интерфейс пользователя. Он является частью .Net Framework и создан для того, чтобы упростить взаимодействие пользователя с элементами Win API. Причём не просто упростить, а буквально полностью скрыть низкоуровневое взаимодействие с графическими элементами путём создания набора базовых компонентов и классов. При этом используемые классы не привязаны к языку разработки, благодаря чему данный проект может использоваться как на родном для Microsoft C#, так и на других языках, например, C++, VB Net и F#. Но не смотря на свою кроссплатформенность в мире языков программирования, Windows Forms проекты легко создаются на C#, однако при попытке создания проекта на C++ возникает множество проблем.

Шаг 0. А вдруг получится сразу?

В настоящее время IDE, поддерживающих Windows forms, не так много — буквально одна только Visual Studio, более известная как просто «студия». Поэтому будем рассматривать создание и решение проблем именно в этой среде разработки. Первым шагом запустим студию, начнём создавать новый проект и попытаемся найти Windows forms проект для C++:

Создаём новый проект в студии

Создаём новый проект в студии

Ищем Winfows Forms для C++

Ищем Winfows Forms для C++

Если у вас более старая версия Visual Studio, то интерфейс будет выглядеть немного иначе, однако данная функциональность будет той же. Также не исключено, что у Вас может быть данный тип проекта для C++ (на некоторых версиях формы для C++ были доступны сразу после установки IDE). Если же у Вас, как и у нас поиск не дал нужных результатов, то переходим к следующему шагу.

Шаг 1. Создание CLR проекта

Поскольку непосредственно Windows Forms проекта у нас не оказалось, мы обхитрим студию и создадим пустой CLR проект на С++. Для этого в том же окне поиска необходимо найти и выбрать Новый CLR проект, ввести имя (если нужно, то поменять директорию расположения проекта) и немного подождать, пока студия сделает свою работу.

Ищем пустой CLR проект (.Net Framework)

Ищем пустой CLR проект (.Net Framework)

Создаём новый пустой CLR проект

Создаём новый пустой CLR проект

В результате Visual Stido создаст новый C++ CLR проект, который будет выглядеть примерно так:

Результат создания нового CLR проекта

Результат создания нового CLR проекта

Шаг 2. Добавить форму

Чтобы сделать CLR проект проектом Windows Forms, нужно просто добавить в него форму. Для этого в верхнем меню нужно выбрать ПроектДобавить новый элемент и в появившемся окне выбрать категорию Visual C++UI и затем выбрать Форма Windows Forms.

Проект - data-lazy-src=

Проект -> Добавить новый элемент

Visual C++ - data-lazy-src=

Visual C++ -> UI -> Форма Windows Forms

После данной операции нас ждёт разочарование в виде ошибки Исключение из HRESULT: 0x8000000A:

Вместо формы получили ошибку

Вместо формы получили ошибку

Шаг 3. Исправляем появившуюся ошибку

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

#include "Form1.h"

#include <Windows.h>

using namespace имя_вашего_проекта;

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
    Application::EnableVisualStyles();
    Application::SetCompatibleTextRenderingDefault(false);
    Application::Run(gcnew Form1);
    return 0;
}

В результате код файла Form1.cpp будет выглядеть следующим образом:

Добавление основной программы к форме

Добавление основной программы к форме

Шаг 4. Переоткрыть проект

Всё, что теперь осталось сделать — это закрыть текущее решение, а затем открыть его снова. Для этого можно закрыть саму студию, а можно выбрать в верхнем меню ФайлЗакрыть решение, после чего в появившемся окне выбрать только что созданный проект и открыть его заново.

Форма создалась, можно добавлять компоненты

Форма создалась, можно добавлять компоненты

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

Программист, сооснователь programforyou.ru, в постоянном поиске новых задач и алгоритмов

Языки программирования: Python, C, C++, Pascal, C#, Javascript

Выпускник МГУ им. М.В. Ломоносова

В этой статье показано, как разработать простое приложение Windows Presentation Foundation (WPF), которое включает общие для большинства приложений WPF элементы: расширяемый язык разметки приложений (XAML), код, определение приложения, элементы управления, макет интерфейса, привязки данных и стили.

Это пошаговое руководство включает следующие шаги:

  • Использование XAML для разработки пользовательского интерфейса (UI) приложения.

  • Написание кода, определяющего поведение приложения.

  • Создание определения приложения для управления приложением.

  • Добавление элементов управления и создание макета для пользовательского интерфейса приложения.

  • Создания таблиц стилей для согласованного отображения пользовательского интерфейса в приложении.

  • Использование привязки к данным для заполнения пользовательского интерфейса на основе данных.

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

Предварительные требования

Visual Studio 2017 или более поздней версии.

Дополнительные сведения об установке последней версии Visual Studio, см. в разделе установка Visual Studio.

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

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

  1. Создайте новый проект приложения WPF в Visual Basic или Visual C# с именем ExpenseIt:

    1. Откройте Visual Studio и выберите Файл > Создать > Проект.

      Откроется диалоговое окно Новый проект.

    2. В разделе Установленные, разверните Visual C# или Visual Basic, а затем выберите Windows Desktop.

    3. Выберите шаблон Приложение WPF (.NET Framework). Введите имя ExpenseIt , а затем нажмите ОК.

      Диалоговое окно нового проекта с помощью выбранного приложения WPF

      Visual Studio создаст проект и откроет конструктор для окна приложения по умолчанию с именем MainWindow.xaml.

  2. Откройте Application.xaml (Visual Basic) или App.xaml (C#).

    Этот файл XAML определяет WPF-приложение и все его ресурсы. Этот файл также используется для указания объекта пользовательского интерфейса, автоматически отображаемого при запуске приложения; в данном случае это MainWindow.xaml.

    В C# он должен выглядеть следующим образом.

    <Application x:Class="ExpenseIt.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         StartupUri="MainWindow.xaml">
        <Application.Resources>
             
        </Application.Resources>
    </Application>
    
  3. Откройте MainWindow.xaml.

    Этот файл XAML представляет главное окно приложения и отображает созданное содержимое страниц. Класс Window определяет свойства окна, такие как заголовок, размер и значок, и обрабатывает события (например, открытие и закрытие окна).

  4. Замените Window на элемент NavigationWindow, как показано в следующем XAML:

    <NavigationWindow x:Class="ExpenseIt.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         ...
    </NavigationWindow>
    

    Это приложение осуществляет переход к различному содержимому вводимых пользователем данных. Вот почему основное Window должно быть заменено на NavigationWindow. NavigationWindow наследует все свойства Window. Дополнительные сведения см. в разделе Общие сведения о переходах.

  5. Измените следующие свойства NavigationWindow:

    • Задайте для свойства Title значение ExpenseIt.

    • Задайте для свойства Width значение 500 пикселей.

    • Задайте для свойства Height значение 350 пикселей.

    • Удалите Grid между тегами NavigationWindow.

    В C# XAML должен выглядеть следующим образом.

    <NavigationWindow x:Class="ExpenseIt.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ExpenseIt" Height="350" Width="500">
        
    </NavigationWindow>
    
  6. Откройте MainWindow.xaml.vb или MainWindow.xaml.cs.

    Этот файл является файлом кода, который содержит код для обработки событий, объявленных в MainWindow.xaml. Этот файл содержит разделяемый класс для окна, определенного в XAML-коде.

  7. Если вы используете C#, измените класс MainWindow, чтобы он наследовал от NavigationWindow. (В Visual Basic это происходит автоматически при изменении окна в XAML.)

    Код должен выглядеть следующим образом:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace ExpenseIt
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : NavigationWindow
        {
            public MainWindow()
            {
                InitializeComponent();
            }
        }
    }
    

Добавление файлов в приложение

В этом разделе вы добавите в приложение две страницы и изображение.

  1. Добавьте новую страницу WPF в проект и назовите её ExpenseItHome.xaml:

    1. В обозревателе решений, щелкните правой кнопкой мыши ExpenseIt и выберите Добавить > Страница.

    2. В окне Добавление нового элемента, уже выбран шаблон Страница (WPF). Введите имя ExpenseItHome, а затем нажмите Добавить.

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

  2. Откройте ExpenseItHome.xaml.

  3. Задайте для Title значение ExpenseIt - Home.

    В C# XAML должен выглядеть следующим образом.

    <Page x:Class="ExpenseIt.ExpenseItHome"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
          mc:Ignorable="d" 
          d:DesignHeight="350" d:DesignWidth="500"
        Title="ExpenseIt - Home">
    
        <Grid>
            
        </Grid>
    </Page>
    
  4. Откройте MainWindow.xaml.

  5. Задайте для Source у NavigationWindow значение ExpenseItHome.xaml.

    Этот параметр задает ExpenseItHome.xaml в качестве первой страницы, открываемой при запуске приложения.

    В C# XAML должен выглядеть следующим образом.

    <NavigationWindow x:Class="ExpenseIt.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ExpenseIt" Height="350" Width="500" Source="ExpenseItHome.xaml">
        
    </NavigationWindow>
    
    Tip

    Можно также задать свойство Источник в категории свойств окна Разное.

    Свойство Source в окне "Свойства"

  6. Добавьте другую страницу WPF в проект и назовите её ExpenseReportPage.xaml:

    1. В обозревателе решений, щелкните правой кнопкой мыши ExpenseIt и выберите Добавить > Страница.

    2. В окне Добавление нового элемента, уже выбран шаблон Страница (WPF). Введите имя ExpenseReportPage, а затем нажмите Добавить.

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

  7. Откройте файл ExpenseReportPage.xaml.

  8. Задайте для Title значение ExpenseIt - View Expense.

    В C# XAML должен выглядеть следующим образом.

    <Page x:Class="ExpenseIt.ExpenseReportPage"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
          mc:Ignorable="d" 
          d:DesignHeight="350" d:DesignWidth="500"
        Title="ExpenseIt - View Expense">
    
        <Grid>
            
        </Grid>
    </Page>
    
  9. Откройте ExpenseItHome.xaml.vb и ExpenseReportPage.xaml.vb, или ExpenseItHome.xaml.cs и ExpenseReportPage.xaml.cs.

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

    Код должен выглядеть следующим образом для ExpenseItHome:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace ExpenseIt
    {
        /// <summary>
        /// Interaction logic for ExpenseItHome.xaml
        /// </summary>
        public partial class ExpenseItHome : Page
        {
            public ExpenseItHome()
            {
                InitializeComponent();
            }
        }
    }
    

    И следующим образом для ExpenseReportPage:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace ExpenseIt
    {
        /// <summary>
        /// Interaction logic for ExpenseReportPage.xaml
        /// </summary>
        public partial class ExpenseReportPage : Page
        {
            public ExpenseReportPage()
            {
                InitializeComponent();
            }
        }
    }
    
  10. Добавьте изображение с именем watermark.png в проект. Можно создать собственное изображение, скопировать файл из примера кода или загрузить его здесь.

    1. Щелкните правой кнопкой мыши узел проекта и выберите добавить > существующий элемент.

    2. В окне Добавить существующий элемент перейдите к файлу изображения, который вы хотите использовать, а затем выберите добавить.

Построение и запуск приложения

  1. Чтобы построить и запустить приложение, нажмите клавишу F5 или выберите начать отладку из меню Отладка.

  2. Закройте приложение, чтобы вернуться в Visual Studio.

Создание макета

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

  • Canvas
  • DockPanel
  • Grid
  • StackPanel
  • VirtualizingStackPanel
  • WrapPanel

Каждый из этих элементов управления макетом поддерживает специальный тип макета дочерних элементов. Размер страницы ExpenseIt может быть изменен, и каждая страница имеет элементы, которые упорядочены по горизонтали и вертикали рядом с другими элементами. Следовательно, Grid является идеальным элементом макета для приложения.

В разделе создается таблица с одним столбцом и тремя строками, с полями шириной 10 пикселей, путем добавления определений столбцов и строк для Grid в ExpenseItHome.xaml.

  1. Откройте ExpenseItHome.xaml.

  2. Задайте для Margin у Grid значение «10,0,10,10», которое соответствует величине полей слева, сверху, справа и снизу:

    <Grid Margin="10,0,10,10">
    
    Tip

    Можно также задать Margin в категории макет свойств элемента:

    Значения полей в окне "Свойства"

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

    <Grid.ColumnDefinitions>
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    

    Свойство Height двух строк имеет значение Auto, означающее, что размер строки определяется её содержимым. Значение по умолчанию для Height равно Star; это означает, что высота строки — это взвешенная пропорция доступного пространства. Например, если две строки имеют Height равную «*», каждый из них имеет высоту в размере половины доступного пространства.

    Ваш Grid теперь должен иметь следующий XAML:

    <Grid Margin="10,0,10,10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
    </Grid>
    

Добавление элементов управления

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

Чтобы создать этот пользовательский интерфейс, нужно добавить следующие элементы для ExpenseItHome.xaml:

  • ListBox (для получения списка пользователей).
  • Label (для заголовков списка).
  • Button (чтобы при её нажатии вывести отчет по расходам для человека, выбранного в списке).

Каждый элемент управления помещается в строке Grid, в соответствии с заданным значением вложенного свойства зависимостей Grid.Row. Дополнительные сведения о вложенных свойствах см. в разделе Свойства зависимостей.

  1. Откройте ExpenseItHome.xaml.

  2. Добавьте следующий XAML где-то между тегов Grid:

    
    <!-- People list -->
    <Border Grid.Column="0" Grid.Row="0" Height="35" Padding="5" Background="#4E87D4">
        <Label VerticalAlignment="Center" Foreground="White">Names</Label>
    </Border>
    <ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1">
        <ListBoxItem>Mike</ListBoxItem>
        <ListBoxItem>Lisa</ListBoxItem>
        <ListBoxItem>John</ListBoxItem>
        <ListBoxItem>Mary</ListBoxItem>
    </ListBox>
    
    <!-- View report button -->
    <Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,0" Width="125" Height="25" HorizontalAlignment="Right">View</Button>
    
    Tip

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

  3. Выполните сборку и запуск приложения.

Добавить изображение и заголовок

В этом разделе вы обновите интерфейс пользователя домашней страницы, добавив изображение и заголовок страницы.

  1. Откройте ExpenseItHome.xaml.

  2. Добавьте еще один столбец в ColumnDefinitions с фиксированным значением Width, равным 230 пикселей:

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="230" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    
  3. Добавьте другую строку в RowDefinitions:

    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
        <RowDefinition />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    
  4. Переместите элементы управления во второй столбец, задав свойству Grid.Column значение 1, в каждом из трех элементов управления (Border, ListBox и Button).

  5. Переместите каждый элемент управления вниз на одну строку, увеличивая на 1 значение его свойства Grid.Row.

    XAML для трех элементов управления теперь выглядит следующим образом:

      <Border Grid.Column="1" Grid.Row="1" Height="35" Padding="5" Background="#4E87D4">
          <Label VerticalAlignment="Center" Foreground="White">Names</Label>
      </Border>
      <ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2">
          <ListBoxItem>Mike</ListBoxItem>
          <ListBoxItem>Lisa</ListBoxItem>
          <ListBoxItem>John</ListBoxItem>
          <ListBoxItem>Mary</ListBoxItem>
      </ListBox>
    
      <!-- View report button -->
      <Button Grid.Column="1" Grid.Row="3" Margin="0,10,0,0" Width="125"
    Height="25" HorizontalAlignment="Right">View</Button>
    
  6. Присвойте свойству Background у Grid в качестве значения файл изображения watermark.png, добавив следующий XAML где-то между <Grid> и </Grid>:

    <Grid.Background>
        <ImageBrush ImageSource="watermark.png"/>
    </Grid.Background>
    
  7. Перед элементом Border добавьте Label с содержимым «View Expense Report». Это заголовок страницы.

    <Label Grid.Column="1" VerticalAlignment="Center" FontFamily="Trebuchet MS" 
            FontWeight="Bold" FontSize="18" Foreground="#0066cc">
        View Expense Report
    </Label>
    
  8. Выполните сборку и запуск приложения.

На следующем рисунке показан полученный результат:

Снимок экрана примера ExpenseIt

Добавьте код для обработки событий

  1. Откройте ExpenseItHome.xaml.

  2. Добавьте обработчик события Click у Button. Дополнительные сведения см. в разделе Создание простого обработчика событий.

      <!-- View report button -->
      <Button Grid.Column="1" Grid.Row="3" Margin="0,10,0,0" Width="125"
    Height="25" HorizontalAlignment="Right" Click="Button_Click">View</Button>
    
  3. Откройте ExpenseItHome.xaml.vb или ExpenseItHome.xaml.cs.

  4. Добавьте следующий код, в класс ExpenseItHome, чтобы добавить обработчик события щелчка кнопки. Обработчик событий открывает страницу ExpenseReportPage.

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        // View Expense Report
        ExpenseReportPage expenseReportPage = new ExpenseReportPage();
        this.NavigationService.Navigate(expenseReportPage);
    }
    

Создание пользовательского интерфейса для страницы ExpenseReportPage

ExpenseReportPage.xaml отображает отчет по расходам для человека, выбранного на странице ExpenseItHome. В этом разделе вы создадите пользовательский интерфейс для ExpenseReportPage. Вы также добавите фон и цвет заливки для различных элементов пользовательского интерфейса.

  1. Откройте файл ExpenseReportPage.xaml.

  2. Добавьте следующий XAML между тегами Grid:

     <Grid.Background>
         <ImageBrush ImageSource="watermark.png" />
     </Grid.Background>
     <Grid.ColumnDefinitions>
         <ColumnDefinition Width="230" />
         <ColumnDefinition />
     </Grid.ColumnDefinitions>
     <Grid.RowDefinitions>
         <RowDefinition Height="Auto" />
         <RowDefinition />
     </Grid.RowDefinitions>
    
    
     <Label Grid.Column="1" VerticalAlignment="Center" FontFamily="Trebuchet MS" 
     FontWeight="Bold" FontSize="18" Foreground="#0066cc">
         Expense Report For:
     </Label>
     <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
         <Grid.ColumnDefinitions>
             <ColumnDefinition />
             <ColumnDefinition />
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto" />
             <RowDefinition Height="Auto" />
             <RowDefinition />
         </Grid.RowDefinitions>
    
         <!-- Name -->
         <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Orientation="Horizontal">
             <Label Margin="0,0,0,5" FontWeight="Bold">Name:</Label>
             <Label Margin="0,0,0,5" FontWeight="Bold"></Label>
         </StackPanel>
    
         <!-- Department -->
         <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Orientation="Horizontal">
             <Label Margin="0,0,0,5" FontWeight="Bold">Department:</Label>
             <Label Margin="0,0,0,5" FontWeight="Bold"></Label>
         </StackPanel>
    
         <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" VerticalAlignment="Top" 
               HorizontalAlignment="Left">
             <!-- Expense type and Amount table -->
             <DataGrid  AutoGenerateColumns="False" RowHeaderWidth="0" >
                 <DataGrid.ColumnHeaderStyle>
                     <Style TargetType="{x:Type DataGridColumnHeader}">
                         <Setter Property="Height" Value="35" />
                         <Setter Property="Padding" Value="5" />
                         <Setter Property="Background" Value="#4E87D4" />
                         <Setter Property="Foreground" Value="White" />
                     </Style>
                 </DataGrid.ColumnHeaderStyle>
                 <DataGrid.Columns>
                     <DataGridTextColumn Header="ExpenseType" />
                     <DataGridTextColumn Header="Amount"  />
                 </DataGrid.Columns>
             </DataGrid>
         </Grid>
     </Grid>
    

    Этот пользовательский интерфейс аналогичен ExpenseItHome.xaml, за исключением того, что данные отчета отображаются в DataGrid.

  3. Выполните сборку и запуск приложения.

  4. Нажмите кнопку View.

    Появится страница отчета по расходам. Также обратите внимание на то, что кнопка возврата активна.

На следующем рисунке показаны элементы пользовательского интерфейса, добавленные в ExpenseReportPage.xaml.

Снимок экрана примера ExpenseIt

Определение стиля элементов управления

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

  1. Откройте Application.xaml или App.xaml.

  2. Добавьте следующий XAML между тагами Application.Resources:

    
    <!-- Header text style -->
    <Style x:Key="headerTextStyle">
        <Setter Property="Label.VerticalAlignment" Value="Center"></Setter>
        <Setter Property="Label.FontFamily" Value="Trebuchet MS"></Setter>
        <Setter Property="Label.FontWeight" Value="Bold"></Setter>
        <Setter Property="Label.FontSize" Value="18"></Setter>
        <Setter Property="Label.Foreground" Value="#0066cc"></Setter>
    </Style>
    
    <!-- Label style -->
    <Style x:Key="labelStyle" TargetType="{x:Type Label}">
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="FontWeight" Value="Bold" />
        <Setter Property="Margin" Value="0,0,0,5" />
    </Style>
    
    <!-- DataGrid header style -->
    <Style x:Key="columnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
        <Setter Property="Height" Value="35" />
        <Setter Property="Padding" Value="5" />
        <Setter Property="Background" Value="#4E87D4" />
        <Setter Property="Foreground" Value="White" />
    </Style>
    
    <!-- List header style -->
    <Style x:Key="listHeaderStyle" TargetType="{x:Type Border}">
        <Setter Property="Height" Value="35" />
        <Setter Property="Padding" Value="5" />
        <Setter Property="Background" Value="#4E87D4" />
    </Style>
    
    <!-- List header text style -->
    <Style x:Key="listHeaderTextStyle" TargetType="{x:Type Label}">
        <Setter Property="Foreground" Value="White" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="HorizontalAlignment" Value="Left" />
    </Style>
    
    <!-- Button style -->
    <Style x:Key="buttonStyle" TargetType="{x:Type Button}">
        <Setter Property="Width" Value="125" />
        <Setter Property="Height" Value="25" />
        <Setter Property="Margin" Value="0,10,0,0" />
        <Setter Property="HorizontalAlignment" Value="Right" />
    </Style>
    

    Этот код XAML добавляет следующие стили:

    • headerTextStyle: Для форматирования заголовка страницы Label.

    • labelStyle: Для форматирования Label.

    • columnHeaderStyle: Для форматирования DataGridColumnHeader.

    • listHeaderStyle: Для форматирования Border заголовка списка.

    • listHeaderTextStyle: Для форматирования Label в заголовке списка.

    • buttonStyle: Для форматирования Button на ExpenseItHome.xaml.

    Обратите внимание на то, что стили представляют собой ресурсы и являются дочерними для свойства Application.Resources. Здесь стили применяются ко всем элементам в приложении. Пример использования ресурсов в приложении .NET Framework см. в разделе использование ресурсов приложения.

  3. Откройте ExpenseItHome.xaml.

  4. Замените весь код в Grid на следующий XAML:

       <Grid.Background>
           <ImageBrush ImageSource="watermark.png"  />
       </Grid.Background>
      
       <Grid.ColumnDefinitions>
           <ColumnDefinition Width="230" />
           <ColumnDefinition />
       </Grid.ColumnDefinitions>
       
       <Grid.RowDefinitions>
           <RowDefinition/>
           <RowDefinition Height="Auto"/>
           <RowDefinition />
           <RowDefinition Height="Auto"/>
       </Grid.RowDefinitions>
    
       <!-- People list -->
      
       <Label Grid.Column="1" Style="{StaticResource headerTextStyle}" >
           View Expense Report
       </Label>
       
       <Border Grid.Column="1" Grid.Row="1" Style="{StaticResource listHeaderStyle}">
           <Label Style="{StaticResource listHeaderTextStyle}">Names</Label>
       </Border>
       <ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2">
           <ListBoxItem>Mike</ListBoxItem>
           <ListBoxItem>Lisa</ListBoxItem>
           <ListBoxItem>John</ListBoxItem>
           <ListBoxItem>Mary</ListBoxItem>
       </ListBox>
    
       <!-- View report button -->
       <Button Grid.Column="1" Grid.Row="3" Click="Button_Click" Style="{StaticResource buttonStyle}">View</Button>
    

    Свойства, определяющие внешний вид элементов управления, такие как VerticalAlignment и FontFamily, при применении стилей удаляются и заменяются. Например headerTextStyle применяется к Label «View Expense Report».

  5. Откройте файл ExpenseReportPage.xaml.

  6. Замените весь код в Grid на следующий XAML:

      <Grid.Background>
          <ImageBrush ImageSource="watermark.png" />
      </Grid.Background>
      <Grid.ColumnDefinitions>
          <ColumnDefinition Width="230" />
          <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
      </Grid.RowDefinitions>
    
    
      <Label Grid.Column="1" Style="{StaticResource headerTextStyle}">
          Expense Report For:
      </Label>
      <Grid Margin="10" Grid.Column="1" Grid.Row="1">
    
          <Grid.ColumnDefinitions>
              <ColumnDefinition />
              <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
              <RowDefinition />
          </Grid.RowDefinitions>
    
          <!-- Name -->
          <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Orientation="Horizontal">
              <Label Style="{StaticResource labelStyle}">Name:</Label>
              <Label Style="{StaticResource labelStyle}"></Label>
          </StackPanel>
    
          <!-- Department -->
          <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" 
      Orientation="Horizontal">
              <Label Style="{StaticResource labelStyle}">Department:</Label>
              <Label Style="{StaticResource labelStyle}"></Label>
          </StackPanel>
    
          <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" VerticalAlignment="Top" 
                HorizontalAlignment="Left">
              <!-- Expense type and Amount table -->
              <DataGrid ColumnHeaderStyle="{StaticResource columnHeaderStyle}" 
                        AutoGenerateColumns="False" RowHeaderWidth="0" >
                  <DataGrid.Columns>
                      <DataGridTextColumn Header="ExpenseType" />
                      <DataGridTextColumn Header="Amount"  />
                  </DataGrid.Columns>
              </DataGrid>
          </Grid>
      </Grid>
    

    В элементы Label и Border будут добавлены стили.

Привязка данных к элементу управления

В этом разделе вы создадите XML-данные, привязанные к различным элементам управления.

  1. Откройте ExpenseItHome.xaml.

  2. После открывающего элемента Grid, добавьте следующий XAML для создания XmlDataProvider, содержащий данные для каждого пользователя:

    <Grid.Resources>
    
    <!-- Expense Report Data -->
    <XmlDataProvider x:Key="ExpenseDataSource" XPath="Expenses">
        <x:XData>
            <Expenses xmlns="">
                <Person Name="Mike" Department="Legal">
                    <Expense ExpenseType="Lunch" ExpenseAmount="50" />
                    <Expense ExpenseType="Transportation" ExpenseAmount="50" />
                </Person>
                <Person Name="Lisa" Department="Marketing">
                    <Expense ExpenseType="Document printing"
          ExpenseAmount="50"/>
                    <Expense ExpenseType="Gift" ExpenseAmount="125" />
                </Person>
                <Person Name="John" Department="Engineering">
                    <Expense ExpenseType="Magazine subscription" 
         ExpenseAmount="50"/>
                    <Expense ExpenseType="New machine" ExpenseAmount="600" />
                    <Expense ExpenseType="Software" ExpenseAmount="500" />
                </Person>
                <Person Name="Mary" Department="Finance">
                    <Expense ExpenseType="Dinner" ExpenseAmount="100" />
                </Person>
            </Expenses>
        </x:XData>
    </XmlDataProvider>
    
    </Grid.Resources>
    

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

  3. В элемент <Grid.Resources> добавьте следующий DataTemplate, который определяет способ отображения данных в ListBox:

    <Grid.Resources>
    
    <!-- Name item template -->
    <DataTemplate x:Key="nameItemTemplate">
        <Label Content="{Binding XPath=@Name}"/>
    </DataTemplate>
    
    </Grid.Resources>
    

    Дополнительные сведения о шаблонах данных см. в разделе Общие сведения о шаблонах данных.

  4. Замените существующий ListBox следующим XAML:

    <ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2" 
             ItemsSource="{Binding Source={StaticResource ExpenseDataSource}, XPath=Person}"
             ItemTemplate="{StaticResource nameItemTemplate}">
    </ListBox>
    

    Этот XAML привязывает свойство ItemsSource элемента ListBox к источнику данных и применяет шаблон данных ItemTemplate.

Подключение данных к элементам управления

Далее добавим код для извлечения имени, выбранного на странице ExpenseItHome и передачи его конструктору ExpenseReportPage. ExpenseReportPage задает контекст данных для переданного элемента к которому привязываются элементы управления, определенные в ExpenseReportPage.xaml.

  1. Откройте файл ExpenseReportPage.xaml.vb или ExpenseReportPage.xaml.cs.

  2. Добавьте конструктор, принимающий объект, чтобы можно было передавать данные отчета о затратах выбранного человека.

    public partial class ExpenseReportPage : Page
    {
        public ExpenseReportPage()
        {
            InitializeComponent();
        }
    
        // Custom constructor to pass expense report data
        public ExpenseReportPage(object data):this()
        {
            // Bind to expense report data.
            this.DataContext = data;
        }
    }
    
  3. Откройте ExpenseItHome.xaml.vb или ExpenseItHome.xaml.cs.

  4. Измените обработчик Click, добавив вызов конструктора, передавая отчет о затратах выбранного человека.

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        // View Expense Report
        ExpenseReportPage expenseReportPage = new ExpenseReportPage(this.peopleListBox.SelectedItem);
        this.NavigationService.Navigate(expenseReportPage);
    }
    

Стиль с использованием шаблонов данных

В этом разделе вы обновите пользовательский Интерфейс для каждого элемента в списках с привязкой к данным с помощью шаблонов данных.

  1. Откройте файл ExpenseReportPage.xaml.

  2. Привяжите содержимое Label «Name» и «Department» к свойствам. Дополнительные сведения о привязке данных см. в разделе Общие сведения о привязке данных.

    <!-- Name -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Orientation="Horizontal">
        <Label Style="{StaticResource labelStyle}">Name:</Label>
        <Label Style="{StaticResource labelStyle}" Content="{Binding XPath=@Name}"></Label>
    </StackPanel>
    
    <!-- Department -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Orientation="Horizontal">
        <Label Style="{StaticResource labelStyle}">Department:</Label>
        <Label Style="{StaticResource labelStyle}" Content="{Binding XPath=@Department}"></Label>
    </StackPanel>
    
  3. После открывающего элемента Grid добавьте следующие шаблоны данных, которые определяют способ отображения данных отчета о расходах:

    <!--Templates to display expense report data-->
    <Grid.Resources>
        <!-- Reason item template -->
        <DataTemplate x:Key="typeItemTemplate">
            <Label Content="{Binding XPath=@ExpenseType}"/>
        </DataTemplate>
        <!-- Amount item template -->
        <DataTemplate x:Key="amountItemTemplate">
            <Label Content="{Binding XPath=@ExpenseAmount}"/>
        </DataTemplate>
    </Grid.Resources>
    
  4. Замените DataGridTextColumn на DataGridTemplateColumn у элемента DataGrid и примените шаблоны к ним.

    <!-- Expense type and Amount table -->
    <DataGrid ItemsSource="{Binding XPath=Expense}" ColumnHeaderStyle="{StaticResource columnHeaderStyle}" AutoGenerateColumns="False" RowHeaderWidth="0" >
       
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="ExpenseType" CellTemplate="{StaticResource typeItemTemplate}" />
            <DataGridTemplateColumn Header="Amount" CellTemplate="{StaticResource amountItemTemplate}" />
        </DataGrid.Columns>
        
    </DataGrid>
    
  5. Выполните сборку и запуск приложения.

  6. Выберите «person», а затем нажмите View.

На следующем рисунке показаны обе страницы приложения ExpenseIt с элементами управления, макетом, стилями, привязками данных и примененными шаблонами данных:

Снимки экрана примера ExpenseIt

Следующие шаги

В этом пошаговом руководстве вы узнали ряд методов для создания пользовательского интерфейса с помощью Windows Presentation Foundation (WPF). Теперь вы должны знать основные стандартные блоки приложения .NET Framework для работы с данными. Более подробную информацию об архитектуре и моделях программирования WPF см. в следующих разделах:

  • Архитектура WPF
  • Обзор XAML (WPF)
  • Общие сведения о свойствах зависимостей
  • Макет

Более подробную информацию о создании приложений см. в следующих разделах:

  • Разработка приложений
  • Элементы управления
  • Общие сведения о привязке данных
  • Графика и мультимедиа
  • Документы в WPF

См. также

  • Общие сведения о панелях
  • Общие сведения о шаблонах данных
  • Построение приложения WPF
  • Стили и шаблоны

Время на прочтение5 мин

Количество просмотров26K

Последние несколько дней я пытался найти библиотеку, которая бы позволила мне писать на C++ программы с GUI. Мои требования были довольно просты:

  • Достаточно только поддержки Windows;

  • Разрешено коммерческое использование;

  • Простая стилизация, в том числе и тёмный режим;

  • Результатом должен быть единый файл .exe размером меньше 40 МБ без или с минимальным количеством зависимостей;

  • Написание части программы с GUI не должно занимать больше времени, чем сама функциональность.

WinUI 3

На первый взгляд кажется идеальным выбором. Позволяет использовать современные компоненты Windows, в то же время допуская настройку цветов стилизации. Для дизайна можно пользоваться XAML, который очень легко освоить, или же напрямую работать с Visual Studio designer.

screenshot

Галерея элементов управления WinUI 3

Проблема: выпуск приложений в неупакованном виде поддерживается не очень хорошо. При попытках перенести приложение в VM или на другой компьютер чаще всего оно отказывалось запускаться из-за отсутствия каких-то непонятных зависимостей. Хуже того, в комплекте нужно поставлять несколько файлов .dll, управляющих функциональностью WinUI. Получить единый портируемый файл .exe невозможно. Использование упакованного вида обычно работает без проблем, но приложения устанавливаются как пакеты AppX, что привносит множество других проблем (особенно если вам нужен доступ ко всем Win32 API).

Win32 / MFC / небольшие библиотеки-обёртки для Win32

Мне нужна была высокая степень портируемости, так что логично было использовать нативный рендеринг операционной системы. Такая программа может быть единым файлом .exe (если мы статически компонуем MFC) и в то же время очень маленькой (всего несколько килобайтов). Можно было бы использовать и ещё более минимальную библиотеку, которую уже написали, что позволило бы мне быстро превратить концепцию в работающее приложение.

screenshot

Простая форма Win32

Проблема: стилизовать нативные элементы управления (controls) Win32 крайне сложно. Мне пришлось бы писать собственную функцию Paint для каждого элемента управления, что потребовало бы столько времени, что я бы успел ещё и обзавестись семьёй. Существует «тайный» тёмный режим для элементов управления Win32, используемый в Проводнике Windows, который можно активировать, но он охватывает только часть элементов управления и выглядит не очень красиво.

Qt

Эта библиотека — Святой Грааль GUI для C++. Хотя она довольно сложна, в ней есть удобная стилизация при помощи языка Qt Style Sheets, похожего на CSS.

screenshot

Использование Qt и собственных таблиц стилей в OBS studio

Проблема: при динамической компоновке для запуска приложения требуется куча разных .dll общим размером более 40 МБ. Можно статически скомпоновать Qt в программу, что существенно уменьшит её размер (так как неиспользуемые части удаляются), но тогда по лицензии LGPL Qt вам придётся сделать её опенсорсной или распространять в виде объектных файлов. Или же можно ежегодно покупать коммерческую лицензию за несколько тысяч долларов.

wxWidgets

Достаточно простая в изучении библиотека с опцией использования wxFormBuilder. Её лицензия менее требовательна, чем у Qt, и её можно статически скомпоновать в исполняемый файл размером 3 МБ.

screenshot

wxWidgets со включенной экспериментальной опцией тёмного режима в Windows

Проблема: в Windows эта библиотека использует нативные компоненты Win32 и не предоставляет никаких опций стилизации (так как мы не можем напрямую переписать функции Paint, она даже хуже, чем применение непосредственно Win32/MFC). Она поддерживает применение тёмных элементов управления Проводника Windows, но, как я говорил, они некрасивые.

hikogui

Довольно новая библиотека GUI retained mode, использующая в качестве бэкенда Vulkan. Имеет встроенный тёмный режим и достаточно проста в самостоятельной стилизации.

screenshot

Скриншоты из официального репозитория

Проблема: для успешной компиляции вам понадобится докторская степень по computer science со специализацией в разработке ПО. Потратив больше получаса на попытки скомпилировать пример (в том числе различных веток и меток релизов), единственное, что мне удалось получить — это исполняемый файл, немедленно вылетавший с ошибкой нарушения доступа внутри какой-то библиотеки Vulkan, поэтому я просто сдался. Проект выглядит очень многообещающе, хотя мне и не нравится активное применение надоедливой STL (без которой иногда даже можно было обойтись).

Sciter

Хорошая альтернатива Electron, позволяющая писать GUI для десктопного приложения на HTML/CSS.

screenshot

Пример плохого сглаживания SVG-значков

Проблема: вы могли подумать, что проблема будет заключаться в большом размере, но на самом деле готовое приложение со всеми .dll занимает около 25 МБ, что меня вполне устраивает. Библиотека могла бы быть ещё лучше, если бы она была опенсорсной и можно было бы пользоваться статически скомпонованной версией для коммерческого использования (та же проблема, что и у Qt). Она не такая дорогая, как Qt (сейчас $310 за лицензию Indie), поэтому я бы заплатил и был счастлив. Но проблема в том, что, как видно на скриншоте (посмотрите на значки заголовка окна), рендеринг неидеален. У меня возникали всевозможные проблемы со сглаживанием шрифтов и изображений. Кроме того, что бы я ни делал, у окна сохранялась довольно толстая (2-3 пикселя) серая рамка, которую никак нельзя ни настроить, ни изменить.

WinForms / WPF

Если вы начнёте спрашивать на форумах про GUI-библиотеки C++ для Windows, то чаще всего вам будут говорить, что это плохая идея (не спорю с этим) и что вместо этого вам нужно писать фронтенд программы на каком-то другом стеке, а затем просто загрузить свою написанную на C++ функциональность как компонент/модуль. Это позволит легко стилизовать её и сильно ускорить разработку. Теоретически, можно получить единый .exe небольшого размера и использовать WinForms/WPF. Это возможно реализовать двумя способами:

  1. Встроить .dll как ресурс в приложение и заставить его извлекать библиотеку в какую-то временную папку, а затем использовать P/Invoke и вызывать скомпилированную .dll из приложения на C#/.NET.

  2. Использовать C++/CLI.

screenshot

DarkUI для WinForms

Проблема: .NET Framework поставляется в комплекте с Windows 10+, так что, строго говоря, это удовлетворяет требованию отсутствия зависимостей. Проблема в том, что при встраивании .dll его всё равно придётся куда-то извлекать и писать дополнительный код для работы P/Invoke, а C++/CLI компилируется в код .NET IL (иными словами, можно открыть получившееся приложение в dnSpy и увидеть код на C++, транслированный в эквивалент на C#); мне же нужно не это, а нативный код).

Решение?

Это лишь некоторые из рассмотренных мной вариантов. После длительных попыток работы со всевозможными библиотеками и даже написания собственных стилей MFC я осознал, что для простых приложений нет ничего более подходящего, чем Dear ImGui.

У неё есть недостатки, в основном возникающие при попытке создания сложных UI; кроме того, это UI не retained mode, а immediate mode, так что только для рендеринга UI с частотой 60 или более кадров нам придётся задействовать GPU-рендерер наподобие DirectX.

Однако библиотека отвечает всем остальным требованиям, потому что DirectX по умолчанию встроен в современные версии Windows.

screenshot

Пример проекта ImGui AppKit

Выше показан написанный мной пример того, как можно применять встроенную функцию множественных вьюпортов при создании простых приложений с GUI.

Размер скомпилированного приложения ImGui AppKit

Скомпилированная программа весит всего 500 КБ и не требует ничего устанавливать, даже VC++ redistributable, если статически скомпоновать в него MFC.

Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Пак курсоров для windows 10 аниме
  • Пропадает основной шлюз windows
  • Установка windows из wim или esd образа
  • Лучший менеджер загрузок для windows 10
  • Сброс к заводским настройкам windows 10 что останется