Как правильно обновить доступность кнопок формы после удаления элемента из динамического списка?

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

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

Почему возникает задержка обновления интерфейса?

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

Проблема заключается в асинхронной природе взаимодействия клиента и сервера. Метод Обновить() не выполняет моментальную подгрузку данных в объект таблицы на форме. Он лишь посылает платформе сигнал о том, что данные устарели и их нужно перечитать при следующей возможности. Клиентский код при этом продолжает выполняться дальше, не дожидаясь, пока сервер пришлет обновленный порцион данных. В итоге проверка ТекущиеДанные происходит по «старым» данным, которые еще хранятся в памяти клиента.

Решение 1: Использование события ПриАктивизацииСтроки

Проанализируем наиболее простой и эффективный способ, предложенный участниками обсуждения. Событие ПриАктивизацииСтроки у элемента формы Таблица (связанной с динамическим списком) срабатывает каждый раз, когда фокус перемещается на новую строку, а также — что критически важно — когда данные списка обновляются и платформа автоматически определяет новую текущую строку.

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

Шаг 1. Создаем общую процедуру (применяя программное изменение форм) обновления состояния кнопок:


&НаКлиенте
Процедура ОбновитьДоступностьКнопок()
    // Проверяем, есть ли данные в текущей строке списка
    ЕстьДанные = (Элементы.СписокДинСписок.ТекущиеДанные <> Неопределено);
    
    // Устанавливаем доступность команды
    Элементы.ФормаУдалитьЭлемент.Доступность = ЕстьДанные;
КонецПроцедуры

Шаг 2. Привязываем эту процедуру к событию ПриАктивизацииСтроки нашего списка:


&НаКлиенте
Процедура СписокДинСписокПриАктивизацииСтроки(Элемент)
    ОбновитьДоступностьКнопок();
КонецПроцедуры

Этот подход хорош тем, что платформа сама гарантирует вызов этого события ровно в тот момент, когда данные «приехали» с сервера и объект ТекущиеДанные стал актуальным.

Решение 2: Проверка состояния через серверный запрос

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

Посмотрим на пример кода, где функция удаления возвращает статус «список пуст»:


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

&НаСервереБезКонтекста
Функция УдалитьНаСервереИПроверитьОстаток(СсылкаДляУдаления)
    
    // 1. Удаление объекта
    ОбъектУдаления = СсылкаДляУдаления.ПолучитьОбъект();
    Если ОбъектУдаления <> Неопределено Тогда
        ОбъектУдаления.Удалить();
    КонецЕсли;
    
    // 2. Легкий запрос для проверки наличия других записей по тем же фильтрам
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка ИЗ Справочник.Файлы ГДЕ Владелец = &Владелец";
    // Параметры фильтра должны совпадать с отбором в ДинамическомСписке
    Запрос.УстановитьПараметр("Владелец", ...); 
    
    Возврат Запрос.Выполнить().Пустой();
    
КонецФункции

Хотя это создает дополнительный запрос к базе данных, такой метод гарантирует мгновенную реакцию интерфейса (UI), так как доступность кнопки устанавливается сразу после возврата из серверного вызова.

Решение 3: Использование «Источника команд»

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

  1. Выберите в дереве элементов вашу команду.
  2. В свойствах команды найдите поле «Источник команд».
  3. Выберите в качестве источника вашу таблицу (СписокДинСписок).

В этом случае платформа сама будет анализировать состояние таблицы. Если в таблице нет строк, команды, связанные с ней как с источником, будут автоматически становиться недоступными. Это наиболее «правильный» путь с точки зрения использования встроенных механизмов платформы 8.3.

Решение 4: Принудительное оповещение

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

  1. После удаления вызываем Оповестить("УдалениеФайла");.
  2. В этой же форме описываем обработчик ОбработкаОповещения.
  3. Внутри обработчика вызываем обновление интерфейса.

Это позволяет разнести логику удаления и логику обновления, давая платформе время на обработку очереди сообщений и перерисовку графических элементов.

Выводы и рекомендации

Подводя итог, можно сказать, что наиболее универсальным решением является вынос кода управления кнопками в событие ПриАктивизацииСтроки. Оно покрывает 90% случаев и не требует выполнения лишних запросов к базе данных.

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

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

← На главную