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