Урок 4. Редактирование списка

На прошлом уроке создали экран редактирования заказа, но реализацию возможности изменять клиента и редактировать позиции заказа оставил на этот урок.

Скачайте архив с изображениями и разархивируйте его в папку проекта \Template\Projects\1. Template\MobileForms\Images.

3KB
Open

Редактирование клиента

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

TemplateOrderEdit.xml
<Command Name="ClientSelectFormShowCommand" Type="FormShowCommand" Assembly="Commands">
  <Xml Type="Path">TemplateClientSelect.xml</Xml>
  <Show Type="None" />
  <Parameters>
    <Parameter Name="ClientId">
      <DataConnection SourceDataConnection="OrderPrimaryGetDataConnection">
        <Fields>
          <Field Name="ClientId" />
        </Fields>
      </DataConnection>
    </Parameter>
  </Parameters>
</Command>

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

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

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

Строка поиска будет представлена объектом типа Panel с именем SearchPanel, содержащим элементы:

  • SearchButton - хоть и является объектом типа Button, но это просто изображение лупы, не выполняющее никакой команды

  • SearchTextBox - текстовое поле для ввода строки поиска

  • ClearSearchButton - кнопка с изображением повернутого крестика для очистки строки поиска

Объект SearchPanel будет иметь настройки BorderCorner и BackColor аналогичные тем, что делали для панелей блоков на экране заказа. Высота панели 40 единиц.

Объект SearchButton будет иметь код:

Самостоятельно создайте объект SearchTextBox, который будет справа от SearchButton без отступов. По высоте текстовое поле должно совпадать с высотой панели, следовательно отступ сверху будет нулевым. Ширина текстового поля должна учитывать размер кнопки ClearSearchButton и оставлять отступ справа в 10 единиц. Для объекта SearchTextBox текст-подсказки будет "Поиск". А его цвет зависит от оформления системы: для темной темы используется DarkGray, а для светлой темы - LightGray. Цвет основного текста (тэг <ForeColor>) тоже зависит от выбранного оформления системы: для темной темы используется WhiteSmoke, а для светлой темы - MostlyBlack. Значение тэга <BackColor> можно тянуть из аналогичного свойства объекта SearchPanel. В тэге <FontStyle> укажем значение TextFont. По умолчанию TextBox имеет рамку, чтобы ее убрать используем тэг <Multiline> со значением True.

Кнопка ClearSearchButton для сброса значения объекта SearchTextBox будет иметь вид:

Самостоятельно создайте команду ResetSearchStringValueSetCommand.

Запустите приложение и проверьте отображение строки поиска на экране выбора клиента.

Отлично!

Самостоятельно добавьте на форму список с клиентами ClientCollectionView. В качестве источника данных используйте SecondaryGetDataConnection, в котором должны быть отфильтрованные по строке поиска данный из PrimaryGetDataConnection.

Запрос на получение списка клиентов должен содержать поля:

В результате у вас должна получиться форма вида:

Запустите приложение и проверьте работу фильтра списка:

Выбор клиента

Добавим на форму параметры, в которых будем возвращать на родительскую форму данные выбранного клиента:

Добавьте команды типа ValueSetCommand, в которых всем параметрам формы, включая ClientId, присваиваются данные выбранного клиента.

Все команды объединим в одну последовательность:

Добавим условие на изменение выбранной записи, в котором будем проверять значение get-проперти SelectedItemChanged:

На это условие создадим Execution, в котором будем сохранять данные в параметры, ставить флаг изменений и уходить с экрана выбора клиента:

Как видите на форме используем паттерн Updated - добавьте в файл параметр Updated и создайте команду для его обновления.

Замена клиента в заказе

Вернемся в файл описания карточки заказа и реализуем обновления данных о клиенте в OrderPrimaryGetDataConnection. Самостоятельно создайте команду типа ValueSetCommand, в которой заменяйте значения в полях DataConnection соответствующих возвращаемым параметрам. Реализуйте Execution, в котором будет вызываться эта команда, используя паттерн Updated.

Запустите приложение и проверьте функциональность смены клиента в заказе.

Дополнительно: на кнопку смены клиента наложите ограничение, если заказ оплачен.

Редактирование позиций заказа

Начнем с реализации возможности добавление позиций в заказ и изменение кол-ва товара в позиции. Для этого будем использовать отдельную форму со списком ТМЦ. А затем добавим удаление позиций с помощью свайпа в карточке заказа.

Подготовка

Первым делом создадим ConvertDataConnection, который будет преобразовывать OrderPositionPrimaryGetDataConnection:

Здесь мы добавляем поле ID, которое будет временным идентификатором, который будем передавать на форму со списком товаров, чтобы правильно выставить флаги Added, Upated и Deleted. О них подробнее позже. Так же добавили поле IsNew, флаг которым будем помечать позиции заказа не сохраненные в базе данных.

В качестве значения нового поля указали объект CounterVariable, который является переменной-счетчиком и каждый раз при обращении увеличивает текущее значение на единицу и возвращает его.

Укажем OrderPositionConvertDataConnection в качестве источника данных для объекта OrderPositionCollectionView.

Создадим форму, которую будем использовать для выбора товаров из каталога. Назовем ее TemplateMaterialList.xml.

Создадим команду для открытия новой формы:

На форму каталога передаем параметр MaterialArray с массивом добавленных товаров в заказ.

На экране редактирования заказа добавьте кнопку Изменить, укажите для нее команду MaterialListFormShowCommand. Кнопку разместите справа над списком позиций заказов:

Список товаров

Перейдем в файл новой формы и в него добавим строку поиска, как делали на форме выбора клиента.

С родительской формы передаем параметр MaterialArray, добавим его на форму, а чтобы было удобно работать с передаваемым массивом данных создадим ArrayGetDataConnection:

Создайте самостоятельно MaterialPrimaryGetDataConnection, который будет получать данные из запроса:

В качестве параметра в запрос передаем массив MaterialId, полученных с родительской формы.

Здесь так же возвращаем два поля с ценой за единицу товара: UnitPrice и UnitPriceString - значение из первого будем возвращать на родительскую форму и использовать для расчета итоговой стоимости, а второе для отображения в карточке товара.

Так же возвращаем два флага:

  • NotUse - true, если в заказе нет позиции с этим товаром, по этому флагу будет отображаться кнопка "Добавить" в карточке товара,

  • Selected - true, если в заказе есть позиция с этим товаром, по этому флагу будет отображаться количество товара и кнопки изменения.

Обернем загружающее соединение в ConvertDataConnection и добавим новые поля:

Поле TotalPrice необходимо для хранения итоговой суммы по выбранному товару.

В полях Quantity и ID подставляем соответствующие значения из массива полученного от родительской формы.

Поля Added, Updated и Deleted необходимы, чтобы при передачи на родительскую форму различать новые товары, которые нужно добавить через set-проперти AddRows, позиции в которых нужно обновить количество товара, и позиции подлежащие удалению из заказа.

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

Сразу создадим условие, в котором будем проверять наличие значения в поле ID:

Отлично, теперь можем реализовывать логику изменения позиций в заказе.

Добавление товара

В шаблоне карточки списка товаров MaterialCollectionView опишем кнопку Добавить:

Создадим команду MaterialAddValueSetCommand типа ValueSetCommand, используемую на кнопке:

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

Так же изменяем значения в полях Added, Updated и Deleted. Новые значения для Added и Updated зависят от наличия временного идентификатора на тот случай, если сначала удалили товар, и сразу нажали на кнопку Добавить. Если у товара есть временный ID, то мы должны рассматривать изменение существующего, а не добавление нового.

Управление количеством

Первой опишем кнопку уменьшения количества:

В условие QuantityOfSelectedMaterialGreater1Condition проверяем количество на больше единицы, чтобы определить, какую команду следует выполнить. Если количество больше единицы, то будем его уменьшать на единицу, а если равно единицы, то меняем значения флагов NotUse и Selected на противоположные, а количество сбрасываем на 0.

Самостоятельно напишите условие и обе команды. Не забудьте менять значения в полях Added, Updated и Deleted, учитывая при этом временный ID. Если у товара нет временного идентификатора, то можно просто сбросить количество и не помечать его на удаление из карточки заказа. При уменьшении количества товара важно правильно

Текущее количество товара будем отображать в объекте:

Кнопка увеличения количества товара, будет выполнять только одну команду:

Самостоятельно создайте команду MaterialIncrementQuantityValueSetCommand.

Добавим в файл формы описание цвета, который используется в тэгах <BackColor> созданных элементов:

Запустим приложение, чтобы проверить отображение и работу новых элементов:

Отлично! Теперь можем реализовать логику передачи данных на родительский экран, где будем обновлять список позиций заказа.

Передача изменений

В заголовок формы (HeadPanel) добавим кнопку Сохранить:

Создайте самостоятельно команду SaveSequentialCommand типа SequentialCommand, оставив ее пока пустой.

Добавим параметры формы, в которых будем возвращать данные по товарам:

Создадим команды на запись данных в параметры.

Первой будет команда для параметра MaterialArrayToAdd. В нем будем получать из MaterialConvertDataConnection все записи, у которых в поле Added стоит значение True:

В параметр MaterialArrayToEdit будем добавлять те записи, у которых в поле Updated стоит значение True и дополнительно будем проверять значение в поле Added, чтобы оно было равно False:

В параметре храним все поля выбранных записей, т.к. информация о ТМЦ могла быть изменена в базе данных.

В параметре MaterialArrayToDelete будем передавать массив временных идентификаторов товаром, помеченных на удаление:

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

Объединим все три команды в ранее созданную команду SaveSequentialCommand:

Не забываем про паттерн Updated, чтобы на родительском экране корректно отработал Execution.

Внесение изменений

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

Первым делом создайте условие MaterialListFormUpdatedTrueEqualCondition для проверки возвращаемого параметра Updated и Execution, который будет выполняться по этому условию.

Далее будет описывать команды на внесение изменений в OrderPositionConvertDataConnection и добавлять их в созданный Execution.

Команда на добавление позиций в заказ:

Здесь разбираем данные из параметра MaterialArrayToAdd с помощью <Array> и добавляем новые строки в OrderPositionConvertDataConnection. Новые позиции помечаем в поле IsNew значением True.

Команда на изменение позиций заказа:

С помощью get-проперти RowsIndicesOf у ConvertDataConnection находим индексы строк, в которых нужно обновить информацию о товарах.

Чтобы при удалении позиций различать позиции сохраненные в базе данных и недавно добавленные в заказ, создадим объект Variable вида:

Объединяем два массива по временному идентификатору записей, и через селектор Number получаем индексы строк. Дальше в командах будем проверять значение во втором поле результирующей таблицы и по нему выделять позиции заказа сохраненные в базе данных.

Первом создадим команду для отмечания позиций на удаление из базы данных:

В поле Deleted ставим значение True - тем самым помечаем для удаления. Дополнительно сбрасываем значения итоговой цены и количества товара в позиции.

Позиций заказа, которые еще не сохраняли в базе данных, удаляем из OrderPositionConvertDataConnection:

Отлично! Добавим Новые команды в Execution:

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

Удаление позиции заказа

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

SwipeMenu

Свайп-меню настраивается в тэге <SwipeMenu>, определенном в CollectionView. Добавим в описание объекта OrderPositionCollectionView следующий код:

Тэг <RightItems> содержит список элементов меню <SwipeItem>, которые будут отображаться справа от карточки при свайпе влево. Если необходимо отображать меню слева от карточки (при свайпе вправо), то используем тэг <LeftItems>.

Элементы свайп-меню описываются тегом <SwipeItem>, в котором указывается текст надписи, путь до изображения, цвет фона и последовательность команд.

Добавим в файл описание используемого цвета для кнопки удаления:

Запустим приложение, чтобы проверить отображение свайп-меню:

Команды удаления

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

Команду OrderPositionDeleteMessageBoxCommand добавим в тэг <Commands> для <SwipeMenu> списка позиций заказа.

Создадим условие проверки, что выбранная запись была недавно добавлена в заказ и еще не сохранена в базе данных:

Создайте самостоятельно команду на удаление новой позиции заказа, назвав ее, например SwipeDeleteValueSetCommand, и команду на удаление из базы данных, например SwipeDeleteFromDatabaseCommand. Индексы строк, редактируемых в командах, следует получать из OrderPositionConvertDataConnection по значению из поля ID выбранной позиции заказа.

Создадим Execution, который будет отслеживать значение параметра Ok команды OrderPositionDeleteMessageBoxCommand, и в зависимости от условия SelectedOrderPositionIsNewEqualCondition будет вызывать одну из двух созданных выше команд.

Запустим приложение и проверим удаление позиций заказа.

Отлично! На следующем уроке рассмотрим работу с JSON на форме, для удобного сохранения

Итоги

На уроке мы рассмотрели .

Ответы

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

Last updated