создание wpf приложений с
Из этого краткого руководства вы узнаете, как создать приложение Windows Presentation Foundation (WPF) с помощью Visual Studio. После создания первоначального приложения вы научитесь добавлять элементы управления и обрабатывать события. По завершении работы с этим руководством у вас будет простое приложение, добавляющее имена в список.
В этом руководстве описано следующее:
Ниже представлен предварительный просмотр приложения, которое будет создано в данном руководстве.
Предварительные требования
Создание приложения WPF
Первым шагом в создании нового приложения является запуск Visual Studio и создание приложения на основе шаблона.
Запустите Visual Studio.
Выберите Создать новый проект.
В раскрывающемся списке язык кода выберите C# или Visual Basic.
В списке шаблонов выберите Приложение WPF, а затем нажмите Далее.
В окне Настройка нового проекта выполните следующие действия:
После создания приложения в Visual Studio должна открыться панель конструктора XAML для формы по умолчанию MainWindow. Если конструктор не отображается, дважды щелкните файл MainWindow.xaml в области Обозреватель решений, чтобы открыть конструктор.
Важные элементы среды Visual Studio
Поддержка WPF в Visual Studio состоит из пяти важных компонентов, с которыми вы будете взаимодействовать при создании приложения.
Все файлы проекта, код, окна и ресурсы отображаются в этой области.
На этой панели отображаются параметры свойств, которые можно настроить в зависимости от выбранного элемента. Например, если выбрать элемент в Обозревателе решений, отобразятся параметры свойств, связанные с файлом. Если выбрать объект в конструкторе, отобразятся параметры этого элемента.
Панель элементов содержит все элементы управления, которые можно добавить на форму. Чтобы добавить элемент управления на текущую форму, дважды щелкните элемент управления или перетащите его.
Это конструктор для документа XAML. Он является интерактивным, и на него можно перетаскивать объекты из панели элементов. Выбирая и перемещая элементы в конструкторе, можно визуально создавать пользовательский интерфейс для приложения.
Если конструктор и редактор отображаются, изменения в одном из них сразу отражаются в другом. При выборе элементов в конструкторе в области Свойства отображаются свойства и атрибуты этого объекта.
Редактор кода XAML
Это редактор кода XAML для документа XAML. Редактор кода XAML — это способ создания пользовательского интерфейса вручную без конструктора. Конструктор может вычислять значения свойств элемента управления при его добавлении в конструктор. В редакторе кода XAML вам предоставляется гораздо больше контроля.
Если конструктор и редактор отображаются, изменения в одном из них сразу отражаются в другом. При переходе по текстовым курсорам в редакторе кода в области Свойства отображаются свойства и атрибуты этого объекта.
Сохраните файл проекта и закройте вкладку редактора.
Изучение кода XAML
После создания проекта в редакторе кода XAML отображается минимальный объем кода XAML для отображения окна. Если редактор не открыт, дважды щелкните элемент MainWindow.xaml в обозревателе решений. Должен отобразиться код XAML, аналогичный следующему:
Корень документа представляет тип объекта, описываемого файлом XAML. Объявлено восемь атрибутов, и обычно они относятся к трем категориям:
Пространство имен XML предоставляет структуру XML, которая определяет, что можно, а что нельзя объявлять в файле.
Изменение окна
Сначала запустим проект и просмотрим выходные данные по умолчанию. Появится окно с заголовком MainWindow без элементов управления:
Для нашего примера приложения это окно слишком велико, а его заголовок не является описательным. Измените заголовок и размер окна, заменив соответствующие атрибуты в XAML следующими значениями:
Подготовка макета
Элемент управления определяет строки и столбцы, в которых будут находиться элементы управления. В сетке всегда объявлена одна строка и столбец, то есть сетка по умолчанию является отдельной ячейкой. Это не обеспечивает большую гибкость при размещении элементов управления.
Затем определите две строки и два столбца, разделив сетку на четыре ячейки:
Выберите сетку в редакторе кода XAML или в конструкторе XAML. Вы увидите, что в конструкторе XAML отображается каждая строка и столбец:
Добавление первого элемента управления
После создания сетки можно приступать к добавлению в нее элементов управления. Начните с элемента управления Label. Создайте новый элемент внутри элемента после определений строк и столбцов, а затем присвойте ему строковое значение Names :
Обратите внимание, что теперь в конструкторе отображается метка, занимающая небольшую часть доступной высоты. Теперь имеется больше места для следующей строки. Большинство элементов управления определяют значения высоты и ширины, которые они должны занимать. В случае элемента управления Label он имеет значение высоты, которое гарантирует, что его можно будет прочитать.
Размещение элементов управления
Давайте поговорим о размещении элементов управления. Метка, созданная в разделе выше, автоматически помещается в строку 0 и столбец 0 сетки. Нумерация строк и столбцов начинается с 0 и увеличивается на 1 для каждой новой строки или столбца. Элементу управления ничего не известно о сетке, и элемент управления не определяет свойства для управления своим размещением в сетке. Элемент управления можно даже поместить в другой элемент управления макета, имеющий собственный набор правил, которые определяют способ размещения элементов управления.
Как указать элементу управления, что ему следует использовать другую строку или столбец, если элемент управления не имеет сведений о сетке? В этом случае на помощь придут вложенные свойства! Сетка использует эффективную систему свойств, предоставляемую WPF. Сетка определяет новые свойства, которые дочерние элементы управления могут объявлять и использовать. Свойства фактически не существуют в самом элементе управления, они вкладываются сеткой при добавлении элемента управления в сетку.
Обратите внимание, что метка теперь переместилась во второй столбец. Вложенные свойства Grid.Row и Grid.Column можно использовать для размещения последующих элементов управления, которые мы создадим. Но на этом этапе следует вернуть метку в строку 0.
Создание поля со списком имен
Добавление оставшихся элементов управления
Создайте элемент управления после списка и вставьте его в строку 1 и столбец 1 сетки. Добавьте еще один атрибут с именем Margin и значением 5,0,0,0 :
Макет окна готов. Однако в наше приложение следует добавить логику, чтобы оно работало. Далее необходимо подключить события элемента управления к коду, чтобы приложение выполняло действия.
Добавление кода для события Click
Теперь необходимо создать код обработчика. Щелкните правой кнопкой мыши ButtonAddName_Click и выберите Перейдите к определению. При этом в коде будет создан метод, соответствующий введенному имени обработчика.
Затем добавьте следующий код для выполнения следующих трех шагов:
Запустите приложение
Теперь, когда у нас есть код события, можно запустить приложение, нажав клавишу F5 или выбрав пункт меню Отладка > Начать отладку. Отобразится окно, и вы можете ввести имя в текстовое поле, а затем добавить его, нажав кнопку.
Быстрый старт с WPF. Часть 1. Привязка, INotifyPropertyChanged и MVVM
По разным причинам большинство из нас использует десктопные приложения, как минимум, браузер 🙂 А у некоторых из нас возникает необходимость в написании своих. В этой статье я хочу пробежаться по процессу разработки несложного десктопного приложения с использованием технологии Windows Presentation Foundation (WPF) и применением паттерна MVVM. Желающих продолжить чтение прошу под кат.
В чём особенность WPF?
Два основных отличия WPF от других средств построения десктопных приложений:
Я не буду углубляться в подробности, т.к. это не совсем тема статьи. Если интересно, то гуглить XAML, WPF rendering, milcore.dll и DirectX 🙂
О чём эта статья?
Эта статья содержит пример приложения, построенного на технологии WPF:
Я постараюсь ориентировать материал статьи в практическую сторону в стиле «повторяй за мной» с пояснениями.
Что нам понадобится для повторения статьи?
Так же в этом разделе я опишу создание проекта.
Запускаем VS, создаём новый проект, тип приложения выбираем WPF App (.NET Framework) (можно ввести в строке поиска справа вверху), называем как угодно.
После создания нового проекта откроется окно редактора интерфейса, у меня оно выглядит так
Внизу находится редактор разметки, вверху — предпросмотр интерфейса окна, но можно поменять относительное расположение редактора кода и предпросмотра интерфейса так, что они будут располагаться в горизонтальном порядке, с помощью вот этих кнопок (справа на границе двух областей):
Перед тем, как начать
Элементы окна (их ещё называют контрОлами от слова Control) должны размещаться внутри контейнера или внутри другого элемента типа ContentControl. Контейнер — это специальный контрол, позволяющий разместить внутри себя несколько дочерних контролов и организовать их взаимное расположение. Примеры контейнеров:
Есть и другие контейнеры. Поскольку контейнер тоже является контролом, то внутри контейнера могут быть вложенные контейнеры, содержащие вложенные контейнеры и так далее. Это позволяет гибко располагать контролы относительно друг друга. Так же с помощью контейнеров мы можем не менее гибко управлять поведением вложенных контролов при изменении размеров окна.
MVVM и интерфейс INotifyPropertyChanged. Копия текста.
Итогом этого примера станет приложение с двумя контролами, в одном из которых можно редактировать текст, а в другом только просматривать. Изменения из одного в другой будут переходить синхронно без явного копирования текста с помощью привязки (binding).
Теперь сосредоточимся на цели этого примера. Мы хотим, чтобы при наборе текста в текстбоксе этот же текст синхронно отображался в текстблоке, избежав при этом явной операции копирования текста. Нам понадобится некая связующая сущность, и вот тут-то мы и подошли к такой штуке, как привязка (binding), о которой было сказано выше. Привязка в терминологии WPF — это механизм, позволяющий связывать некоторые свойства контролов с некоторыми свойствами объекта C#-класса и выполнять взаимное обновление этих свойств при изменении одной из частей связки (это может работать в одну, в другую или в обе стороны сразу). Для тех, кто знаком с Qt, можно провести аналогию слотов и сигналов. Чтобы не растягивать время, перейдём к коду.
Итак, для организации привязки нужны свойства контролов и некое свойство некоего C#-класса. Для начала разберёмся с XAML-кодом. Текст обоих контролов хранится в свойстве Text, поэтому добавим привязку для этих свойств. Делается это так:
Мы сделали привязку, но пока непонятно к чему 🙂 Нам нужен объект какого-то класса и какое-то свойство в этом объекте, к которому будет выполнена привязка (как ещё говорят, на которое нужно забиндиться).
Так что это за класс? Этот класс называется вьюмоделью (view model) и служит как раз связующим звеном между view (интерфейсом или его частями) и model (моделью, т.е. теми частями кода, которые отвечают за логику приложения. Это позволяет отделить (в какой-то степени) логику приложения от интерфейса (представления, view) и называется паттерном Model-View-ViewModel (MVVM). В рамках WPF этот класс также называется DataContext.
Однако, просто написать класс вьюмодели недостаточно. Нужно ещё как-то оповещать механизм привязки о том, что свойство вьюмодели или свойство вью изменилось. Для этого существует специальный интерфейс INotifyPropertyChanged, который содержит событие PropertyChanged. Реализуем этот интерфейс в рамках базового класса BaseViewModel. В дальнейшем все наши вьюмодели мы будем наследовать от этого базового класса, чтобы не дублировать реализацию интерфейса. Итак, добавим в проект каталог ViewModels, а в этот каталог добавим файл BaseViewModel.cs. Получим такую структуру проекта:
Код реализации базовой вьюмодели:
Создадим для нашего класса MainWindow свою вьюмодель, унаследовавшись от базовой. Для этого в том же каталоге ViewModels создадим файл MainWindowViewModel.cs, внутри которого будет такой код:
Шикарно! Теперь нужно добавить в эту вьюмодель свойство, на которое будем биндить текст наших контролов. Поскольку это текст, тип этого свойства должен быть string:
В итоге получим такой код
Так, кажется, справились. Осталось забиндиться на это свойство из вьюхи и готово. Давайте сделаем это прямо сейчас:
Ништяк, запускаем проект, набираем текст в текстбокс иииии… ничего не происходит))) Ну, ничего страшного, на самом деле мы идём правильной дорогой, просто пока ещё не дошли до нужной точки.
Предлагаю на минутку остановиться и подумать, чего же нам не хватает. Вьюха у нас есть. Вьюмодель тоже. Свойства вроде забиндили. Нужный интерфейс реализовали. Проделали кучу работы ради копирования жалкой строчки текста, за что нам это. 111
Ладно, шутки в сторону. Мы забыли создать объект вьюмодели и кое-что ещё (об этом позже). Сам класс мы описали, но это ничего не значит, ведь у нас нет объектов этого класса. Ок, где нужно хранить ссылку на этот объект? Ближе к началу примера я упомянул некий DataContext, используемый в WPF. Так вот, у любой вью есть свойство DataContext, которому мы можем присвоить ссылку на нашу вьюмодель. Сделаем это. Для этого откроем файл MainWindow.xaml и нажмём F7, чтобы открыть код этой вьюхи. Он практически пустой, в нём есть только конструктор класса окна. Добавим в него создание нашей вьюмодели и поместим её в DataContext окна (не забываем добавить using с нужным неймспейсом):
Это было просто, но этого всё равно не хватает. По-прежнему при запуске приложения никакой синхронизации текста не происходит. Что ещё нужно сделать?
Нужно вызвать событие PropertyChanged при изменении свойства SynchronizedText и сообщить вьюхе о том, что она должна следить за этим событием. Итак, чтобы вызвать событие, модифицируем код вьюмодели:
Что мы тут сделали? Добавили скрытое поле для хранения текста, обернули его в уже существующее свойство, а при изменении этого свойства не только меняем скрытое поле, но и вызываем метод OnPropertyChanged, определённый в базовой вьюмодели и вызывающий событие PropertyChanged, объявленное в интерфейсе INotifyPropertyChanged, так же реализованное в базовой вьюмодели. Получается, что при каждом изменении текста возникает событие PropertyChanged, которому передаётся имя свойства вьюмодели, которое было изменено.
Ну, почти всё, финишная прямая! Осталось указать вьюхе, что оно должно слушать событие PropertyChanged:
Помимо того, что мы указали, по какому триггеру должно происходить обновление, мы так же указали, в какую сторону это обновление отслеживается: от вью к вьюмодели или наоборот. Поскольку в текстбоксе мы вводим текст, то нам интересны изменения только во вью, поэтому выбираем режим OneWayToSource. В случае с текстблоком всё ровно наоборот: нам интересны изменения во вьюмодели, чтобы отобразить их во вью, поэтому выбираем режим OneWay. Если бы нам нужно было, чтобы изменения отслеживались в обе стороны, можно было не указывать Mode вообще, либо указать TwoWay явно.
Итак, запускаем программу, набираем текст и voi-la! Текст синхронно меняется, и мы нигде ничего не копировали!
Спасибо за внимание, продолжение следует. Будем разбираться с DataTemplate и паттерном Command.
Создание простого приложения для обработки данных с помощью WPF и Entity Framework 6
эта статья посвящена использованию средств данных в Visual Studio и не пытается объяснить основные технологии в любой глубине. Предполагается, что у вас есть базовые знания XAML, Entity Framework и SQL. В этом примере также не демонстрируется Архитектура Model-View-ViewModel (MVVM), которая является стандартом для приложений WPF. Однако этот код можно скопировать в собственное приложение MVVM с небольшими изменениями.
Установка и подключение к Northwind
в этом примере используется SQL Server Express LocalDB и образец базы данных Northwind. если поставщик данных ADO.NET для этого продукта поддерживает Entity Framework, он также должен работать с другими продуктами SQLной базы данных.
Установите учебную базу данных Northwind, выполнив следующие действия.
Откроется окно редактора запросов.
скопируйте скрипт Transact-SQL Northwind в буфер обмена. этот сценарий T-SQL создает базу данных Northwind с нуля и заполняет ее данными.
По истечении короткого времени выполнение запроса завершается и создается база данных Northwind.
Настройка проекта
в Visual Studio создайте новый проект приложения WPF на C#.
добавьте пакет NuGet для Entity Framework 6. В Обозреватель решений выберите узел проекта. в главном меню выберите Project > управление пакетами NuGet.
теперь можно использовать Visual Studio для создания модели на основе базы данных Northwind.
Создание модели
Щелкните правой кнопкой мыши узел проекта в обозревателе решений и последовательно выберите Добавить > Новый элемент. на левой панели в узле C# выберите данные и в средней области выберите ADO.NET EDM.
на следующем экране введите или выберите подключение LocalDB Northwind (например, (LocalDB) \MSSQLLocalDB), укажите базу данных northwind и нажмите кнопку далее.
На следующей странице мастера выберите таблицы, хранимые процедуры и другие объекты базы данных для включения в модель Entity Framework. Разверните узел dbo в представлении в виде дерева и выберите Customers, Orders и Order Details. Оставьте установленными значения по умолчанию и нажмите кнопку Готово.
Мастер создает классы C#, представляющие модель Entity Framework. Классы являются простыми старыми классами C#, и они являются привязкум к пользовательскому интерфейсу WPF. Файл EDMX описывает связи и другие метаданные, связывающие классы с объектами в базе данных. TT — это шаблоны T4, которые создают код, работающий с моделью, и сохраняет изменения в базе данных. Все эти файлы можно просмотреть в Обозреватель решений в узле Northwind_model.
Область конструктора для файла EDMX позволяет изменять некоторые свойства и связи в модели. Мы не будем использовать конструктор в этом пошаговом руководстве.
Замените первое вхождение HashSet на ObservableCollection около строки 51. Не заменяйте второй экземпляр hash.
Теперь все готово для подключения этой модели к XAML-странице, чтобы можно было просматривать, перемещать и изменять данные.
Привязка модели к странице XAML
можно написать собственный код привязки данных, но гораздо проще позволить Visual Studio сделать это за вас.
Разверните узел проекта и выберите Customer (клиент). (Источники для заказов автоматически формируются из свойства навигации Orders в Customer.)
Нажмите кнопку Готово.
Перейдите к файлу MainWindow. XAML в представлении кода. Мы постоянно используем XAML для целей этого примера. Измените заголовок MainWindow на что-то более описательное и увеличьте его высоту и ширину до 600 x 800. Вы всегда можете изменить его позже. Теперь добавьте эти три определения строк в главную сетку, одну строку для кнопок навигации, одну для сведений клиента и одну для сетки, которая показывает их заказы:
В представлении кода теперь можно увидеть новый Grid элемент в строке 1 (средняя строка) родительской сетки. Родительская сетка имеет DataContext атрибут, который ссылается на CollectionViewSource, добавленный в Windows.Resources элемент. Учитывая этот контекст данных, при привязке первого текстового поля к адресу это имя сопоставляется со Address свойством в текущем Customer объекте в CollectionViewSource.
Когда клиент отображается в верхней половине окна, необходимо просмотреть заказы в нижней половине. Заказы отображаются в одном элементе управления представления сетки. Для работы привязки «основной — подробности» необходимо выполнить привязку к свойству Orders в классе Customers, а не к отдельному узлу Orders. Перетащите свойство Orders класса Customers в нижнюю половину формы, чтобы конструктор поместит его в строку 2:
Visual Studio создала весь код привязки, который подключает элементы управления пользовательского интерфейса к событиям в модели. Для того чтобы увидеть некоторые данные, необходимо написать код для заполнения модели. Сначала перейдите к файлу MainWindow. XAML. CS и добавьте член данных в класс MainWindow для контекста данных. Этот объект, который был создан для вас, действует примерно так же, как элемент управления, отслеживающий изменения и события в модели. Вы также добавите элементы данных CollectionViewSource для клиентов и заказов, а также связанную логику инициализации конструктора. Начало класса должно выглядеть следующим образом:
Добавьте using директиву для System. Data. Entity, чтобы перевести метод расширения нагрузки в область:
Нажмите клавишу F5. Вы должны увидеть сведения для первого клиента, полученного в CollectionViewSource. Их заказы также должны отображаться в сетке данных. Форматирование не имеет ничего хорошего, так что давайте исправляется. Можно также создать способ просмотра других записей и выполнения базовых операций CRUD.
Настройка макета страницы и добавление сеток для новых клиентов и заказов
Сначала добавьте эти стили в Windows.Resources элемент в файле MainWindow. XAML:
Затем замените всю внешнюю сетку этой разметкой:
Добавление кнопок для навигации, добавления, обновления и удаления
в Windows Forms приложениях вы получаете объект BindingNavigator с кнопками для навигации по строкам в базе данных и выполнения базовых операций CRUD. WPF не предоставляет BindingNavigator, но достаточно просто создать его. Это можно сделать с помощью кнопок в горизонтальном StackPanel и связать кнопки с командами, привязанными к методам в коде программной части.
Логика команды состоит из четырех частей: (1) команды, (2) привязки, (3) кнопки и (4) обработчики команд в коде программной части.
Добавление команд, привязок и кнопок в XAML
Сначала добавьте команды в файл MainWindow. XAML внутри Windows.Resources элемента:
CommandBinding сопоставляет RoutedUICommand событие с методом в коде программной части. Добавьте этот CommandBindings элемент после Windows.Resources закрывающего тега:
Теперь добавьте с помощью StackPanel кнопок навигации, добавления, удаления и обновления. Сначала добавьте этот стиль в Windows.Resources :
Во-вторых, вставьте этот код сразу после элемента RowDefinitions для внешнего Grid элемента в верхнюю часть страницы XAML:
Добавление обработчиков команд в класс MainWindow
Код программной части является минимальным, за исключением методов Add и DELETE. Навигация выполняется путем вызова методов для свойства View объекта CollectionViewSource. В этом DeleteOrderCommandHandler примере показано, как выполнить каскадное удаление в заказе. Сначала необходимо удалить связанные с ним Order_Details. UpdateCommandHandler Добавляет нового клиента или заказа в коллекцию или просто обновляет существующего клиента или заказ с учетом изменений, внесенных пользователем в текстовые поля.
Добавьте эти методы обработчика в класс MainWindow в MainWindow. XAML. CS. Если CollectionViewSource для таблицы Customers имеет другое имя, необходимо изменить имя в каждом из этих методов: