Урок 3. Выпадающий список
Продолжим совершенствовать наш проект. Создадим форму для списка клиентов и карточку клиента. И заменим стартовую форму проекта. Теперь это будет форма списка клиентов.
На этом уроке:
познакомимся со сниппетами, которые ускоряют разработку форм;
рассмотрим применение SetDataConnection;
рассмотрим возможность передавать значения параметров в момент вызова команды.
Если хотите начать практику с этого урока, то вам необходимо развернуть учебный проект по инструкции в статье Разворачивание проекта.
При разворачивании проекта используйте backup базы данных, который можете найти в архиве из раздела Ответы прошлого урока. Скопируйте папки Forms, Workflow и Patterns в папку с развернутым проектом, например, в папку D:\WT\Projects\Template\Projects\1. Template.
Инструкция по подключению шаблонов находится по ссылке.
Форма списка клиентов
Форма списка клиентов должна содержать таблицу и три кнопки редактирования списка. Сохранение данных в таблицу в базе данных будет происходить на форме карточки клиента. Поэтому на форме списка кнопка "Сохранить" и FootPanel будут отсутствовать.
Создание формы
Для создания формы воспользуйтесь паттерном Empty Form (пустая форма с хэдером).

После того как создали файл формы, необходимо подменить стартовую форму. В конфигурационном файле клиентской части (WorkflowForms.dll.config) в параметре StartFormFileName указан путь до стартовой формы. Его оставим без изменений. А переименуем сами xml-файлы форм. Для этого перейдем в папку форм проекта Template\Projects\1. Template\Forms\ и переименуем файлы:
файл TemplateStart.xml переименуем в TemplateCityList.xml, т.к. это форма списка городов;
а только что созданный TemplateClientList.xml переименуем в TemplateStart.xml, таким образом будущий список клиентов станет стартовой формой.
После этого перейдем в Eclipse и обновим состояние нашего проекта в окне Project Explorer, чтобы редактор увидел изменения в именах файлов. Для этого выберем наш проект и нажмем клавишу F5, либо кликнем правой кнопкой мыши на имени проекта и в открывшемся меню выберем пункт Refresh. Затем перейдем в файл формы списка городов и в тэге <Form>
исправим значение атрибута Name на TemplateCityListForm. Это необходимо, чтобы в журнале событий ошибки имели правильное и уникальное имя формы, и мы могли быстро найти нужный файл.
Перезапустите проект и убедитесь, что стартовая форма успешно заменилась новым файлом.
Самостоятельно создайте необходимые элементы формы:
таблицу клиентов с колонками ClientId, № (RowNumber), ФИО (Name), Город (CityTitle) и Телефон (Phone);
три кнопки редактирования списка. Не забудьте про условие активности кнопок, если выделена строка таблицы.
Пока нужен только интерфейс.
В результате у вас должна получиться похожая форма:

Загрузка данных из базы данных на форму
Создание таблицы client в базе данных
Перейдем в программу для управления СУБД PostgreSQL. И для нашей базы данных template_project выполним следующий скрипт:
CREATE SEQUENCE template.client_id_seq;
CREATE TABLE template.client
(
client_id bigint NOT NULL DEFAULT nextval('template.client_id_seq'::regclass),
city_id smallint,
date_of_birth date,
title character varying,
email character varying,
phone character varying,
CONSTRAINT pk_client_id PRIMARY KEY (client_id),
CONSTRAINT fk_city_id FOREIGN KEY (city_id)
REFERENCES template.city (city_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
Описание запроса для чтения таблицы client базы данных
Перейдем в файл описания работы серверной части приложения (Template.xml). Добавим запрос для получения списка клиентов:
<SqlQuery Name="ClientSelectSqlQuery">
<Text>
SELECT
client.client_id AS "ClientId",
client.title AS "Name",
city.title AS "CityTitle",
client.phone AS "Phone"
FROM
template.client
LEFT JOIN template.city USING(city_id)
ORDER BY client.title;
</Text>
</SqlQuery>
Создайте ClientViewSqlQueryPermission с этим запросом и дайте права доступа группе GuestGroup.
На форме списка клиентов (TemplateStart.xml) создайте PrimaryGetDataConnection на этот запрос и укажите его в тэге <SourceDataConnection>
для таблицы ClientDatabaseTable.
Перезапустите проект. Убедитесь, что форма успешно загружена, и в журнале нет никаких сообщений об ошибках.
Отлично! Теперь можем заняться формой для карточки клиента.
Карточка клиента
Карточка клиента должна содержать поля: ФИО, Дата рождения, Город, Контактный телефон и E-mail. Поле "Город" будет представлено в виде выпадающего списка. Справа от поля "Город" будет кнопка, по которой будет открываться существующая форма со списком городов.
Скачайте новый архив с шаблонами по ссылке ниже. Замените содержимое папки с шаблонами, на которую ссылаются свойства проекта, на содержимое из архива.
С помощью шаблона Entity Form создайте форму для карточки клиента со следующими параметрами:

Одна команда на открытие формы
Вернемся в файл стартовой формы (TemplateStart.xml). Создадим команду FormShowCommand для формы карточки клиента, в которой сразу укажем два параметра:
<Command Name="ClientEditFormShowCommand" Type="FormShowCommand" Assembly="Commands">
<Xml Type="Path">TemplateClientEdit.xml</Xml>
<Show Type="None" />
<Parameters>
<Parameter Name="Edit"> </Parameter>
<Parameter Name="ClientId"> </Parameter>
</Parameters>
</Command>
Форма списка клиентов в таблице содержит колонки не для всех полей, которые описаны в задании на карточку клиента. Нет смысла перегружать sql-запрос для списка клиентов лишними полями, которые понадобятся на другой форме. В карточке клиента будем использовать дополнительный sql-запрос, в котором для конкретного клиента будем получать все необходимые данные. Для этого нам и понадобится параметр ClientId. В файле карточки клиента (TemplateClientEdit.xml) эти параметры уже есть.
Также мы не будем делать отдельные команды открытия формы на добавление и редактирование. Нам хватит и одной. А значения параметров будем подставлять в месте вызова команды. В этом нам поможет универсальное значение Input, которое используется только при описании команд и позволяет сократить дублирование кода.
Для параметра Edit в качестве значения укажем <Input>
со значением по умолчанию False. А для параметра ClientId укажем <Input>
без значения.
<Command Name="ClientEditFormShowCommand" Type="FormShowCommand" Assembly="Commands">
<Xml Type="Path">TemplateClientEdit.xml</Xml>
<Show Type="None" />
<Parameters>
<Parameter Name="Edit">
<Input Name="Edit">False</Input>
</Parameter>
<Parameter Name="ClientId">
<Input Name="ClientId" />
</Parameter>
</Parameters>
</Command>
Для открытия формы в режиме добавления записи нам не нужно передавать ClientId. А для параметра Edit мы уже указали значение по умолчанию. Таким образом, на кнопке ClientAddButton в тэге <Commands>
пропишем простой вызов команды по имени:
<Commands>
<Command Name="ClientEditFormShowCommand" />
</Commands>
Для открытия формы в режиме редактирования в команду ClientEditFormShowCommand через Input будем передавать нужные значения параметров. И так как открыть форму карточки клиента можно либо по кнопке "Редактировать запись...", либо по двойному клику по строке в таблице, мы создадим SequentialCommand, в которой будем вызывать ClientEditFormShowCommand:
<Command Name="ClientEditSequentialCommand" Type="SequentialCommand" Assembly="Commands">
<Commands>
<Command Name="ClientEditFormShowCommand">
<Input Name="Edit">True</Input>
<Input Name="ClientId">
<Object Name="ClientDatabaseTable">
<Property Name="SelectedRowCellValueByColumnName">
<Parameters>
<Parameter Name="ColumnName">ClientId</Parameter>
</Parameters>
</Property>
</Object>
</Input>
</Command>
</Commands>
</Command>
Укажем команду ClientEditSequentialCommand в тэге <Commands>
кнопки "Редактировать запись...".
Добавьте самостоятельно обработку двойного клика по строке таблицы и вызов команды ClientEditSequentialCommand.
Также самостоятельно создайте команду типа DataConnectionRefreshCommand на ClientPrimaryGetDataConnection, которая будет выполняться в Execution по изменению параметра Updated у команды ClientEditFormShowCommand.
Перезапустите проект. Убедитесь, что форма успешно загружена, и карточка клиента открывается без сообщений об ошибках.
Отлично! Теперь можем приступить к наполнению формы карточки клиента объектами. Но для начала реализуем запрос и загружающее соединение с данными для получения информации по клиенту на форме.
Запросы к базе данных
Перейдем в файл описания работы серверной части приложения (Template.xml). Добавим запрос для получения данных по конкретному клиенту:
<SqlQuery Name="ClientByIdSelectSqlQuery">
<Text>
SELECT
client.title AS "Name",
client.city_id AS "CityId",
client.date_of_birth AS "DateOfBirth",
client.email AS "Email",
client.phone AS "Phone"
FROM
template.client
WHERE
client.client_id = {ClientId};
</Text>
</SqlQuery>
Добавим его в ранее созданный ClientViewSqlQueryPermission.
Давайте сразу сделаем запросы на сохранение изменений в таблицу template.client:
<SqlQuery Name="ClientInsertSqlQuery">
<Text>
INSERT INTO template.client(
city_id,
date_of_birth,
title,
email,
phone
)
VALUES (
{CityId},
{DateOfBirth},
{Name},
{Email},
{Phone}
)
RETURNING client_id;
</Text>
</SqlQuery>
<SqlQuery Name="ClientUpdateSqlQuery">
<Text>
UPDATE template.client
SET
city_id = {CityId},
date_of_birth = {DateOfBirth},
title = {Name},
email = {Email},
phone = {Phone}
WHERE
client_id = {ClientId};
</Text>
</SqlQuery>
<SqlQuery Name="ClientDeleteSqlQuery">
<Text>
DELETE FROM template.client
WHERE
client_id = {ClientId};
</Text>
</SqlQuery>
Запрос ClientInsertSqlQuery возвращает идентификатор client_id новой записи. Этот идентификатор будем использовать на формах, как результат выполнения команды SaveCommand. Но об этом позже, а пока настроим права доступа к новым запросам.
Соберем новые запросы в ClientEditSqlQueryPermission:
<Permission Name="ClientEditSqlQueryPermission" Type="SqlQueryPermission">
<SqlQueries>
<SqlQuery Name="ClientInsertSqlQuery" />
<SqlQuery Name="ClientUpdateSqlQuery" />
<SqlQuery Name="ClientDeleteSqlQuery" />
</SqlQueries>
</Permission>
И сделаем ClientEditRole:
<Role Name="ClientEditRole">
<Permissions>
<Permission Name="ClientViewSqlQueryPermission" />
<Permission Name="ClientEditSqlQueryPermission" />
</Permissions>
</Role>
Скорректируем права доступа для GuestGroup:
<Group Name="GuestGroup">
<Roles>
<Role Name="CityEditRole" />
<Role Name="ClientEditRole" />
</Roles>
</Group>
Создание объектов формы
Перейдем в файл карточки клиента (TemplateClientEdit.xml) и первым делом создадим PrimaryGetDataConnection:
<DataConnection Name="ClientPrimaryGetDataConnection" Type="PrimaryGetDataConnection" Assembly="DataConnections">
<SqlQuery Name="ClientByIdSelectSqlQuery" Type="Select">
<Workflow Name="Template" />
<Fields>
<Field Name="Name" />
<Field Name="CityId" />
<Field Name="DateOfBirth" />
<Field Name="Email" />
<Field Name="Phone" />
</Fields>
<Parameters>
<Parameter NativeName="ClientId">
<Value>
<Parameter Name="ClientId" />
</Value>
</Parameter>
</Parameters>
</SqlQuery>
</DataConnection>
Создавать объекты на форме можно по одному: отдельно Label, отдельно связанный с ним TextBox. А можно воспользоваться сниппетом, который вставит пару объектов с корректной привязкой координат относительно друг друга и контейнера, в котором они располагаются.
Вставить сниппет можно из окна автозаполнения. Разместим курсор внутри ContentPanel и начнем писать "Lab". Нажмите на сочетание клавиш Ctrl+Space, чтобы открылось окно автозаполнения.

Редактор подсказывает нам три сниппета: "Label + ComboBox", "Label + DateTimePicker" и "Label + TextBox". Справа от имени сниппета указывается его короткое имя. Например, lcombox. По этому имени также можно искать конкретный сниппет. Эти сниппеты пригодятся нам при создании объектов на форме.
Выберем сниппет "Label + TextBox" и нажмем Enter. Откроется окно настроек:

Последние два поля оставим пустыми, т.к. в ContentPanel у нас еще нет никаких объектов, к которым можно привязаться. Жмем Finish.
Редактор на место курсора подставит код наших объектов NameLabel и NameTextBox. Также откроет блокнот с текстом подсказки необходимых изменений. Сейчас эта подсказка нас не интересует - все необходимые доработки уже существуют.
Давайте смотреть, что добавил редактор. В объекте NameLabel редактор подсвечивает ошибки:

Это из-за того, что последние два поля в настройках сниппета мы оставили пустыми. Давайте заменим значения для тэгов <Top>
и <Left>
на 5 и 10 соответственно.
Вторым интересным моментом является то, что редактор для объекта NameTextBox в тэг <Text>
сразу подставил наше соединение с данными ClientPrimaryGetDataConnection и указал нужное поле.
<Text>
<DataConnection SourceDataConnection="ClientPrimaryGetDataConnection">
<Fields>
<Field Name="Name" />
</Fields>
</DataConnection>
</Text>
Перейдем в приложение и нажмем кнопку "Добавить запись...". Убедимся, что карточка клиента успешно загружена, и проверим расположение объектов.

Сначала доделаем все поля на форме, а затем скорректируем ее размеры.
Для создания поля "Дата рождения" воспользуемся сниппетом "Label + DateTimePicker":

Теперь заполним два последних поля. И укажем в них ранее созданные поля.
Жмем Finish.
Обратите внимание на значения тэгов <Top>
у DateOfBirthLabel и DateOfBirthDateTimePicker. Отступ между объектами NameTextBox и DateOfBirthLabel равен 5 пикселей. А отступ между DateOfBirthLabel и DateOfBirthDateTimePicker - нулевой. Такие значения отступов позволяют визуально отделить поля одного свойства от полей другого свойства.
Редактор для объекта DateOfBirthDateTimePicker в тэг <Value>
сразу подставил наше соединение с данными ClientPrimaryGetDataConnection и указал нужное поле.
Перейдем в приложение и убедимся, что карточка клиента успешно загружена, и проверим расположение объектов.

Внесем небольшие правки в описание объекта DateOfBirthDateTimePicker. Во-первых, изменим его ширину, прописав в тэг <Width>
значение 150, чтобы поле выглядело симпатичнее. Во-вторых, изменим значение атрибута Show у тэга <NullValue>
на True. Атрибут Show определяет, может ли дата иметь значение NULL.
В итоге синтаксис объекта DateOfBirthDateTimePicker будет выглядеть так:
<MyObject Name="DateOfBirthDateTimePicker" Type="DateTimePicker" Assembly="BaseControls">
<Top>
<Object Name="DateOfBirthLabel">
<Property Name="Bottom" />
</Object>
</Top>
<Left>
<Object Name="DateOfBirthLabel">
<Property Name="Left" />
</Object>
</Left>
<Width>150</Width>
<Format>dd MMMM yyyy</Format>
<ShowCalendar>True</ShowCalendar>
<NullValue Show="True" />
<Value>
<DataConnection SourceDataConnection="ClientPrimaryGetDataConnection">
<Fields>
<Field Name="DateOfBirth" />
</Fields>
</DataConnection>
</Value>
</MyObject>
По заданию поле "Город" должно быть сделано в виде выпадающего списка (ComboBox). Поэтому для его создания воспользуемся сниппетом "Label + ComboBox":

Помимо знакомых уже полей настроек, этот сниппет имеет две специальных настройки: Имя схемы БД и Имя таблицы БД. Они необходимы для автоматического создания SqlQuery, на основе которого будет заполняться выпадающий список.
Жмем Finish.
Как можем видеть, редактор в файле описания работы серверной части приложения (Template.xml) создал запрос CityShortSelectSqlQuery. Осталось добавить этот запрос в какой-нибудь SqlQueryPermission. Например, в CityViewSqlQueryPermission.
Вы могли заметить, что текст запроса в созданном CityShortSelectSqlQuery полностью совпадает с текстом запроса в CitySelectSqlQuery. Такое дублирование кода допустимо. Лучше иметь отдельный запрос на заполнение выпадающего списка. Забегая вперед, назову две причины такого разделения. Во-первых, в будущем это упростит настраивание прав доступа. А, во-вторых, текст обоих запросов будет дополняться и изменяться по-разному.
Вернемся в файл карточки клиента (TemplateClientEdit.xml) и посмотрим, что добавилось там.
Редактор создал CityShortPrimaryGetDataConnection, который прописал в тэг <ValueList>
созданного объекта CityComboBox. А в тэг <Value>
того же объекта подставил ClientPrimaryGetDataConnection и указал нужное поле.
Перейдем в приложение и убедимся, что карточка клиента успешно загружена, и проверим расположение объектов.
Самостоятельно создайте поля "Контактный телефон" и "E-mail", использую нужные сниппеты. И скорректируйте размеры формы.
В результате у вас должна получиться форма подобного вида:

Редактирование выпадающего списка
По заданию справа от поля "Город" должна располагаться кнопка, по которой будет открываться форма со списком городов. Давайте создадим ее.
Для начала скачайте архив с изображением для этой кнопки и распакуйте его в папку \Template\Projects\1. Template\Forms\Images\16x16.
Создайте самостоятельно команду на открытие формы TemplateCityList.xml.
Создадим саму кнопку, разместив код, представленный ниже, сразу после описания объекта CityComboBox.
<MyObject Name="CityListButton" Type="Button" Assembly="BaseControls">
<Top>
<Object Name="CityComboBox">
<Property Name="Top" />
</Object>
</Top>
<Left>
<Formula>
<Plus DataType="IntegerDataType">
<Item>
<Object Name="CityComboBox">
<Property Name="Right" />
</Object>
</Item>
<Item>5</Item>
</Plus>
</Formula>
</Left>
<Height>22</Height>
<Width>22</Width>
<Hint>Список городов...</Hint>
<BackgroundImage>Images\16x16\list.png</BackgroundImage>
<BackgroundImageLayout>Center</BackgroundImageLayout>
<FlatStyle>Flat</FlatStyle>
<FlatBorderSize>1</FlatBorderSize>
<FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
<FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
<FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
<Commands>
<Command Name="CityListFormShowCommand" />
</Commands>
</MyObject>
Не забудьте поправить ширину CityComboBox с учетом ширины созданной кнопки и отступа в 5 пикселей между объектами.
Перейдем в приложение и убедимся, что карточка клиента успешно загружена, и форма со списком городов открывается.

Осталось реализовать обновление CityShortPrimaryGetDataConnection, который предоставляет список для CityComboBox, если на форме были сохранены изменения.
Для этого самостоятельно выполните следующие пункты:
Создайте DataConnectionRefreshCommand на CityShortPrimaryGetDataConnection;
Создайте условие для проверки параметра Updated у команды открытия формы TemplateCityList.xml;
Создайте Execution, который по условию из предыдущего пункта будет вызывать команду на обновление CityShortPrimaryGetDataConnection;
На форме TemplateCityList.xml создайте параметр Updated и команду UpdatedTrueValueSetCommand;
Там же на форме TemplateCityList.xml в тэге
<Commands>
кнопки SaveButton исправьте список выполняемых команд. Удалите вызов команды CityDataConnectionRefreshCommand. Вместо нее добавьте вызовы команд UpdatedTrueValueSetCommand и FormCloseCommand;Так же на форме TemplateCityList.xml удалите описание команды CityDataConnectionRefreshCommand. Эта команда нам больше не понадобится.
Перейдем в приложение. Убедимся, что формы успешно загружаются, а при сохранении изменений на форме списка городов, в карточке клиента обновляется список городов в CityComboBox.
Сохранение изменений в таблицу в базе данных
Запросы ClientInsertSqlQuery, ClientUpdateSqlQuery у нас уже есть. Давайте сделаем для них два SetDataConnection:
<DataConnection Name="ClientInsertSetDataConnection" Type="SetDataConnection" Assembly="DataConnections">
<Workflow Name="Template" />
<Parameters>
<Parameter NativeName="Name">
<Value>
<Object Name="NameTextBox" />
</Value>
</Parameter>
<Parameter NativeName="DateOfBirth">
<Value>
<Object Name="DateOfBirthDateTimePicker"/>
</Value>
</Parameter>
<Parameter NativeName="CityId">
<Value>
<Object Name="CityComboBox" />
</Value>
</Parameter>
<Parameter NativeName="Phone">
<Value>
<Object Name="PhoneTextBox" />
</Value>
</Parameter>
<Parameter NativeName="Email">
<Value>
<Object Name="EmailTextBox" />
</Value>
</Parameter>
</Parameters>
<SqlQueries>
<SqlQuery Name="ClientInsertSqlQuery" Type="Insert" />
</SqlQueries>
</DataConnection>
<DataConnection Name="ClientUpdateSetDataConnection" Type="SetDataConnection" Assembly="DataConnections">
<Workflow Name="Template" />
<Parameters>
<Parameter NativeName="ClientId">
<Value>
<Parameter Name="ClientId" />
</Value>
</Parameter>
<Parameter NativeName="Name">
<Value>
<Object Name="NameTextBox" />
</Value>
</Parameter>
<Parameter NativeName="DateOfBirth">
<Value>
<Object Name="DateOfBirthDateTimePicker"/>
</Value>
</Parameter>
<Parameter NativeName="CityId">
<Value>
<Object Name="CityComboBox" />
</Value>
</Parameter>
<Parameter NativeName="Phone">
<Value>
<Object Name="PhoneTextBox" />
</Value>
</Parameter>
<Parameter NativeName="Email">
<Value>
<Object Name="EmailTextBox" />
</Value>
</Parameter>
</Parameters>
<SqlQueries>
<SqlQuery Name="ClientUpdateSqlQuery" Type="Update" />
</SqlQueries>
</DataConnection>
Как вы помните, чтобы SetDataConnection выполнился, нужна команда SaveCommand, которая будет активировать соединение с данными для отправки. Давайте создадим две команды для каждого SetDataConnection:
<Command Name="ClientInsertSaveCommand" Type="SaveCommand" Assembly="Commands">
<DataConnections>
<DataConnection Name="ClientInsertSetDataConnection" />
</DataConnections>
</Command>
<Command Name="ClientUpdateSaveCommand" Type="SaveCommand" Assembly="Commands">
<DataConnections>
<DataConnection Name="ClientUpdateSetDataConnection" />
</DataConnections>
</Command>
Как вы помните, наш запрос ClientInsertSqlQuery возвращает идентификатор client_id новой записи. Команда ClientInsertSaveCommand получает этот идентификатор от ClientInsertSetDataConnection и записывает его в свой результат выполнения. Давайте создадим команду типа ValueSetCommand, которая запишет этот результат в параметр формы ClientId:
<Command Name="ClientIdValueSetCommand" Type="ValueSetCommand" Assembly="Commands">
<Parameter Name="ClientId">
<Command Name="ClientInsertSaveCommand" />
</Parameter>
</Command>
Это нам нужно для того, чтобы на родительской форме мы могли использовать идентификатор нового клиента.
Скорректируем синтаксис команды SaveSequentialCommand, которая уже есть в коде:
<Command Name="SaveSequentialCommand" Type="SequentialCommand" Assembly="Commands">
<Commands>
<If>
<When>
<Parameter Name="Edit" />
</When>
<Then>
<Command Name="ClientUpdateSaveCommand" />
</Then>
<Else>
<Command Name="ClientInsertSaveCommand" />
<Command Name="ClientIdValueSetCommand" />
</Else>
</If>
<Command Name="UpdatedTrueValueSetCommand" />
<Command Name="FormCloseCommand" />
</Commands>
</Command>
Вернемся в файл стартовой формы (TemplateStart.xml). Здесь мы получим значение параметра ClientId из команды ClientEditFormShowCommand, которое будем использовать для выделение строки в таблице ClientDatabaseTable. Это позволит пользователю убедиться в том, что новая запись успешно сохранилась. Для выделения строки в таблице создадим следующую команду:
<Command Name="ClientSelectInTableValueSetCommand" Type="ValueSetCommand" Assembly="Commands">
<Object Name="ClientDatabaseTable">
<Property Name="SelectRowByFieldValue">
<Parameters>
<Parameter Name="ColumnName">ClientId</Parameter>
<Parameter Name="Value">
<Command Name="ClientEditFormShowCommand" Parameter="ClientId" />
</Parameter>
</Parameters>
</Property>
</Object>
</Command>
Добавьте вызов этой команды в Execution по изменению параметра Updated у команды ClientEditFormShowCommand после вызова команды типа DataConnectionRefreshCommand.
Перезапустите проект. Убедитесь, что формы успешно загружаются, и происходит выделение строки нового клиента.
Удаление записей
Вернемся в файл стартовой формы (TemplateStart.xml) и реализуем функционал удаления записей из таблицы клиентов.
У нас уже есть sql-запрос на удаление записи в таблице template.client в базе данных. Давайте создадим SetDataConnection для этого запроса:
<DataConnection Name="ClientDeleteSetDataConnection" Type="SetDataConnection" Assembly="DataConnections">
<Workflow Name="Template" />
<Parameters>
<Parameter NativeName="ClientId">
<Value>
<Object Name="ClientDatabaseTable">
<Property Name="SelectedRowCellValueByColumnName">
<Parameters>
<Parameter Name="ColumnName">ClientId</Parameter>
</Parameters>
</Property>
</Object>
</Value>
</Parameter>
</Parameters>
<SqlQueries>
<SqlQuery Name="ClientDeleteSqlQuery" Type="Delete" />
</SqlQueries>
</DataConnection>
Sql-запрос ожидает только один параметр ClientId. В качестве значения в этот параметр передадим значение из одноименной колонки выделенной строки таблицы ClientDatabaseTable.
После удаления записи из таблицы в базе данных нам нужно будет обновить данные, получаемые из ClientPrimaryGetDataConnection. Это можно сделать используя знакомую нам команду DataConnectionRefreshCommand. А можно использовать более компактный способ обновить DataConnection.
У SetDataConnection и DatabaseTableSetDataConnection есть необязательный тэг <Refresh>
, в качестве значения которого указывается список тэгов <DataConnection>
c именами загружающих соединений с данными, которые будут обновлены после выполнения сохранения.
Давайте добавим такой тэг в наш ClientDeleteSetDataConnection. Таким образом, общий синтаксис соединения с данными для отправки будет выглядеть так:
<DataConnection Name="ClientDeleteSetDataConnection" Type="SetDataConnection" Assembly="DataConnections">
<Workflow Name="Template" />
<Parameters>
<Parameter NativeName="ClientId">
<Value>
<Object Name="ClientDatabaseTable">
<Property Name="SelectedRowCellValueByColumnName">
<Parameters>
<Parameter Name="ColumnName">ClientId</Parameter>
</Parameters>
</Property>
</Object>
</Value>
</Parameter>
</Parameters>
<SqlQueries>
<SqlQuery Name="ClientDeleteSqlQuery" Type="Delete" />
</SqlQueries>
<Refresh>
<DataConnection Name="ClientPrimaryGetDataConnection" />
</Refresh>
</DataConnection>
Самостоятельно создайте команду SaveCommand для нового DataConnection и пропишите ее в тэге <Commands>
кнопки "Удалить запись...".
Перезапустите проект. Убедитесь, что форма успешно загружена, и попытайтесь удалить, создать и обновить записи в таблице.

Итоги
На уроке мы узнали, что помимо паттернов форм, есть сниппеты, которые позволяют вставлять куски кода в редактируемый файл. Сниппеты ускоряют процесс наполнения формы объектами.
Также рассмотрели использование универсального значения Input, которое позволяет передавать в команду значения параметров в месте вызова команды, а не при ее описании.
Еще с первого урока у нас есть проблема с отсутствием проверки корректности введенных пользователем данных. На следующем уроке рассмотрим, как это сделать корректно и удобно для пользователя. Также рассмотрим паттерн onClose, суть которого заключается в проверке наличия изменений на форме и уведомлении пользователя о них при попытке закрыть форму без сохранения.
Ответы
В архиве присутствуют xml-файлы форм и серверный xml-файл, также лежит бэкап базы данных и файл с запросами на изменение структуры базы данных - с помощью файлов можете проверить себя.
Last updated