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