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