Как передать текущую строку табличной части документа во внешнюю обработку?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При разработке расширений или внешних обработок для конфигураций на управляемых формах (например, ЗУП 3.1, ERP или Бухгалтерия 3.0) мы часто сталкиваемся с задачей контекстной обработки данных. Типичный сценарий: пользователь выделяет строку в табличной части документа (например, конкретного сотрудника в документе "Прием на работу списком") и нажимает кнопку, чтобы распечатать форму или выполнить действие именно для этой строки.

Однако стандартные механизмы Библиотеки Стандартных Подсистем (БСП) часто передают в обработку только ссылку на весь документ, игнорируя то, на какой строке стоит курсор. Разберем подробно, почему так происходит, как получить доступ к текущей строке и какие архитектурные подходы мы можем использовать для решения этой задачи.

Понимаем разницу между Формой и Объектом

Прежде чем писать код, давайте разберем фундаментальную проблему, которая часто вызывает недопонимание. В платформе 1С существует четкое разделение контекстов:

  1. Клиент (Форма): Здесь находится пользовательский интерфейс. Понятие "Текущая строка" (выделенная курсором) существует только здесь. Это свойство элемента управления формы.
  2. Сервер (Объект): Здесь происходит работа с базой данных. Когда мы передаем документ на сервер (например, в обработку заполнения), мы работаем с объектом ДокументОбъект. У объекта нет понятия "курсор" или "выделенная строка". У него есть только коллекция строк табличной части.

Ошибка, которую часто допускают разработчики, заключается в попытке обратиться к текущей строке из модуля объекта внешней обработки. Это невозможно технически. Нам необходимо "захватить" данные текущей строки на клиенте и передать их в обработку явным образом.

Как получить текущую строку на клиенте

Если мы находимся в модуле формы документа (или в расширении формы), получить данные текущей строки очень просто. Для этого мы обращаемся к коллекции элементов формы.

Допустим, наша табличная часть на форме называется Сотрудники (имя элемента формы, а не реквизита объекта). Чтобы получить данные активной строки, используем свойство ТекущиеДанные.

Рассмотрим пример кода на клиенте:


&НаКлиенте
Процедура КомандаОбработкиСтроки(Команда)
    
    // Получаем текущие данные выделенной строки
    ТекущаяСтрока = Элементы.Сотрудники.ТекущиеДанные;
    
    Если ТекущаяСтрока = Неопределено Тогда
        Сообщить("Не выбрана строка в таблице!");
        Возврат;
    КонецЕсли;
    
    // ТекущаяСтрока - это объект типа ДанныеФормыЭлементКоллекции
    // Мы можем обращаться к колонкам по имени
    ВыбранныйСотрудник = ТекущаяСтрока.Сотрудник;
    ИдентификаторСтроки = ТекущаяСтрока.НомерСтроки; // Или КлючСтроки
    
    Сообщить("Выбран сотрудник: " + Строка(ВыбранныйСотрудник));

КонецПроцедуры

Этот код работает, потому что Элементы доступны на клиенте. Свойство ТекущиеДанные возвращает специальный объект, содержащий значения колонок той строки, на которой сейчас стоит фокус ввода.

Проблема передачи в БСП (Внешние обработки)

Сложность возникает, когда мы используем механизм внешних обработок и печатных форм через БСП. Стандартно команда "Вызов серверного метода" передает в модуль обработки массив ссылок на документы (ОбъектыНазначения). Контекст формы при этом теряется.

Давайте проанализируем варианты решения этой задачи.

Вариант 1. Обработка с открытием формы (Client-side)

Если ваша внешняя обработка регистрируется с режимом запуска "Открытие формы" (а не "Вызов серверного метода"), то при ее запуске открывается форма обработки. В этот момент мы все еще находимся на клиенте и теоретически можем "подсмотреть" во владельца формы.

Рассмотрим, как это реализовать в модуле формы внешней обработки:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Получаем переданные параметры (обычно здесь ссылки на объекты)
    // Но про текущую строку здесь информации еще нет
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    
    // Попытаемся получить форму-владельца (форму документа, откуда запустили обработку)
    ВладелецФормы = ЭтаФорма.ВладелецФормы;
    
    Если ВладелецФормы <> Неопределено Тогда
        
        // Пытаемся обратиться к элементам формы владельца
        // ВНИМАНИЕ: Это ненадежный метод, так как зависит от имен элементов в документе
        Попытка
            ТекДанные = ВладелецФормы.Элементы.Сотрудники.ТекущиеДанные;
            Если ТекДанные <> Неопределено Тогда
                // Запоминаем данные, которые нам нужны
                СотрудникДляОбработки = ТекДанные.Сотрудник;
            КонецЕсли;
        Исключение
            // Элемент "Сотрудники" не найден или недоступен
        КонецПопытки;
        
    КонецЕсли;
    
КонецПроцедуры

Важное предостережение: Данный метод обращается к ЭтаФорма.ВладелецФормы. Это работает, если обработка открывается модально или в блокирующем окне прямо из документа. Однако, полагаться на точные имена элементов формы (Элементы.Сотрудники) рискованно — если 1С обновит конфигурацию и переименует таблицу, ваша обработка перестанет работать.

Вариант 2. Использование Расширения конфигурации (Рекомендуемый)

Наиболее надежный и современный способ решить задачу в ЗУП 3.1 или ERP — использовать расширение конфигурации. Мы можем перехватить команду или создать свою кнопку на форме документа, считать текущую строку и передать нужные параметры в процедуру обработки.

Давайте разберем алгоритм действий:

  1. Создаем расширение конфигурации.
  2. Заимствуем форму документа (например, "Прием на работу списком").
  3. Добавляем свою команду и кнопку на командную панель табличной части.
  4. В обработчике команды считываем ТекущиеДанные.
  5. Вызываем серверную процедуру, передавая туда конкретные данные строки (например, Ссылку на сотрудника или КлючСтроки), а не весь документ целиком.

Пример кода в модуле формы расширения:


&НаКлиенте
Процедура Расш1_ОбработатьТекущегоСотрудника(Команда)
    
    ТекДанные = Элементы.Сотрудники.ТекущиеДанные;
    Если ТекДанные = Неопределено Тогда
        ПоказатьПредупреждение(, "Выберите сотрудника в списке!");
        Возврат;
    КонецЕсли;
    
    // Формируем структуру параметров для передачи на сервер
    ПараметрыОбработки = Новый Структура;
    ПараметрыОбработки.Вставить("Сотрудник", ТекДанные.Сотрудник);
    ПараметрыОбработки.Вставить("ДокументСсылка", Объект.Ссылка);
    
    // Вызываем серверный метод
    ВыполнитьОбработкуНаСервере(ПараметрыОбработки);
    
КонецПроцедуры

&НаСервере
Процедура ВыполнитьОбработкуНаСервере(ПараметрыОбработки)
    // Здесь уже работаем с конкретным сотрудником, полученным из текущей строки
    ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
    // Логика вашей обработки...
КонецПроцедуры

Вариант 3. Подбор внутри обработки (Архитектурный)

Если вы не хотите использовать расширения и ограничены только внешней обработкой, подключаемой через "Дополнительные отчеты и обработки", то самым правильным решением будет изменение логики взаимодействия с пользователем.

Вместо того чтобы пытаться угадать, какая строка была активна, давайте предложим пользователю выбрать их явно:

  1. Обработка получает ссылку на документ (весь список сотрудников).
  2. При открытии формы обработки мы программно заполняем таблицу внутри обработки данными из документа.
  3. Пользователь видит список, ставит галочки напротив нужных сотрудников (или выбирает одного).
  4. Нажимает "Выполнить".

Этот подход более устойчив к ошибкам, так как пользователь явно контролирует, для кого будет выполнено действие, и вам не нужно взламывать контекст формы владельца.

Резюме

Подводя итог дискуссии, отметим ключевые моменты:

← На главную