В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача динамического изменения интерфейса в зависимости от того, какая строка выбрана пользователем в списке. Однако стандартный подход «добавить реквизит прямо в событии при активизации строки» приводит к неприятным последствиям: динамический список полностью очищается, данные исчезают, а кнопки управления формой блокируются. Разберем детально, почему это происходит и как реализовать задачу правильно.
Рассмотрим ситуацию, с которой сталкиваются многие разработчики. В форме списка справочника Номенклатура создается обработчик события СписокПриАктивизацииСтроки. Внутри этого обработчика выполняется переход на сервер, где вызывается метод ИзменитьРеквизиты для добавления нового поля ввода. Код выглядит примерно так:
&НаСервере
Процедура ПриАктивизацииСтрокиНаСервере()
Если Элементы.Найти("Реквизит1") <> Неопределено Тогда
// Удаление старого реквизита
УдаляемыеРеквизиты = Новый Массив;
УдаляемыеРеквизиты.Добавить("Реквизит1");
Элементы.Удалить(Элементы["Реквизит1"]);
ИзменитьРеквизиты(, УдаляемыеРеквизиты);
КонецЕсли;
// Добавление нового реквизита
МассивРеквизитов = Новый Массив;
ОписаниеТипа = Новый ОписаниеТипов("Строка");
Реквизит1 = Новый РеквизитФормы("Реквизит1", ОписаниеТипа);
МассивРеквизитов.Добавить(Реквизит1);
ИзменитьРеквизиты(МассивРеквизитов);
// Создание элемента формы
Элемент1 = ЭтаФорма.Элементы.Добавить("Реквизит1", Тип("ПолеФормы"));
Элемент1.Вид = ВидПоляФормы.ПолеВвода;
Элемент1.ПутьКДанным = "Реквизит1";
КонецПроцедуры
После выполнения такого кода динамический список «ломается». Это происходит из-за того, что метод ИзменитьРеквизиты инициирует полную пересборку контекста формы. Поскольку форма находится в процессе обработки интерактивного события (смена строки), возникает конфликт состояний. Платформа теряет связь с текущим состоянием динамического списка, и он перестает отображать данные.
Проанализируем ситуацию с точки зрения архитектуры платформы. Основные причины кроются в следующем:
ПриАктивизацииСтроки четко указано: в данном обработчике нельзя использовать серверные методы формы с директивой &НаСервере, а также изменять свойства, которые могут привести к серверному вызову.ИзменитьРеквизиты — это тяжелая операция. Она заставляет сервер полностью уничтожить старое описание формы в памяти и собрать новое. Если это происходит «на лету» при навигации по списку, клиентская часть (браузер или тонкий клиент) не может корректно сопоставить данные списка с новой структурой формы.ПриАктивизацииСтроки срабатывает крайне часто — при каждом перемещении курсора, включая быстрый скроллинг клавиатурой. Постоянные вызовы ИзменитьРеквизиты создают колоссальную нагрузку и делают интерфейс «ватным».Самый правильный и производительный способ — отказаться от динамического создания реквизитов в момент работы пользователя. Проанализируем, как сделать это лучше. Вместо того чтобы удалять и добавлять элементы, мы создадим их один раз при открытии формы, а затем будем лишь управлять их свойствами.
Шаг 1. В процедуре ПриСозданииНаСервере заранее создайте все необходимые реквизиты и элементы формы. Установите им свойство Видимость = Ложь.
Шаг 2. В событии ПриАктивизацииСтроки на клиенте изменяйте только видимость или значения этих элементов. Это «легкие» операции, которые не требуют перестройки всей формы.
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Просто меняем видимость или данные, это безопасно
Элементы.ГруппаДополнительно.Видимость = (ТекущиеДанные.ТипНоменклатуры = ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Товар"));
КонецПроцедуры
Если специфика задачи все же требует выполнения тяжелых серверных действий именно после выбора строки, необходимо «разорвать» прямую связь между событием списка и серверным вызовом. Для этого используем метод ПодключитьОбработчикОжидания.
Рассмотрим алгоритм реализации по шагам:
ПриАктивизацииСтроки мы не идем на сервер сразу. Мы подключаем обработчик ожидания на очень короткое время (например, 0.1 секунды).Пример кода на клиенте:
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
// Отключаем предыдущий вызов, если он был
ОтключитьОбработчикОжидания("ВыполнитьОбновлениеФормы");
// Подключаем новый вызов через 0.1 сек
ПодключитьОбработчикОжидания("ВыполнитьОбновлениеФормы", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьОбновлениеФормы()
// Теперь здесь можно безопасно вызывать серверные методы
ОбновитьЭлементыНаСервере();
КонецПроцедуры
Часто разработчики пытаются использовать ИзменитьРеквизиты там, где достаточно обычных Данных формы. Если ваша цель — показать описание товара или картинку под списком, не нужно пересоздавать элементы формы.
Выясним причину, по которой стоит выбрать этот путь: изменение значения реквизита, который уже существует на форме (например, строковая переменная или адрес картинки), происходит мгновенно и не вызывает сбоев в работе ДинамическогоСписка. Вы можете просто обновлять текстовое поле, связанное с реквизитом формы, в контекстном серверном вызове, не меняя структуру самой формы.
Проанализировав ситуацию, можно выделить главные правила работы с динамическими списками в Управляемом приложении:
ИзменитьРеквизиты и Элементы.Добавить() внутри ПриАктивизацииСтроки. Это архитектурный тупик.&НаСервере в списке делает работу с программой некомфортной.Соблюдение этих простых принципов позволит вашим интерфейсам работать стабильно, а динамическим спискам — всегда отображать актуальные данные без досадных ошибок и «пустых экранов».