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