Как программно перебрать строки табличной части и передать ТекущиеДанные в процедуру

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача массово пересчитать или обработать строки табличной части так, как если бы пользователь изменил их вручную. Основная сложность заключается в том, что типовые процедуры (особенно в конфигурациях на базе БСП, таких как УТ 11, ERP или КА) часто завязаны на параметр ТекущиеДанные элемента управления (таблицы формы). Рассмотрим, как правильно организовать такой перебор, избежав типичных ошибок новичков.

Проблема использования ТекущейСтроки и ТекущихДанных

Разберем ситуацию: у нас есть табличная часть Товары. Мы хотим в цикле вызвать для каждой строки процедуру ЗТЧ_ТоварыНоменклатураПриИзменении. Внутри этой процедуры код часто обращается к Элементы.Товары.ТекущиеДанные. Если мы просто запустим цикл по Объект.Товары, значение ТекущиеДанные не будет меняться автоматически — оно будет всегда указывать на ту строку, на которой физически стоит курсор пользователя.

Проанализируем попытку решения, которую часто выбирают начинающие программисты: принудительная активация строки в цикле.


Для Каждого ТекСтрока Из Объект.Товары Цикл
    // Пытаемся сделать строку активной через идентификатор
    Элементы.Товары.ТекущаяСтрока = ТекСтрока.ПолучитьИдентификатор();
    
    // Вызываем процедуру, надеясь, что ТекущиеДанные обновятся
    ЗТЧ_ТоварыНоменклатураПриИзменении(Элементы.Товары); 
КонецЦикла;

Важный нюанс: программная установка ТекущаяСтрока на клиенте работает, но она инициирует перерисовку интерфейса. Если строк в таблице много, интерфейс начнет «прыгать», а производительность резко упадет. Кроме того, ТекущаяСтрока — это идентификатор (число), а не сама строка с данными.

Правильный способ №1: Использование метода ДанныеСтроки

Чтобы не заставлять систему перерисовывать форму на каждой итерации цикла, мы можем получить доступ к данным конкретной строки, используя её идентификатор. У элемента формы «Таблица» есть замечательный метод ДанныеСтроки(). Этот метод возвращает объект типа ДанныеФормыСтруктура, который идентичен по свойствам ТекущиеДанные.

Рассмотрим правильную реализацию перебора:


Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    // Получаем уникальный идентификатор строки в контексте формы
    Идентификатор = СтрокаТЧ.ПолучитьИдентификатор();
    
    // Получаем данные конкретной строки по идентификатору
    ДанныеСтроки = Элементы.Товары.ДанныеСтроки(Идентификатор);
    
    // Теперь мы можем передать эти данные в любую процедуру
    // Если процедура ожидает Элемент, нужно убедиться, что она умеет работать не только с ТекущиеДанные
    ОбработатьСтрокуПрограммно(ДанныеСтроки);
КонецЦикла;

Разбор типовой процедуры пересчета (БСП)

Посмотрим на структуру процедуры, представленной в сообщении №6. Она использует механизмы БСП для обработки строк. Ключевым моментом здесь является подготовка СтруктураДействий и вызов ОбработкаТабличнойЧастиКлиент.ОбработатьСтрокуТЧ.

Выясним причину, почему прямой вызов обработчика события ПриИзменении в цикле — плохая практика. Эти обработчики обычно принимают параметр Элемент, из которого внутри извлекаются ТекущиеДанные. Чтобы сделать код универсальным, выполним рефакторинг.

Рекомендуемый подход: Рефакторинг и разделение логики

Проанализируем ситуацию: чтобы код работал и при ручном вводе, и при программном переборе, логику пересчета нужно вынести в отдельную процедуру, принимающую данные строки как параметр.

Шаг 1. Создаем общую процедуру пересчета:


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

Шаг 2. Используем её в обработчике события:


&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        ВыполнитьПересчетСтрокиТоваров(ТекущиеДанные);
    КонецЕсли;
КонецПроцедуры

Шаг 3. Используем её для массового пересчета в цикле:


&НаКлиенте
Процедура ПересчитатьВсеСтрокиТаблицы()
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        // На клиенте строка таблицы Объект.Товары уже является 
        // типом ДанныеФормыЭлементКоллекции, что нам и нужно
        ВыполнитьПересчетСтрокиТоваров(СтрокаТЧ);
    КонецЦикла;
КонецПроцедуры

Почему это работает лучше?

  1. Отсутствие визуальных артефактов. Программа не меняет фокус в таблице, пользователь не видит «бегающего» курсора.
  2. Типизация данных. На клиенте Объект.Товары представляет собой коллекцию ДанныеФормыКоллекция. Когда мы итерируем её через Для Каждого, переменная цикла уже содержит ДанныеФормыЭлементКоллекции. Это именно тот тип данных, который возвращает свойство ТекущиеДанные.
  3. Совместимость с БСП. Функции пересчета БСП ожидают на вход именно структуру данных строки, которую мы успешно передаем.

Важные замечания по контексту исполнения

Посмотрим на ситуацию глубже: если ваша задача — просто изменить значения в строках (например, установить ставку НДС), это гораздо эффективнее делать на сервере. Перебор элементов формы (Элементы.Товары) на клиенте оправдан только в том случае, если вам необходимо вызвать сложные клиентские процедуры, которые содержат:

Если же логика чисто расчетная (математика, заполнение реквизитов), всегда старайтесь переносить цикл на сервер и работать напрямую с Объект.Товары. Это исключит лишние сетевые вызовы между клиентом и сервером на каждой строке, что критично для работы через медленный интернет или веб-клиент.

Подведем итог: для перебора строк с имитацией «текущих данных» используйте прямой цикл по Объект.ТабличнаяЧасть на клиенте и передавайте переменную цикла в выделенную процедуру обработки. Это обеспечит чистоту кода и высокую скорость работы интерфейса.

← На главную