При разработке интерфейсов на управляемых формах программисты часто сталкиваются с ситуацией, когда сообщение, сформированное в процедуре ПриСозданииНаСервере, «улетает» в основное окно приложения вместо того, чтобы отобразиться в окне открываемой формы. Это создает неудобства для пользователя, так как сообщение может потеряться на фоне других уведомлений или вовсе остаться незамеченным. В этой статье мы подробно разберем, почему это происходит, и рассмотрим несколько эффективных способов решения этой задачи.
Для начала проанализируем ситуацию и поймем механику работы платформы 1С. Процедура ПриСозданииНаСервере выполняется на стороне сервера еще до того, как форма была физически отрисована на клиенте. В этот момент существует контекст формы, ее реквизиты и элементы, но само ОкноКлиентскогоПриложения еще не создано. Если мы просто вызываем метод Сообщить() или создаем объект СообщениеПользователю без явного указания привязки, платформа помещает его в общую очередь сообщений текущего сеанса. Когда сервер возвращает управление клиенту, клиентское приложение выводит накопленные сообщения в активное на тот момент окно — и зачастую это основное окно программы.
Наиболее «чистый» с точки зрения архитектуры способ — это использование свойства ИдентификаторНазначения объекта СообщениеПользователю. Этот идентификатор позволяет платформе понять, какому именно окну адресовано сообщение. В качестве значения мы должны передать уникальный идентификатор текущей формы.
Разберем по шагам, как это реализовать в коде:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Добро пожаловать в форму! Пожалуйста, проверьте данные.";
// Привязываем сообщение к текущей форме через ее уникальный идентификатор
Сообщение.ИдентификаторНазначения = ЭтаФорма.УникальныйИдентификатор;
Сообщение.Сообщить();
КонецПроцедуры
Важный нюанс: этот метод гарантирует, что сообщение будет направлено в нужное окно, когда оно будет открыто на клиенте. Однако, стоит помнить, что на очень старых релизах платформы 8.3 этот механизм мог работать нестабильно, поэтому всегда проверяйте поведение в вашей конкретной версии.
Если нам нужно не просто вывести текст, а подсветить конкретное поле или привязать сообщение к объекту (например, к документу или справочнику), мы используем метод УстановитьДанные(). Платформа 1С устроена так, что если сообщение связано с путем к данным, которые отображаются на форме, оно автоматически «прилипает» к этой форме и выводится в ее панели сообщений.
Рассмотрим пример, где сообщение привязывается к основному реквизиту Объект:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Внимание: реквизит 'Наименование' заполнен некорректно.";
// Указываем путь к данным и поле
Сообщение.Поле = "Объект.Наименование";
Сообщение.ПутьКДанным = "Объект";
// Устанавливаем связь с конкретным объектом данных
Сообщение.УстановитьДанные(Объект);
Сообщение.Сообщить();
КонецПроцедуры
Проанализируем ситуацию: когда мы используем УстановитьДанные(Объект), платформа ищет форму, которая редактирует этот объект, и выводит сообщение именно там. Это самый эффективный способ избежать «всплытия» сообщений в главном окне.
Иногда возникают ситуации, когда на сервере еще невозможно точно определить, как должно выглядеть сообщение, или вы хотите использовать клиентские возможности (например, вывести ПоказатьПредупреждение). В этом случае мы можем сохранить информацию о необходимости вывода сообщения в реквизите формы или в структуре параметров, а само действие выполнить в процедуре ПриОткрытии на клиенте.
Разберем этот алгоритм:
ТекстСообщенияПриОткрытии (тип Строка).ПриСозданииНаСервере заполним этот реквизит.ПриОткрытии проверим реквизит и выведем сообщение.Пример кода на сервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Логика проверки
Если Объект.Сумма = 0 Тогда
ЭтаФорма.ТекстСообщенияПриОткрытии = "Не забудьте указать сумму документа!";
КонецЕсли;
КонецПроцедуры
Пример кода на клиенте:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если Не ПустаяСтрока(ТекстСообщенияПриОткрытии) Тогда
ПоказатьОповещениеПользователя("Внимание", , ТекстСообщенияПриОткрытии);
// Или стандартное сообщение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ТекстСообщенияПриОткрытии;
Сообщение.Сообщить();
КонецЕсли;
КонецПроцедуры
Этот подход хорош тем, что в момент выполнения ПриОткрытии окно формы уже гарантированно существует и является активным, поэтому сообщение будет выведено корректно.
Если ваша задача — информировать пользователя о статусе или важных условиях работы с формой, возможно, стандартное сообщение — не лучший вариант. Вместо него мы можем использовать элементы формы типа Декорация-надпись. Это выглядит более профессионально и интегрировано в интерфейс.
Разберем, как это сделать:
ИнформационнаяНадпись.ЦветТекста (например, Красный) и сделаем его по умолчанию невидимым.ПриСозданииНаСервере будем управлять его видимостью и текстом.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Статус = Перечисления.СтатусыДокументов.Заблокирован Тогда
Элементы.ИнформационнаяНадпись.Заголовок = "ВНИМАНИЕ: Редактирование запрещено!";
Элементы.ИнформационнаяНадпись.Видимость = Истина;
Иначе
Элементы.ИнформационнаяNadpis.Видимость = Ложь;
КонецЕсли;
КонецПроцедуры
Такой способ исключает риск того, что сообщение «улетит» в другое окно, так как текст является частью самой формы.
Подведем итог нашему исследованию. Для того чтобы сообщение гарантированно осталось внутри формы при его создании на сервере, рекомендуется:
СообщениеПользователю.ИдентификаторНазначения и передавать туда УникальныйИдентификатор формы.УстановитьДанные(), если это технически возможно.ПриОткрытии.Выбор конкретного метода зависит от ваших задач, но наиболее стабильным и предпочтительным в современной разработке на платформе 1С 8.3 является сочетание привязки к данным и идентификатора назначения.