Почему исчезают строки при программном заполнении табличной части с установленным отбором и как это исправить

Программист 1С v8.3 (Обычные формы)
← На главную

При разработке в среде 1С:Предприятие 8.2 и 8.3 на обычных формах (ОФ) программисты часто сталкиваются с неочевидным поведением интерфейса: при добавлении новой строки в табличную часть она физически создается, но визуально мгновенно пропадает. Это происходит в тех случаях, когда для элемента управления "Табличное поле" включен программный фильтр через свойство ОтборСтрок. Рассмотрим подробнее, почему это случается и как правильно организовать работу с двумя связанными таблицами.

Разберем причину возникновения проблемы

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

Проблема заключается в следующем алгоритме работы системы:

  1. В табличном поле установлен активный отбор, например: УсловиеНомер = 5.
  2. Программа вызывает метод Объект.Скидки.Добавить().
  3. В этот момент создается абсолютно пустая строка, где значение поля УсловиеНомер равно 0 (или не определено).
  4. Так как значение 0 не равно значению отбора 5, визуальный компонент формы мгновенно скрывает эту строку как не соответствующую критериям.
  5. Пользователь видит, что номер строки в ТЧ инкрементировался (строка добавилась), но сама строка в списке отсутствует.

Следовательно, чтобы строка не исчезала, нам необходимо обеспечить заполнение ключевого поля связи в момент создания строки, еще до того, как форма успеет ее перерисовать.

Шаг 1: Правильная архитектура связи (Ключ связи вместо номера строки)

Прежде чем приступать к исправлению кода заполнения, обратим внимание на важное замечание коллег из обсуждения: использование НомерСтроки для связи таблиц — это "мина замедленного действия". Номера строк в 1С непостоянны: они пересчитываются при удалении строк, при их перемещении (кнопками "вверх"/"вниз") или при сортировке. Если связь держится на номере, то при любом изменении порядка строк в главной таблице все подчиненные данные в другой таблице перемешаются или "отвалятся".

Рекомендуемое решение: добавим в обе табличные части реквизит КлючСвязи (тип Число). При добавлении новой строки в главную таблицу будем генерировать для нее уникальный идентификатор (например, на основе текущего времени в миллисекундах или просто максимальный существующий + 1). Именно этот ключ мы будем использовать для фильтрации подчиненной таблицы.

Шаг 2: Реализация связи на форме

Рассмотрим, как должен выглядеть код в событии ПриАктивизацииСтроки главной таблицы ("Условия"). Мы будем устанавливать отбор в подчиненной таблице ("Скидки") по нашему новому полю КлючСвязи:


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

Шаг 3: Программное заполнение строки без "исчезновения"

Теперь перейдем к решению главной задачи: как заполнить таблицу из внешней обработки (через процедуру Инициализировать), чтобы строки оставались видимыми. Ключевой момент — передать в обработку значение текущего ключа связи из формы.

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


// Внутри модуля обработки заполнения
Процедура ЗаполнитьСкидки(ДокументОбъект, ЗначениеКлюча)
    
    // Добавляем строку непосредственно в объект документа
    НоваяСтрока = ДокументОбъект.Скидки.Добавить();
    
    // КРИТИЧЕСКИ ВАЖНО: заполняем поле связи СРАЗУ после добавления
    НоваяСтрока.КлючСвязи = ЗначениеКлюча;
    
    // Заполняем остальные реквизиты
    НоваяСтрока.НаименованиеСкидки = "Сезонная 5%";
    НоваяСтрока.Процент = 5;
    
КонецПроцедуры

Если вы используете механизм Добавить() непосредственно в коде формы, ситуация упрощается. Вы можете получить значение активного отбора прямо из элементов формы. Проанализируем ситуацию: если мы нажмем стандартную кнопку "Добавить" в командной панели табличного поля, 1С в обычных формах часто сама пытается подставить значение из отбора. Но при программном вызове метода Добавить() это нужно делать вручную.

Особенности работы через внешние обработки заполнения ТЧ

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

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

Как только поле КлючСвязи (или УсловиеНомер, если вы решили оставить старую логику) будет заполнено в коде добавления строки, механизм ОтборСтрок увидит, что новая строка соответствует критериям, и она останется видимой для пользователя.

Дополнительные рекомендации по обновлению интерфейса

Иногда даже при правильном заполнении реквизитов форма может не сразу "увидеть" изменения. В таких случаях после программного изменения состава табличной части рекомендуется принудительно обновить визуальное состояние табличного поля. Рассмотрим метод ОбновитьСтроки():


// В коде формы после вызова обработки заполнения
ЭлементыФормы.Скидки.ОбновитьСтроки();

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

← На главную