Как правильно выводить сообщения пользователю из серверных процедур в 1С:Предприятии 8.3 Управляемые формы?

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

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

Традиционно для вывода сообщений используется метод Сообщить(), но в последнее время фирма "1С" активно продвигает объект СообщениеПользователю и соответствующие обертки из Библиотеки стандартных подсистем (БСП). Давайте рассмотрим эти подходы, их преимущества, недостатки и особенности применения.

Механизм вывода сообщений с сервера

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

Использование метода Сообщить()

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

Пример использования на сервере:


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

Преимущества Сообщить():

  1. Простота: Легко и быстро написать.
  2. Универсальность: Работает в большинстве контекстов (клиент, сервер, тонкий клиент, веб-клиент и т.д.).

Недостатки Сообщить():

  1. Ограниченный функционал: Это просто вывод текстовой строки. Мы не можем привязать сообщение к конкретному элементу формы, к данным объекта или указать, в какую именно форму выводить сообщение.
  2. "Некошерность" и устаревание: Согласно рекомендациям фирмы "1С", изложенным в ИТС и в некоторых типовых конфигурациях (например, УТ11), метод Сообщить() считается устаревшим и не рекомендуется для использования в продакшн-коде. Инструменты вроде BSL Language Server даже диагностируют его использование как потенциальную проблему — поможет инструмент разработки и проверки синтаксиса кода через BSL. Многие разработчики используют его только для временных отладочных сообщений, чтобы потом легко их находить и удалять.
  3. Не всегда работает: В некоторых специфических случаях (например, Сообщить(Неопределено)) или в определенных контекстах метод может не привести к ожидаемому результату, хотя это скорее исключение.

Итак, хотя Сообщить() и функционален, для серьезных прикладных решений нам следует рассмотреть более продвинутые инструменты.

Использование объекта СообщениеПользователю

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

Основные возможности СообщениеПользователю:

  1. Привязка к элементу формы: Мы можем указать конкретное поле или элемент табличной части, к которому относится сообщение — для этого подойдёт настройка контроля ввода данных и обработчиков без программирования. При двойном щелчке по такому сообщению в окне сообщений, фокус будет перенесен на соответствующий элемент формы, что значительно улучшает пользовательский опыт.
  2. Привязка к данным объекта: Сообщение может быть привязано к конкретному реквизиту объекта или записи регистра. Если в текущей форме нет элемента, соответствующего этому реквизиту, платформа может даже автоматически открыть новую форму объекта и перенести туда сообщения, связанные с этим ключом данных.
  3. Указание целевой формы: Мы можем явно задать уникальный идентификатор формы, в которую должно быть выведено сообщение, вместо того чтобы полагаться на активное окно.

Как использовать СообщениеПользователю:

Для создания и вывода сообщения с помощью объекта СообщениеПользователю, мы обычно выполняем следующие шаги:

  1. Создаем новый объект: НовоеСообщение = Новый СообщениеПользователю;
  2. Заполняем текст сообщения: НовоеСообщение.Текст = "Текст вашего сообщения";
  3. Привязываем к полю (опционально): Если сообщение относится к конкретному полю формы (например, к реквизиту объекта или ячейке табличной части), мы можем указать путь к нему: НовоеСообщение.Поле = "Объект.ТабличнаяЧасть.Количество";
  4. Привязываем к данным (опционально): Если сообщение относится к конкретному объекту или записи, мы можем указать его ключ: НовоеСообщение.КлючДанных = СсылкаНаОбъект;
  5. Указываем целевую форму (опционально): Если нужно вывести сообщение не в активное окно, а в конкретную форму, мы используем свойство ИдентификаторНазначения: НовоеСообщение.ИдентификаторНазначения = GUIDЦелевойФормы;
  6. Выводим сообщение: НовоеСообщение.Сообщить();

Пример использования СообщениеПользователю в серверной процедуре проверки остатков:


// В процедуре с директивой НаСервере
Процедура ПроверитьОстаткиНаСервере(ТабличнаяЧастьДокумента, ИдентификаторФормыДокумента) НаСервере

    // Имитация проверки остатков для каждой строки табличной части
    Для Каждого СтрокаТЧ Из ТабличнаяЧастьДокумента Цикл
        Если СтрокаТЧ.Количество > 10 Тогда // Условие нехватки для примера
            НовоеСообщение = Новый СообщениеПользователю;
            НовоеСообщение.Текст = "Не хватает товара '" + СтрокаТЧ.Номенклатура.Наименование + "' в количестве " + (СтрокаТЧ.Количество - 10) + " шт.";
            НовоеСообщение.Поле = "Объект.Товары[" + (СтрокаТЧ.НомерСтроки - 1) + "].Количество"; // Привязка к конкретной ячейке
            НовоеСообщение.КлючДанных = ТабличнаяЧастьДокумента.Владелец.Ссылка; // Привязка к объекту документа
            Если ЗначениеЗаполнено(ИдентификаторФормыДокумента) Тогда
                НовоеСообщение.ИдентификаторНазначения = ИдентификаторФормыДокумента; // Выводим в форму, откуда был вызов
            КонецЕсли;
            НовоеСообщение.Сообщить();
        КонецЕсли;
    КонецЦикла;

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

КонецПроцедуры

Обратите внимание, что для использования ИдентификаторНазначения, нам нужно передать идентификатор формы с клиента на сервер. Мы можем получить его с помощью метода формы УникальныйИдентификатор.

Использование Библиотеки стандартных подсистем (БСП)

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

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


// В процедуре с директивой НаСервере
Процедура ПроверитьОстаткиНаСервереСБСП(ТабличнаяЧастьДокумента) НаСервере
    // ... логика проверки ...
    Если НеДостаточноТовара Тогда
        // Пример вызова из БСП
        ОбщегоНазначения.СообщитьПользователю("Не хватает товара на складе!", 
                                              ОбъектДокумента.Ссылка, 
                                              "ТабличнаяЧасть.РеквизитКоличества");
    КонецЕсли;
КонецПроцедуры

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

Решение проблемы "теряющихся" сообщений при закрытии формы

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

Для решения этой проблемы мы можем использовать следующий подход:

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

Давайте рассмотрим, как это может выглядеть:


// В модуле формы документа

// Предположим, что мы передали идентификатор формы списка при открытии документа
// как параметр формы, например, "ИдентификаторФормыСписка".
// Или получили его из контекста.

ПеременнаяДляИдентификатораФормыСписка = Неопределено;

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

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

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    // ... Ваша логика после записи ...

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

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

Информационные сообщения: ПоказатьОповещениеПользователя()

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

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

Пример:


&НаСервере
Процедура ВыполнитьДлительнуюОперациюНаСервере()
    // ... Длительные вычисления ...
    ПоказатьОповещениеПользователя("Операция завершена", "Ваша длительная операция успешно выполнена.", , , "Информационная", 10);
КонецПроцедуры

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


// В серверной процедуре:
&НаСервере
Функция ВыполнитьДлительнуюОперациюНаСервереИСообщить()
    // ... Длительные вычисления ...
    Возврат "Ваша длительная операция успешно выполнена.";
КонецФункции

// В клиентской процедуре, которая вызывает серверную:
&НаКлиенте
Процедура ЗапуститьДлительнуюОперацию()
    ТекстОповещения = ВыполнитьДлительнуюОперациюНаСервереИСообщить();
    ПоказатьОповещениеПользователя("Операция завершена", ТекстОповещения);
КонецПроцедуры

Важность форматирования сообщений

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

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

Следуя этим рекомендациям, мы можем сделать наши приложения более удобными и интуитивно понятными для пользователей.

Выводы и лучшие практики

Мы выяснили, что в контексте управляемых форм и серверных вызовов в 1С:Предприятии 8.3:

  1. Для простых отладочных сообщений или в очень редких случаях, где не требуется никаких дополнительных функций, метод Сообщить() все еще может быть использован, но его следует избегать в продакшн-коде.
  2. Предпочтительным и рекомендованным методом является использование объекта СообщениеПользователю. Он предоставляет гибкость в привязке к элементам формы, данным объекта и указании целевой формы.
  3. В конфигурациях с БСП всегда следует использовать обертки БСП, такие как ОбщегоНазначения.СообщитьПользователю(), для стандартизации и упрощения кода.
  4. Мы должны предусмотреть механизмы перенаправления сообщений (например, из формы документа в форму списка), чтобы избежать потери важной информации при закрытии форм. Этого можно достичь, собирая сообщения после записи на сервере и повторно выводя их с указанием ИдентификаторНазначения родительской формы.
  5. Для некритичных информационных уведомлений и оповещений о длительных операциях следует использовать ПоказатьОповещениеПользователя(), вызывая его с клиента.
  6. Всегда уделяйте внимание формулировке сообщений, делая их максимально информативными, понятными и полезными для пользователя.

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

← На главную