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

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

Приветствуем вас! Сегодня мы рассмотрим одну из частых и весьма актуальных задач в разработке на платформе 1С:Предприятие – как обеспечить автоматическое обновление данных в динамическом списке и оповещать пользователя о появлении новых элементов, добавленных другими пользователями. Мы разберем различные подходы, от простых встроенных механизмов до более сложных и эффективных решений, появившихся в последних версиях платформы. Представим ситуацию: вы работаете со списком документов, и в это время другие пользователи создают новые документы, которые должны появиться в вашем списке. Наша цель – сделать так, чтобы эти новые документы отображались автоматически, без необходимости ручного обновления, и, возможно, с каким-то уведомлением для пользователя. Давайте выясним, какие инструменты предоставляет платформа 1С для решения этой задачи.

Решение 1: Использование Системы взаимодействия 1С

Система взаимодействия – это мощный механизм платформы 1С:Предприятие, предназначенный для обмена сообщениями между пользователями, проведения обсуждений, видеозвонков и других форм коммуникации. Мы можем адаптировать его для нашей задачи, используя его как канал для отправки оповещений о новых данных. Принцип работы: 1. Когда какой-либо пользователь записывает новый документ (или изменяет существующий), мы можем инициировать отправку сообщения через Систему взаимодействия. 2. Это сообщение будет адресовано другим пользователям, работающим с соответствующим динамическим списком. 3. На стороне клиента, в форме, где расположен динамический список, мы можем отловить это сообщение и вызвать метод обновления списка. Как это реализовать: * На стороне сервера (при записи объекта): Создадим подписку на событие ПриЗаписи для нужного нам типа документов. В обработчике этой подписки мы будем отправлять уведомление.


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

// Вспомогательная функция для отправки сообщения через Систему взаимодействия
Функция ОтправитьСообщениеСистемыВзаимодействия(ТекстСообщения, ИдентификаторОбъекта)
    // Для отправки сообщения потребуется объект "СообщениеСистемыВзаимодействия"
    СообщениеВСВ = Новый СообщениеСистемыВзаимодействия;
    СообщениеВСВ.Текст = ТекстСообщения;
    СообщениеВСВ.Тема = "Обновление списка документов"; // Можно использовать для фильтрации
    СообщениеВСВ.ПараметрыСообщения.Вставить("ИдентификаторОбъекта", ИдентификаторОбъекта);

    // Отправляем сообщение.
    // Здесь мы отправляем сообщение всем активным пользователям.
    // Для более точного таргетирования можно использовать список пользователей.
    СистемаВзаимодействия.ОтправитьСообщение(СообщениеВСВ);
КонецФункции

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


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

// Вспомогательная процедура для показа оповещения
&НаКлиенте
Процедура ПоказатьОповещениеПользователя(Текст)
    Оповещение = Новый ОписаниеОповещения("ОбработатьОповещение", ЭтотОбъект);
    ПоказатьОповещениеПользователя(Оповещение, Текст, Заголовок = "Новые данные");
КонецПроцедуры

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

Решение 2: Новый механизм "Уведомления клиента" (начиная с версии 8.3.26)

Начиная с версии платформы 8.3.26, появился специализированный механизм "Уведомления клиента", который позволяет отправлять гарантированные уведомления с сервера в клиентское приложение без использования Системы взаимодействия. Это более легковесный и целенаправленный способ для наших задач. Принцип работы: 1. На сервере, после записи объекта, мы вызываем метод ОтправитьУведомление() глобального контекста. 2. На клиенте, мы заранее подключаем обработчик для приема этих уведомлений с помощью УведомленияКлиента.ПодключитьОбработчик(). 3. Когда уведомление приходит, срабатывает наш обработчик, и мы обновляем динамический список. Как это реализовать: * На стороне сервера (при записи объекта): Используем ту же подписку на событие ПриЗаписи.


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

    // Отправляем уведомление. Первый параметр - ключ уведомления,
    // по которому клиент сможет определить, что за уведомление пришло.
    ОтправитьУведомление("ОбновлениеСпискаДокументов", ПараметрыУведомления);
КонецПроцедуры

Мы также можем использовать свойство ФоновоеЗадание.НомерРодительскогоСеанса, если уведомление отправляется из фонового задания, чтобы адресовать его конкретному сеансу. * На стороне клиента (в модуле формы): В модуле формы, например, в событии ПриСозданииНаСервере или ПриОткрытии, мы подключаем обработчик.


// Пример кода в модуле формы
&НаКлиенте
Перем ИдентификаторОбработчикаУведомлений;

&НаКлиенте
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // ... ваш код инициализации формы ...

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

&НаКлиенте
Процедура ПриЗакрытии()
    // Важно отключать обработчик при закрытии формы, чтобы избежать утечек памяти
    Если ИдентификаторОбработчикаУведомлений <> Неопределено Тогда
        УведомленияКлиента.ОтключитьОбработчик(ИдентификаторОбработчикаУведомлений);
    КонецЕсли;
КонецПроцедуры

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

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

Решение 3: Периодическое автообновление динамического списка

Это самый простой и встроенный механизм, который не требует написания сложного кода. Однако он не является "реальным временем" и может создавать избыточную нагрузку на сервер при частом обновлении. Принцип работы: Динамический список имеет свойства Автообновление и ПериодАвтообновления. Если установить Автообновление в Истина и задать ПериодАвтообновления (в секундах), платформа будет периодически опрашивать базу данных и обновлять список. Как это реализовать: В конфигураторе, для элемента формы "Динамический список", установите следующие свойства: * Автообновление: Истина * ПериодАвтообновления: Укажите желаемый интервал в секундах (например, 30 или 60). Преимущества: Очень просто в настройке, не требует программирования. Недостатки: * Не является мгновенным оповещением, данные обновляются с задержкой, равной периоду. * Создает постоянную нагрузку на сервер, так как список будет опрашиваться, даже если изменений нет. * Пользователь не получает явного оповещения о появлении новых данных, просто видит их при следующем обновлении.

Решение 4: Использование методов `ОповеститьОбИзменении()` или `Оповестить()` в связке с Подписками на события

Этот подход представляет собой компромисс между простотой и эффективностью. Мы будем использовать механизм подписок на события для отслеживания изменений данных и методы глобального контекста для оповещения открытых форм. Принцип работы: 1. Мы создаем ПодпискуНаСобытие, которая будет срабатывать при записи или изменении нужных нам объектов (например, документов). 2. В обработчике подписки мы вызываем метод ОповеститьОбИзменении() или Оповестить(). * ОповеститьОбИзменении(КлючЗаписи): Уведомляет все динамические списки в открытых формах об изменении указанного объекта. Важно, чтобы у динамического списка была задана ОсновнаяТаблица, соответствующая типу объекта, который мы оповещаем. * Оповестить(ИмяСобытия, Параметр, Источник): Отправляет произвольное оповещение всем созданным (не обязательно открытым) формам. В форме, которая должна отреагировать, должен быть обработчик события ОбработкаОповещения(). 3. На стороне клиента, в форме со списком, мы реализуем обработчик ОбработкаОповещения(), который вызывает метод Обновить() динамического списка. Как это реализовать: * Шаг 1: Создаем Подписку на событие (в конфигураторе) Создадим новую ПодпискуНаСобытие. * Источник: Выбираем нужные нам документы (например, "Документ.ЗаказКлиента"). * Событие: Выбираем ПриЗаписи или ОбработкаПроведения, в зависимости от того, когда нам нужно отслеживать изменения. * Обработчик: Создаем общую серверную процедуру, например, в общем модуле. * Шаг 2: Реализуем обработчик подписки (на сервере) В модуле, указанном в качестве обработчика подписки:


// Пример кода в ОбщемМодуле
Процедура ПриЗаписиДокументаОповещение(Источник, Отказ, СтандартнаяОбработка) Экспорт
    Если Источник.ЭтоНовый() Тогда // Оповещаем только о новых документах
        // Вариант А: Оповещение об изменении объекта.
        // Работает, если у ДС задана ОсновнаяТаблица, соответствующая Источнику.
        ОповеститьОбИзменении(Источник.ПолучитьСсылку());

        // Вариант Б: Отправка произвольного оповещения.
        // Позволяет передать больше информации и не зависит от ОсновнойТаблицы ДС.
        ПараметрыОповещения = Новый Структура;
        ПараметрыОповещения.Вставить("ИдентификаторДокумента", Источник.УникальныйИдентификатор);
        ПараметрыОповещения.Вставить("ПредставлениеДокумента", Источник.ПредставлениеДокумента);
        Оповестить("НовыйДокументВСписке", ПараметрыОповещения);
    КонецЕсли;
КонецПроцедуры

* Шаг 3: Реализуем обработчик оповещения в форме (на клиенте) В модуле формы, где находится динамический список:


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

// Вспомогательная процедура для показа оповещения
&НаКлиенте
Процедура ПоказатьОповещениеПользователя(Текст)
    Оповещение = Новый ОписаниеОповещения("ОбработатьОповещение", ЭтотОбъект);
    ПоказатьОповещениеПользователя(Оповещение, Текст, Заголовок = "Новые данные");
КонецПроцедуры

Преимущества: Более гибкий, чем простое автообновление, срабатывает по факту изменения данных. Не требует Системы взаимодействия. Недостатки: Метод ОповеститьОбИзменении() обновляет списки только если у них задана ОсновнаяТаблица. Метод Оповестить() требует ручной обработки в каждой форме.

"Упоротый" вариант: Регистр сведений для оповещений

Этот вариант был упомянут в обсуждении как "совершенно упоротый", но может быть рассмотрен в очень специфических случаях, когда другие механизмы по каким-то причинам недоступны или неприменимы. Мы не рекомендуем его для типового использования. Принцип работы: 1. Создаем РегистрСведений (непериодический, независимый) с измерениями: Пользователь (ссылка на пользователя), КлючОповещения (строка, уникальный идентификатор события) и, возможно, ПараметрыОповещения (строка или хранилище значений для передачи данных). 2. При записи документа, в подписке на событие, записываем в этот регистр записи для всех активных пользователей (или тех, кого нужно оповестить). 3. На клиенте, в форме, запускаем таймер (например, через ПодключитьОбработчикОжидания), который будет периодически опрашивать этот регистр для текущего пользователя. 4. Если находятся записи, соответствующие текущему пользователю, обрабатываем их (обновляем список, показываем оповещение) и удаляем записи из регистра. Преимущества: Работает на старых версиях платформы, не зависит от встроенных механизмов оповещений. Недостатки: * Очень ресурсоемкий: постоянные запросы к базе данных от каждого клиента. * Сложно поддерживать: требует ручной очистки регистра, возможны "зависшие" оповещения. * Избыточная логика: по сути, мы пытаемся "переизобрести" механизм оповещений, который уже есть в платформе.

Заключение

Мы рассмотрели несколько подходов к решению задачи автоматического обновления динамического списка и оповещения пользователя о новых данных. * Для современных версий платформы (8.3.26 и выше) наиболее предпочтительным и эффективным является использование механизма "Уведомления клиента". Он предоставляет целенаправленное и гарантированное решение для сервер-клиент уведомлений. * Если ваша платформа старше 8.3.26, или вам нужна более широкая функциональность взаимодействия (чат, обсуждения), то Система взаимодействия 1С будет хорошим выбором. * Метод ОповеститьОбИзменении() / Оповестить() в связке с подписками на события является гибким и достаточно эффективным решением для большинства задач, если не требуется гарантированная доставка или специфический функционал "Уведомлений клиента". * Периодическое автообновление – это самый простой вариант, но он наименее эффективен и не обеспечивает мгновенной реакции или явного оповещения. Выбирайте решение, которое наилучшим образом соответствует требованиям вашей задачи, версии платформы и доступным ресурсам.

← К списку