В процессе разработки часто возникает задача интеграции с внешними системами через COM-соединение или HTTP-запросы. Полученные данные обычно помещаются в ТаблицуЗначений (ТЗ), и перед разработчиком встает вопрос: как удобно и правильно предоставить пользователю возможность выбора строк из этой таблицы для дальнейшей обработки в основной форме? Рассмотрим подробные механизмы реализации этой задачи в среде 1С:Предприятие 8.3 на управляемых формах.
Это классический и наиболее гибкий подход. Он позволяет реализовать сложную логику фильтрации, поиска и оформления строк. Основная идея заключается в создании вспомогательной формы, в которую передается наша ТЗ.
Шаг 1. Подготовка данных и открытие формы
Рассмотрим ситуацию, когда в основной форме мы уже получили таблицу через COM. Нам необходимо передать ее в форму подбора. Правильнее всего делать это через ВременноеХранилище, так как прямая передача больших таблиц через параметры может негативно сказаться на производительности.
&НаКлиенте
Процедура КомандаПодбор(Команда)
// Помещаем таблицу во временное хранилище
АдресДанных = ПоместитьДанныеВоВременноеХранилищеНаСервере();
ПараметрыПодбора = Новый Структура;
ПараметрыПодбора.Вставить("АдресДанных", АдресДанных);
ОткрытьФорму("Обработка.МояОбработка.Форма.ФормаПодбора",
ПараметрыПодбора,
ЭтаФорма,
Истина, , ,
Новый ОписаниеОповещения("ПослеЗакрытияПодбора", ЭтаФорма));
КонецПроцедуры
&НаСервере
Функция ПоместитьДанныеВоВременноеХранилищеНаСервере()
// Объект.ТЗВнешниеДанные - реквизит формы типа ТаблицаЗначений
Возврат ПоместитьВоВременноеХранилище(Объект.ТЗВнешниеДанные.Выгрузить(), ЭтаФорма.УникальныйИдентификатор);
КонецФункции
Шаг 2. Инициализация формы подбора
В форме подбора создадим реквизит СписокДляВыбора с типом ТаблицаЗначений. В обработчике ПриСозданииНаСервере загрузим данные.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
АдресДанных = Параметры.АдресДанных;
Если ЗначениеЗаполнено(АдресДанных) Тогда
ТЗ = ПолучитьИзВременногоХранилища(АдресДанных);
ЗначениеВРеквизитФормы(ТЗ, "СписокДляВыбора");
КонецЕсли;
КонецПроцедуры
Шаг 3. Обработка выбора пользователя
Разберем, как вернуть выбранное значение. Если нам нужно выбрать одну строку, используем событие Выбор элемента формы «Таблица».
&НаКлиенте
Процедура СписокДляВыбораВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ТекущиеДанные = Элемент.ТекущиеДанные;
// Формируем структуру с данными для возврата
Результат = Новый Структура;
Результат.Вставить("GUID", ТекущиеДанные.GUID);
Результат.Вставить("Наименование", ТекущиеДанные.Наименование);
ОповеститьОВыборе(Результат);
КонецПроцедуры
Если задача заключается в быстром выборе нескольких элементов из плоского списка и создание отдельной формы кажется избыточным, проанализируем использование метода ПоказатьОтметкуЭлементов. Этот метод выводит стандартное диалоговое окно со списком флажков.
Выясним, как это работает на практике:
СписокЗначений.
&НаКлиенте
Процедура ВыбратьИзСписка(Команда)
Список = Новый СписокЗначений;
Для Каждого СтрокаТЗ Из Объект.ТЗВнешниеДанные Цикл
Список.Добавить(СтрокаТЗ.GUID, СтрокаТЗ.Наименование);
КонецЦикла;
Оповещение = Новый ОписаниеОповещения("ЗавершитьВыбор", ЭтаФорма);
ПоказатьОтметкуЭлементов(Оповещение, Список, "Выберите объекты");
КонецПроцедуры
&НаКлиенте
Процедура ЗавершитьВыбор(ВыбранныеЭлементы, ДополнительныеПараметры) Экспорт
Если ВыбранныеЭлементы <> Неопределено Тогда
Для Каждого Элемент Из ВыбранныеЭлементы Цикл
// Логика добавления в ТЧ основной формы
ДобавитьСтрокуВДокумент(Элемент.Значение, Элемент.Представление);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Рассмотрим критически важный момент: объекты, полученные через COM-соединение, являются прокси-объектами. Если вы закроете соединение, попытка обратиться к ТекущиеДанные.Наименование, где данные ссылаются на COM-объект, вызовет ошибку «Объект не найден».
Рекомендация: При получении данных из COM-базы всегда выполняйте полное копирование данных в «родную» для текущей базы ТаблицуЗначений. Используйте примитивные типы (строка, число) или создавайте ссылки по GUID сразу при загрузке.
Проанализируем пример функции конвертации GUID в ссылку 1С:
&НаСервереБезКонтекста
Функция ПолучитьСсылкуПоУид(Знач СтрУид)
Попытка
Уид = Новый УникальныйИдентификатор(СтрУид);
Ссылка = Справочники.Номенклатура.ПолучитьСсылку(Уид);
// Проверяем существование объекта в нашей базе
Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
Возврат Справочники.Номенклатура.ПустаяСсылка();
КонецЕсли;
Возврат Ссылка;
Исключение
Возврат Справочники.Номенклатура.ПустаяСсылка();
КонецПопытки;
КонецФункции
Если внешняя таблица содержит тысячи строк, стандартный метод НайтиСтроки() может работать медленно. Посмотрим на альтернативный вариант с использованием объекта Соответствие.
При загрузке данных из COM создайте соответствие, где ключом будет уникальный идентификатор, а значением — структура данных или индекс строки. Поиск в Соответствии выполняется мгновенно вне зависимости от объема данных, так как использует механизм хеш-таблиц.
Разберем, почему важно использовать ОповеститьОВыборе вместо прямого обращения к ВладелецФормы. Обращение напрямую к реквизитам другой формы (например, ВладелецФормы.Объект.Товары.Добавить()) создает жесткую зависимость между формами. Это нарушает принципы инкапсуляции.
Правильный путь — форма подбора «выбрасывает» событие выбора, а основная форма ловит его в обработчике ОбработкаВыбора. Таким образом, одну и ту же форму подбора можно использовать в разных документах и справочниках без переписывания кода.
&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
// Проверяем тип пришедших данных
Если ТипЗнч(ВыбранноеЗначение) = Тип("Структура") Тогда
// Обрабатываем GUID и добавляем в ТЧ
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = ПолучитьСсылкуПоУид(ВыбранноеЗначение.GUID);
КонецЕсли;
КонецПроцедуры
Иногда логика обработки данных скрыта в модуле объекта (например, в модуле внешней обработки). Чтобы вызвать ее из формы подбора, воспользуемся методом РеквизитФормыВЗначение.
&НаСервере
Процедура ВызватьМетодОбработки()
// "Объект" - это реквизит формы, ссылающийся на ВнешнююОбработку
ОбъектОбработки = РеквизитФормыВЗначение("Объект");
ТаблицаРезультат = ОбъектОбработки.ПолучитьВнешниеДанныеЧерезCOM();
ЗначениеВРеквизитФормы(ТаблицаРезультат, "СписокДляВыбора");
КонецПроцедуры
Подведем итог: для реализации качественного выбора из таблицы значений следует отдавать предпочтение созданию отдельной формы подбора с передачей данных через временное хранилище. Это обеспечит стабильность работы интерфейса, позволит избежать проблем с сериализацией COM-объектов и сделает ваш код более универсальным.