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