Почему пропадают данные в динамическом списке при программном изменении формы и как это исправить?

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача динамического изменения интерфейса в зависимости от того, какая строка выбрана пользователем в списке. Однако стандартный подход «добавить реквизит прямо в событии при активизации строки» приводит к неприятным последствиям: динамический список полностью очищается, данные исчезают, а кнопки управления формой блокируются. Разберем детально, почему это происходит и как реализовать задачу правильно.

Проблема: использование ИзменитьРеквизиты в событии активизации строки

Рассмотрим ситуацию, с которой сталкиваются многие разработчики. В форме списка справочника Номенклатура создается обработчик события СписокПриАктивизацииСтроки. Внутри этого обработчика выполняется переход на сервер, где вызывается метод ИзменитьРеквизиты для добавления нового поля ввода. Код выглядит примерно так:


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

После выполнения такого кода динамический список «ломается». Это происходит из-за того, что метод ИзменитьРеквизиты инициирует полную пересборку контекста формы. Поскольку форма находится в процессе обработки интерактивного события (смена строки), возникает конфликт состояний. Платформа теряет связь с текущим состоянием динамического списка, и он перестает отображать данные.

Причины возникновения ошибки

Проанализируем ситуацию с точки зрения архитектуры платформы. Основные причины кроются в следующем:

  1. Ограничения обработчика события: В справке 1С (Синтакс-помощник) для события ПриАктивизацииСтроки четко указано: в данном обработчике нельзя использовать серверные методы формы с директивой &НаСервере, а также изменять свойства, которые могут привести к серверному вызову.
  2. Перестроение контекста: Метод ИзменитьРеквизиты — это тяжелая операция. Она заставляет сервер полностью уничтожить старое описание формы в памяти и собрать новое. Если это происходит «на лету» при навигации по списку, клиентская часть (браузер или тонкий клиент) не может корректно сопоставить данные списка с новой структурой формы.
  3. Производительность (Ping-pong): Событие ПриАктивизацииСтроки срабатывает крайне часто — при каждом перемещении курсора, включая быстрый скроллинг клавиатурой. Постоянные вызовы ИзменитьРеквизиты создают колоссальную нагрузку и делают интерфейс «ватным».

Решение №1: Управление видимостью (Рекомендуемое)

Самый правильный и производительный способ — отказаться от динамического создания реквизитов в момент работы пользователя. Проанализируем, как сделать это лучше. Вместо того чтобы удалять и добавлять элементы, мы создадим их один раз при открытии формы, а затем будем лишь управлять их свойствами.

Шаг 1. В процедуре ПриСозданииНаСервере заранее создайте все необходимые реквизиты и элементы формы. Установите им свойство Видимость = Ложь.

Шаг 2. В событии ПриАктивизацииСтроки на клиенте изменяйте только видимость или значения этих элементов. Это «легкие» операции, которые не требуют перестройки всей формы.


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Просто меняем видимость или данные, это безопасно
    Элементы.ГруппаДополнительно.Видимость = (ТекущиеДанные.ТипНоменклатуры = ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Товар"));
КонецПроцедуры

Решение №2: Использование обработчика ожидания

Если специфика задачи все же требует выполнения тяжелых серверных действий именно после выбора строки, необходимо «разорвать» прямую связь между событием списка и серверным вызовом. Для этого используем метод ПодключитьОбработчикОжидания.

Рассмотрим алгоритм реализации по шагам:

  1. В событии ПриАктивизацииСтроки мы не идем на сервер сразу. Мы подключаем обработчик ожидания на очень короткое время (например, 0.1 секунды).
  2. Если пользователь быстро листает список, обработчик будет постоянно переподключаться, не выполняя лишних действий.
  3. Когда пользователь остановится на строке, сработает процедура обработчика, из которой уже можно безопасно вызвать серверную процедуру.

Пример кода на клиенте:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    // Отключаем предыдущий вызов, если он был
    ОтключитьОбработчикОжидания("ВыполнитьОбновлениеФормы");
    // Подключаем новый вызов через 0.1 сек
    ПодключитьОбработчикОжидания("ВыполнитьОбновлениеФормы", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьОбновлениеФормы()
    // Теперь здесь можно безопасно вызывать серверные методы
    ОбновитьЭлементыНаСервере();
КонецПроцедуры

Решение №3: Работа с данными формы без ИзменитьРеквизиты

Часто разработчики пытаются использовать ИзменитьРеквизиты там, где достаточно обычных Данных формы. Если ваша цель — показать описание товара или картинку под списком, не нужно пересоздавать элементы формы.

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

Важные выводы

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

Соблюдение этих простых принципов позволит вашим интерфейсам работать стабильно, а динамическим спискам — всегда отображать актуальные данные без досадных ошибок и «пустых экранов».

← На главную