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

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

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

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

1. Использование обработчика ожидания (Polling) с контрольным индикатором

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

Как мы это можем реализовать:

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

    • Константа: Мы можем создать константу, например, типа "Дата", в которую будет записываться текущее время при каждом изменении данных. Это самый простой вариант.
    • Специальный регистр сведений: Более гибкое решение — создать небольшой регистр сведений, который будет хранить метку времени последнего изменения или даже идентификатор измененных данных. Этот вариант особенно полезен, если нам нужно отслеживать изменения не просто в целом, а по конкретным объектам или группам данных.

    Для примера, если мы решили использовать константу ДатаПоследнегоИзмененияРегистра, код у второго сотрудника после записи данных в регистр сведений будет выглядеть следующим образом:

    
    // ... код изменения данных в регистре сведений, например:
    НаборЗаписей = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Поле1.Установить(ЗначениеОтбора);
    НаборЗаписей.Прочитать();
    // Изменяем записи
    // ...
    НаборЗаписей.Записать(); 
            
    // Теперь обновляем константу-индикатор, чтобы сигнализировать об изменении
    НаборКонстант = Константы.ПолучитьНабор();
    НаборКонстант.ДатаПоследнегоИзмененияРегистра = ТекущаяДата();
    НаборКонстант.Записать();
    
  2. Установка обработчика ожидания на форме первого сотрудника. На форме первого сотрудника, которая должна отображать актуальные данные, мы должны установить обработчик ожидания. Этот обработчик будет с заданной периодичностью выполнять проверку значения нашего контрольного индикатора.

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

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

    Для хранения последнего зафиксированного значения индикатора добавим на форму реквизит, например, ПоследнееЗначениеИндикатора с типом "Дата".

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

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

2. Динамический список с автообновлением

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

Как мы можем это реализовать:

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

  1. Откройте форму обработки в конфигураторе и выделите элемент формы, который является динамическим списком.
  2. В окне свойств этого элемента найдите свойство Автообновление и установите его значение в Истина.
  3. Затем укажите желаемый ПериодАвтообновления (например, 5 секунд).

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

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


&НаКлиенте
Процедура ОбновитьТаблицуНаФорме()
    // Предполагается, что 'МойДинамическийСписок' - это имя элемента формы
    Элементы.МойДинамическийСписок.Обновить(); // Вызываем метод обновления динамического списка
КонецПроцедуры

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

Преимущества: Главное преимущество — простота настройки, особенно если данные уже отображаются динамическим списком. Требует минимального количества дополнительного кода или даже не требует его вовсе. Недостатки: Могут возникнуть определенные проблемы с пользовательским опытом. Например, при частом автоматическом обновлении может сбрасываться выделение строки, позиция прокрутки или состояние других элементов, связанных со списком. В некоторых случаях, если динамический список очень сложен (много связей, вычисляемых полей) или содержит очень большой объем данных, автоматическое обновление может быть ресурсоемким и негативно влиять на общую производительность системы.

3. Использование Системы взаимодействия (с версии 8.3.9)

Для более современных и эффективных подходов к обмену информацией между разными сеансами пользователей платформа 1С:Предприятие, начиная с версии 8.3.9, предлагает мощный инструмент — Систему взаимодействия. Это "push-ориентированный" механизм, который позволяет отправлять оповещения и сообщения в реальном времени, что делает его идеальным для задач моментального обновления.

Как мы можем это реализовать:

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

  2. Отправка оповещения вторым сотрудником. После того как второй сотрудник изменяет данные в регистре сведений и записывает их, он может отправить оповещение первому сотруднику (или группе сотрудников) через Систему взаимодействия.

    Пример отправки оповещения с параметрами, если мы хотим передать какую-то дополнительную информацию:

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

    Если мы хотим отправить адресное сообщение конкретному пользователю:

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

    Для этого в модуле формы или клиента мы используем процедуру ОбработкаВзаимодействия или подписываемся на события:

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

    Альтернативный способ — использовать механизм подписки на события: это более специфично и позволяет лучше контролировать обработку различных оповещений.

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

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

4. Фоновые (регламентные) задания и частичное обновление данных форм

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

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

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

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

  1. Для самых простых случаев наблюдения за статусами, если производительность не является критически важным фактором, динамический список с автообновлением может оказаться вполне приемлемым и легким в реализации.
  2. Если требуется более тонкий контроль над процессом и необходим баланс между оперативностью и нагрузкой на систему, обработчик ожидания в сочетании с контрольным индикатором (константой или регистром) представляет собой отличный и проверенный выбор.
  3. Для достижения максимально оперативных результатов и использования современных возможностей платформы, особенно если у вас версия 8.3.9 или выше, Система взаимодействия будет наиболее предпочтительным и эффективным вариантом.

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

← На главную