Урок 8. Редактирование выпадающего списка

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

Нам понадобятся иконки из архива:

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

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

При разворачивании проекта используйте backup базы данных, который можете найти в архиве из раздела Ответы прошлого урока. Скопируйте папки Forms, Workflow и Patterns в папку с развернутым проектом, например, в папку D:\WT\Projects\Template\Projects\1. Template.

Инструкция по подключению шаблонов находится по ссылке.

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

Перейдем в файл карточки заказа (TemplateOrderEdit.xml), где нам необходимо добавить кнопку, по которой будем открывать форму карточки клиента.

Пользователь может выбрать клиента из выпадающего списка, а может ввести имя клиента, которого еще нет в базе данных. Если пользователь выбрал существующего клиента, то по кнопке редактирования будет открываться карточка с данными этого клиента. Если пользователь ввел имя нового клиента, то будет открываться карточка нового клиента, в которую будет передаваться введенное имя для заполнения поля "Имя (ФИО)".

Первым делом добавим команды на открытие формы TemplateClientEdit.xml для создания и редактирования клиента:

TemplateOrderEdit.xml
<Command Name="ClientAddFormShowCommand" Type="FormShowCommand" Assembly="Commands">
  <Xml Type="Path">TemplateClientEdit.xml</Xml>
  <Show Type="None" />
  <Parameters>
    <Parameter Name="ClientTitle">
      <Object Name="ClientComboBox">
        <Property Name="Text" />
      </Object>
    </Parameter>
  </Parameters>
</Command>

<Command Name="ClientEditFormShowCommand" Type="FormShowCommand" Assembly="Commands">
  <Xml Type="Path">TemplateClientEdit.xml</Xml>
  <Show Type="None" />
  <Parameters>
    <Parameter Name="Edit">True</Parameter>
    <Parameter Name="ClientId">
      <Object Name="ClientComboBox" />
    </Parameter>
  </Parameters>
</Command>

В команде ClientAddFormShowCommand на дочернюю форму передается параметр ClientTitle. В нем будет храниться значение, которое пользователь вводит в ClientComboBox.

Добавим кнопку редактирования клиента сразу же под описанием ClientComboBox:

TemplateOrderEdit.xml
<MyObject Name="ClientAddEditButton" Type="Button" Assembly="BaseControls">
  <Top>
    <Object Name="ClientComboBox">
      <Property Name="Top" />
    </Object>
  </Top>
  <Left>
    <Calculate>
      <Expression>{0} + 5</Expression>
      <Items>
        <Item>
          <Object Name="ClientComboBox">
            <Property Name="Right" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Left>
  <Height>22</Height>
  <Width>22</Width>
  <BackgroundImage>
    <Switch>
      <Case>
        <When>
          <Condition Name="ClientComboBoxIsNullOrEmptyCondition" />
        </When>
        <Then>Images\16x16\plus.png</Then>
      </Case>
      <Case>Images\16x16\pencil.png</Case>
    </Switch>
  </BackgroundImage>
  <BackgroundImageLayout>Center</BackgroundImageLayout>
  <Hint>
    <Switch>
      <Case>
        <When>
          <Condition Name="ClientComboBoxIsNullOrEmptyCondition" />
        </When>
        <Then>Добавить запись...</Then>
      </Case>
      <Case>Редактировать запись...</Case>
    </Switch>
  </Hint>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Commands>
    <If>
      <When>
        <Condition Name="ClientComboBoxIsNullOrEmptyCondition" />
      </When>
      <Then>
        <Command Name="ClientAddFormShowCommand" />
      </Then>
      <Else>
        <Command Name="ClientEditFormShowCommand" />
      </Else>
    </If>
  </Commands>
</MyObject>

Скорректируйте ширину ClientComboBox, учитывая ширину новой кнопки и отступ между объектами.

С помощью условия ClientComboBoxIsNullOrEmptyCondition мы определяем, какая иконка будет отображаться на кнопке, и какая команда на открытие формы будет выполняться.

Теперь нам необходимо реализовать логику обработки результата команд ClientAddFormShowCommand и ClientEditFormShowCommand:

TemplateOrderEdit.xml
<Execution>
  <ConditionExpression>
    <Command Name="ClientAddFormShowCommand" Parameter="Updated" />
  </ConditionExpression>
  <Commands>
    <Command Name="ClientDataConnectionRefreshCommand" />
    <Command Name="ClientComboBoxValueSetCommand">
      <Command Name="ClientAddFormShowCommand" Parameter="ClientId" />
    </Command>
  </Commands>
</Execution>

<Execution>
  <ConditionExpression>
    <Command Name="ClientEditFormShowCommand" Parameter="Updated" />
  </ConditionExpression>
  <Commands>
    <Command Name="ClientDataConnectionRefreshCommand" />
  </Commands>
</Execution>

Если при создании нового клиента пользователь сохранил изменения, то мы обновляем список клиентов и подставляем в ClientComboBox идентификатор новой записи. А если было редактирование клиента, то просто обновляем список.

Самостоятельно создайте команды ClientDataConnectionRefreshCommand и ClientComboBoxValueSetCommand. Обратите внимание, что синтаксис вызова команды ClientComboBoxValueSetCommand подразумевает использование конструкции <Input>.

Перейдем в файл карточки клиента (TemplateClientEdit.xml). Добавим на форму параметр ClientTitle и скорректируем значение тэга <Text> объекта NameTextBox с учетом нового параметра:

TemplateClientEdit.xml
<MyObject Name="NameTextBox" Type="TextBox" Assembly="BaseControls">
  <Top>
    <Object Name="NameLabel">
      <Property Name="Bottom" />
    </Object>
  </Top>
  <Left>
    <Object Name="NameLabel">
      <Property Name="Left" />
    </Object>
  </Left>
  <Width>
    <Calculate>
      <Expression>{0} - {1} - 10</Expression>
      <Items>
        <Item>
          <Object Name="ContentPanel">
            <Property Name="Width" />
          </Object>
        </Item>
        <Item>
          <Object Name="NameTextBox">
            <Property Name="Left" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Width>
  <Text>
    <Switch>
      <Case>
        <When>
          <Parameter Name="Edit" />
        </When>
        <Then>
          <DataConnection SourceDataConnection="ClientPrimaryGetDataConnection">
            <Fields>
              <Field Name="Name" />
            </Fields>
          </DataConnection>
        </Then>
      </Case>
      <Case>
        <Parameter Name="ClientTitle" />
      </Case>
    </Switch>
  </Text>
</MyObject>

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

Отлично! Можем двигаться дальше.

Форма списка в режиме выбора

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

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

Для этого нам нужно:

  • На форме заказа создать кнопку доступа к форме списка клиентов;

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

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

Кнопка списка

Начнем с карточки заказа.

Вернемся в файл TemplateOrderEdit.xml и первым делом создадим команду на открытие списка клиентов:

TemplateOrderEdit.xml
<Command Name="ClientListFormShowCommand" Type="FormShowCommand" Assembly="Commands">
  <Xml Type="Path">TemplateClientList.xml</Xml>
  <Show Type="None" />
  <Parameters>
    <Parameter Name="SelectionMode">True</Parameter>
    <Parameter Name="SelectedClientId">
      <Object Name="ClientComboBox" />
    </Parameter>
    <Parameter Name="ClientTitle">
      <Object Name="ClientComboBox">
        <Property Name="Text" />
      </Object>
    </Parameter>
  </Parameters>
</Command>

Параметром SelectionMode будем активировать режим выбора на форме списка клиентов.

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

А если пользователь ввел имя, которого еще нет в базе, то его значение передаем в параметре ClientTitle. Этот параметр пригодится, когда с формы списка будем создавать нового клиента.

Создадим кнопку для доступа к списку клиентов:

TemplateOrderEdit.xml
<MyObject Name="ClientListButton" Type="Button" Assembly="BaseControls">
  <Top>
    <Object Name="ClientComboBox">
      <Property Name="Top" />
    </Object>
  </Top>
  <Left>
    <Calculate>
      <Expression>{0} + 5</Expression>
      <Items>
        <Item>
          <Object Name="ClientAddEditButton">
            <Property Name="Right" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Left>
  <Height>
    <Object Name="ClientAddEditButton">
      <Property Name="Height" />
    </Object>
  </Height>
  <Width>
    <Object Name="ClientAddEditButton">
      <Property Name="Width" />
    </Object>
  </Width>
  <BackgroundImage>Images\16x16\list.png</BackgroundImage>
  <BackgroundImageLayout>Center</BackgroundImageLayout>
  <Hint>Клиенты...</Hint>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Commands>
    <Command Name="ClientListFormShowCommand" />
  </Commands>
</MyObject>

Скорректируйте размер самого ClientComboBox, учитывая размеры новой кнопки.

Добавим обработку результата команд ClientListFormShowCommand:

TemplateOrderEdit.xml
<Execution>
  <ConditionExpression>
    <Command Name="ClientListFormShowCommand" Parameter="Updated" />
  </ConditionExpression>
  <Commands>
    <Command Name="ClientDataConnectionRefreshCommand" />
    <Command Name="ClientComboBoxValueSetCommand">
      <Command Name="ClientListFormShowCommand" Parameter="SelectedClientId" />
    </Command>
  </Commands>
</Execution>

Обновляем список клиентов и подставляем в ClientComboBox идентификатор записи, которую выбрали на форме списка.

Запустите проект и проверьте загрузку карточки заказа и отображение объектов на форме.

Теперь можем заняться формой списка.

Режим выбора

Перейдем в файл списка клиентов (TemplateClientList.xml) и первым делом добавим на форму параметры, которые получаем из карточки заказа:

TemplateClientList.xml
<Parameter Name="SelectionMode">False</Parameter>
<Parameter Name="ClientTitle" />
<Parameter Name="SelectedClientId" />

Дополним интерфейс формы панелью FootPanel, на которой будет размещаться кнопка "Выбрать":

TemplateClientList.xml
<MyObject Name="FootSeparatePanel" Type="Panel" Assembly="BaseControls">
  <Bottom>
    <Object Name="FootPanel">
      <Property Name="Top" />
    </Object>
  </Bottom>
  <Left>5</Left>
  <Height>1</Height>
  <Width>
    <Calculate>
      <Expression>{0} - 10</Expression>
      <Items>
        <Item>
          <Form>
            <Property Name="Width" />
          </Form>
        </Item>
      </Items>
    </Calculate>
  </Width>
  <AutoScroll>False</AutoScroll>
  <BackColor>ThemeSeparateBackgroundColor</BackColor>
  <Visible>
    <Parameter Name="SelectionMode" />
  </Visible>
</MyObject>

<MyObject Name="FootPanel" Type="Panel" Assembly="BaseControls">
  <Bottom>
    <Form>
      <Property Name="Height" />
    </Form>
  </Bottom>
  <Left>0</Left>
  <Height>40</Height>
  <BackColor>ThemeBackgroundColor</BackColor>
  <Width>
    <Form>
      <Property Name="Width" />
    </Form>
  </Width>
  <Visible>
    <Parameter Name="SelectionMode" />
  </Visible>

  <!-- SelectionButton -->
</MyObject>

Видимость объектов FootSeparatePanel и FootPanel будет определяться параметром SelectionMode.

Скорректируем высоту ContentPanel:

<Height>
  <Calculate>
    <Expression>{0} - {1}</Expression>
    <Items>
      <Item>
        <Switch>
          <Case>
            <When>
              <Parameter Name="SelectionMode" />
            </When>
            <Then>
              <Object Name="FootSeparatePanel">
                <Property Name="Top" />
              </Object>
            </Then>
          </Case>
          <Case>
            <Form>
              <Property Name="Height" />
            </Form>
          </Case>
        </Switch>
      </Item>
      <Item>
        <Object Name="ContentPanel">
          <Property Name="Top" />
        </Object>
      </Item>
    </Items>
  </Calculate>
</Height>

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

TemplateClientList.xml
<Command Name="SelectedClientIdValueSetCommand" Type="ValueSetCommand" Assembly="Commands">
  <Parameter Name="SelectedClientId">
    <Object Name="ClientDatabaseTable">
      <Property Name="SelectedRowCellValueByColumnName">
        <Parameters>
          <Parameter Name="ColumnName">ClientId</Parameter>
        </Parameters>
      </Property>
    </Object>
  </Parameter>
</Command>

<Command Name="SelectedArchiveClientMessageBoxCommand" Type="MessageBoxCommand" Assembly="Commands">
  <Caption />
  <Text>Нельзя выбрать запись, находящуюся в архиве.</Text>
  <Icon Type="Warning" />
  <Buttons Type="Ok" />
</Command>

<Command Name="SelectClientSequentialCommand" Type="SequentialCommand" Assembly="Commands">
  <Commands>
    <If>
      <When>
        <Condition Name="SelectedClientIsArchiveCondition" />
      </When>
      <Then>
        <Command Name="SelectedArchiveClientMessageBoxCommand" />
      </Then>
      <Else>
        <Command Name="SelectedClientIdValueSetCommand" />
        <Command Name="UpdatedTrueValueSetCommand" />
        <Command Name="FormCloseCommand" />
      </Else>
    </If>
  </Commands>
</Command>

Скорректируем Execution на обработку условия двойного клика по ячейки таблицы (ClientDatabaseTableCellDoubleClickCondition), добавив проверку параметра SelectionMode:

TemplateClientList.xml
<Execution>
  <ConditionExpression>
    <Condition Name="ClientDatabaseTableCellDoubleClickCondition" />
  </ConditionExpression>
  <Commands>
    <If>
      <When>
        <Parameter Name="SelectionMode" />
      </When>
      <Then>
        <Command Name="SelectClientSequentialCommand" />
      </Then>
      <ElseIf>
        <When>
          <Condition Name="SelectedClientIsArchiveCondition" />
        </When>
        <Then>
          <Command Name="EditingArchiveClientMessageBoxCommand" />
        </Then>
      </ElseIf>
      <Else>
        <Command Name="ClientEditSequentialCommand" />
      </Else>
    </If>
  </Commands>
</Execution>

Создадим кнопку выбора клиента, скопировав код в FootPanel:

TemplateClientList.xml
<MyObject Name="SelectionButton" Type="Button" Assembly="BaseControls">
  <Top>5</Top>
  <Right>
    <Formula>
      <Minus DataType="IntegerDataType">
        <Item>
          <Object Name="FootPanel">
            <Property Name="Right" />
          </Object>
        </Item>
        <Item>5</Item>
      </Minus>
    </Formula>
  </Right>
  <Height>30</Height>
  <Width>200</Width>
  <TextAlign>MiddleCenter</TextAlign>
  <FontStyle>ButtonFontStyle</FontStyle>
  <ImageAlign>MiddleLeft</ImageAlign>
  <Image>Images\24x24\check.png</Image>
  <Text>Выбрать</Text>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Enabled>
    <Condition Name="ClientSelectedCondition" />
  </Enabled>
  <Commands>
    <Command Name="SelectClientSequentialCommand" />
  </Commands>
  <DisabledMode>True</DisabledMode>
  <DisabledText>Чтобы продолжить, необходимо выбрать запись в таблице.</DisabledText>
</MyObject>

Запустите проект и проверьте, как работает выбор клиента из карточки заказа.

На форму списка клиентов передаем параметр ClientTitle, давайте скорректируем команду ClientEditFormShowCommand так, чтобы этот параметр передавался на карточку клиента:

TemplateClientList.xml
<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>
    <Parameter Name="ClientTitle">
      <Parameter Name="ClientTitle" />
    </Parameter>
  </Parameters>
</Command>

Запустите проект и проверьте работу форм списка клиента и карточек заказа и клиента.

Самостоятельно

Поиск клиента по имени

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

Для задания понадобятся изображения из архива:

Создайте панель со строкой поиска (SearchKeywordsTextBox) и кнопками "Поиск" (SearchButton) и "Сбросить" (SearchResetButton).

Поиск клиента по имени будет выступать в роли глобального фильтра. Используйте переменную Variable для хранения значения фильтра и передачи его в параметр (SearchKeywords) в ClientPrimaryGetDataConnection.

Не забудьте про атрибут RefreshQuery у тэга <Parameter>, чтобы не допустить обновление PrimaryGetDataConnection при изменении значения переменной. Для обновления соединения с данными есть команда ClientDataConnectionRefreshCommand.

В качестве значения переменной и поля SearchKeywordsTextBox используйте параметр ClientTitle.

По кнопке SearchButton значение из текстового поля сохраняйте в переменную Variable и вручную обновляйте ClientPrimaryGetDataConnection.

По кнопке SearchResetButton сбрасывайте значение у переменной и текстового поля SearchKeywordsTextBox и вручную обновляйте ClientPrimaryGetDataConnection.

Обе кнопки должны быть доступны, если поле SearchKeywordsTextBox заполнено.

В запросе ClientSelectSqlQuery в выражении WHERE используйте условие:

{SearchKeywords} ISNULL OR client.title ilike '%' || {SearchKeywords} ||'%'

Выделение клиента в таблице

На форму списка клиентов в параметр SelectedClientId передаем идентификатор клиента, выбранного в выпадающем списке на родительской форме. Создайте <Execution>, который по условию FormLoadedCondition будет вызывать команду на выделение нужной записи в таблице.

Итоги

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

Ответы

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

Last updated