Многие из тех, кто программировал на платформе 7.7, сталкивались с задачей доработки стандартных форм подбора номенклатуры, например, в ТиС. Пользователи часто желали видеть в одной таблице и остатки, и цены, да чтобы еще можно было отфильтровать список, например, по ненулевым остаткам. Создать произвольную форму списка стандартными средствами, которая бы при этом еще и не тормозила при листании и поиске на списках приличного размера, было не так-то просто. Честно говоря, именно такого рода задачи привели меня в свое время к использованию известных внешних компонент, которые позволяли семерке более эффективно получать данные запросами и отображать списки в альтернативных контролах. Ну а когда я начал осваивать платформу 8.2 и познакомился в общих чертах с ее базовыми механизмами, мне захотелось проверить, насолько проще можно решить подобные задачи теперь.
Итак, на управляемых формах попробуем создать простейшую форму для подбора номенклатуры, так, чтобы в списке отображался остаток и цена, и можно было выводить только те строчки, по которым есть остаток. Предполагаем что у нас уже есть справочник Номенклатура, документ Реализация, регистр накопления ОстаткиНоменклатуры и регистр сведений ЦеныНоменклатуры.
Создаем новую управляемую форму списка для справочника Номенклатура. Если созданная форма прописалась, как основная форма списка справочника, очистим это поле, дабы наша новая форма подбора открывалась только в нужном нам месте, а не везде, где предусмотрено открытие формы списка по умолчанию. Указываем мастеру, какие реквизиты справочника мы желаем видеть в списке, пусть это будут Код и Наименование. Выбираем детищу имя, например ФормаПодбора.
Теперь нас будет интересовать основной реквизит этой формы, имеющий тип ДинамическийСписок и имя ему - просто Список. В списке реквизитов формы основной реквизит отображается жирным шрифтом, я выделил его на картинке. Заглянем в его свойства, система автоматом установила для него основную таблицу, данные из которой и будут помещаться в список и отображаться на форме. Именно установка в качестве основной таблицы справочника позволит списку выглядеть и функционировать именно как список справочника, со всеми присущими ему иконками и командами. Так же установлен флажок "Динамическое считывание данных", это свойство позволяет отображать на лету изменения, происходящие с номенклатурой, например, в сеансах других пользователей - добавление новых записей, например.
Нас же больше всего интересует флажок "Произвольный запрос". Именно его установка позволит нам изменить набор данных, который окажется в нашем списке. Устанавливаем флажок и переходим по появившейся снизу ссылке "Настройка списка - открыть".
Видим, что платформа любезно подготовила для нас текст запроса, который пока что позволяет нам получит все тот же обычный список номенклатуры с наименованием, кодом и другими реквизитами справочника. Но теперь у нас есть возможность отредактировать этот запрос! Можем воспользоваться конструктором запроса или написать текст вручную, кто как привык.
Быстренько добавляем левые соединения с виртуальными таблицами остатков и цен, задаем нужные параметры, нам пока достаточно даты получения остатков и цен, и типа цены (конечно, такое измерение уже должно быть в нашем регистре сведений). Запрос готов.
Любопытства ради переходим на закладку настройки - и вот оно, счастье вчерашнего семерочника! Без всякого программирования, в самой первой закладке имеем возможность задавать любые интересуюшие нас отборы по полям, отбираемым в запросе! И главное - ровно все то же самое будет доступно и в пользовательском режиме! Выбрав в стандартных действиях пункт "Настроить список", пользователь увидит точно такое же окно настроек. Немного облегчим ему жизнь, заранее добавив отбор по полю Количество. Пользователю останется лишь установить флажок активности созданного нами отбора, когда это потребуется.
Закрываем форму настройки списка и продолжаем облагораживание нашей формы подбора. Добавляем булевский реквизит ЗапрашиватьКоличество и таблицу значений Корзина, в ней мы будем отображать уже выбранную номенклатуру с количеством, ждущую переноса в документ. Перетаскиваем созданные реквизиты на форму, располагаем, как нам нравится. Кстати, нужно не забыть, что у реквизита Список, благодаря нашему новому запросу, появились новые доступные поля - Количество и Цена, перетаскиваем на форму и их тоже:
Теперь вспоминаем, что запрос у нас содержит два параметра, которые мы должны получить из формы документа, в которой будем вызывать подбор, и передать в запрос. Для этой цели неплохо подойдут параметры формы, создаем два параметра нужных типов:
Переходим к модулю формы. Прописываем установку параметров в запрос, для этого идеально подойдет событие формы ПриСозданииНаСервере(), оно отрабатывает самым первым до открытия формы. Для передачи параметров используется специальная коллекция Параметры, присутствующая у реквизита формы Список:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Список.Параметры.УстановитьЗначениеПараметра("Период", Параметры.Дата);
Список.Параметры.УстановитьЗначениеПараметра("ТипЦен", Параметры.ТипЦен);
КонецПроцедуры
Прописываем обработку двойного клика по списку номенклатуры. В клиентском контексте, где у нас выполняются все обработчики типа кликов и нажатий, тип данных ТаблицаЗначений недоступен, а созданный нами реквизит формы Корзина лишь "маскируется" под ТЗ, на самом деле это служебный тип данных, ДанныеФормыКоллекция, предназначенный только для отображения ТЗ на форме. Поэтому работу с реальной ТЗ (поиск и добавление строк) переносим в серверную процедуру. Для преобразований между служебным типом данных и настоящей ТЗ и обратно используются две функции глобального контекста: ДанныеФормыВЗначение() и ЗначениеВДанныеФормы(). Отключаем стандартную обработку, чтобы при клике на списке не открывалась форма элемента.
&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Если ЗапрашиватьКоличество Тогда
ДобавитьКоличество = 0;
Если ВвестиЧисло(ДобавитьКоличество, "Введите количество единиц", 15, 3) Тогда
ДобавитьВПодбор(ВыбраннаяСтрока, ДобавитьКоличество);
КонецЕсли;
Иначе
ДобавитьВПодбор(ВыбраннаяСтрока, 1);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ДобавитьВПодбор(Номенклатура, Количество)
ТЗ = ДанныеФормыВЗначение(Корзина, Тип("ТаблицаЗначений"));
Строка = ТЗ.Найти(Номенклатура, "Номенклатура");
Если Строка = Неопределено Тогда
Строка = ТЗ.Добавить();
Строка.Номенклатура = Номенклатура;
КонецЕсли;
Строка.Количество = Строка.Количество + Количество;
ЗначениеВДанныеФормы(ТЗ, Корзина);
КонецПроцедуры // ДобавитьВПодбор()
Теперь корзина у нас заполняется выбранной номенклатурой и количеством. Остается организовать передачу корзины в вызывающий документ. Добавляем команду формы ПеренестиВДокумент, перетаскиваем ее на форму, получаем связанную с командой кнопку. Создаем обработчик команды. Поскольку форму мы изначально создавали как форму списка, а не форму выбора, нам придется принудительно оповестить вызывающую форму о том, что выбор завершен:
&НаКлиенте
Процедура ПеренестиВДокумент(Команда)
Результат = Новый Структура;
Результат.Вставить("Корзина", Корзина);
ОповеститьОВыборе(Результат);
КонецПроцедуры
На этом желаемый результат достигнут - мы создали примитивную форму подбора, содержащую список номенклатуры с остатком и ценой, которая может накапливать выбираемые товары и количества и передавать их в вызывающий документ. Приведем лишь пример вызова этой формы из некоторого документа, условно назовем его Реализация, с передачей необходимых параметров.
По нажатию на кнопку Подбор вызываем созданную форму и передаем параметры. Обращаю внимание на обязательную передачу в открываемую форму параметра ЭтаФорма (третий параметр в вызове формы, форма-владелец). Если этот параметр не передать, то событие ОбработкаПодбора() не возникнет в контесте формы вызывающего документа.
&НаКлиенте
Процедура Подбор(Команда)
ДатаПодбора = ?(ЗначениеЗаполнено(Объект.Ссылка), Объект.Дата, '00010101');
ПараметрыПодбора = Новый Структура;
ПараметрыПодбора.Вставить("Дата", ДатаПодбора);
ПараметрыПодбора.Вставить("ТипЦен", Объект.ТипЦен);
ФормаВыбора = ОткрытьФорму("Справочник.Номенклатура.Форма.ФормаПодбора", ПараметрыПодбора, ЭтаФорма);
КонецПроцедуры
Ну и, собственно, то, ради чего все затевалось - разбираем "корзину" и добавляем новые строки в табличную часть Товары нашего документа. На всякий случай, не забываем, что Корзина у нас не настоящая ТЗ, а служебная коллекция ДанныеФормыКоллекция:
&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
Если ТипЗнч(ВыбранноеЗначение) = Тип("Структура") Тогда
Если ВыбранноеЗначение.Свойство("Корзина") Тогда
Для каждого Элемент Из ВыбранноеЗначение.Корзина Цикл
Элементы.Товары.ДобавитьСтроку();
ТД = Элементы.Товары.ТекущиеДанные;
ТД.Номенклатура = Элемент.Номенклатура;
ТД.Количество = Элемент.Количество;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Вот и все. Надеюсь, моя скромная заметка кому-то поможет побыстрее разобраться с динамическими списками и управляемыми формами.