При разработке управляемых приложений в 1С:Предприятие 8.3 часто возникает необходимость выполнять определенные действия после того, как пользователь закроет форму, открытую для просмотра или редактирования какого-либо значения. Для реализации такого асинхронного поведения платформа предоставляет механизм ОписаниеОповещения, который позволяет указать процедуру-обработчик, вызываемую по завершении определенного события. Однако, многие разработчики сталкиваются с тем, что методы, такие как ПоказатьЗначение, не всегда корректно отрабатывают с ОписаниеОповещения, особенно при работе со ссылочными типами данных. Давайте рассмотрим эту проблему подробнее и выясним, как ее решить.
ПоказатьЗначение и ОписаниеОповещенияИсходная задача, с которой мы столкнулись, заключается в следующем: есть табличная часть обработки, содержащая ссылки на различные элементы справочников. При клике на строку этой табличной части необходимо открыть форму элемента справочника для просмотра или редактирования, а после ее закрытия — обновить данные в табличной части, поскольку измененный элемент мог перестать соответствовать условиям отбора. Для открытия формы используется метод ПоказатьЗначение, а для обработки закрытия — ОписаниеОповещения.
Рассмотрим пример кода, демонстрирующий попытку реализации этой логики:
&НаКлиенте
Процедура СписокТекущихЗадачВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
// Создаем описание оповещения, указывая имя процедуры и объект-владелец
Оповещение = Новый ОписаниеОповещения("СтартОбновленияТекДанных", ЭтотОбъект);
// Вызываем ПоказатьЗначение для открытия формы элемента
ПоказатьЗначение(Оповещение, Объект.СписокТекущихЗадач[ВыбраннаяСтрока].СсылкаНаЗадачу);
КонецПроцедуры
&НаКлиенте
Процедура СтартОбновленияТекДанных Экспорт
// Сюда не попадает!
// Здесь должен был быть код для обновления данных, например:
// ОбновитьТекущиеДанные();
КонецПроцедуры
Как мы видим из комментария, процедура СтартОбновленияТекДанных, которая должна быть вызвана после закрытия формы, не отрабатывает. При этом, никаких явных ошибок платформа не выдает, что затрудняет диагностику проблемы. Разработчик ожидает, что после закрытия формы, открытой методом ПоказатьЗначение, будет вызвана процедура, указанная в ОписаниеОповещения. Однако этого не происходит.
Метод ПоказатьЗначение предназначен для унифицированного открытия формы представления какого-либо значения (элемента справочника, документа, перечисления и т.д.). Его удобство заключается в том, что нам не нужно заранее знать конкретный тип формы или даже метаданных, к которым относится ссылка; платформа сама определяет и открывает подходящую форму. Первый параметр ПоказатьЗначение — это опциональный объект ОписаниеОповещения, который, по идее, должен обеспечивать обратный вызов. Однако на практике возникает проблема, которую мы сейчас рассмотрим.
После многочисленных попыток и экспериментов выяснилось, что проблема с невызовом процедуры оповещения при использовании ПоказатьЗначение связана с известной ошибкой платформы 1С:Предприятие. Эта ошибка зарегистрирована под номерами **000149127** и **600111424** и, к сожалению, на текущий момент (согласно информации из открытых источников и поддержки 1С) находится "на рассмотрении" или "не исправлена".
Суть ошибки заключается в следующем: методы ПоказатьЗначение, ОткрытьЗначение и ОткрытьЗначениеАсинх некорректно обрабатывают ОписаниеОповещения, если в качестве второго параметра (значения для открытия) передается **ссылочный тип данных** (например, ссылка на элемент справочника или документ). При этом, если передать в ПоказатьЗначение простой тип данных (например, число, строка, булево), то оповещение срабатывает штатно. Именно поэтому разработчик не получает ошибок, но и процедура не вызывается — платформа просто игнорирует оповещение в данном специфическом случае.
Таким образом, наша исходная проблема заключается не в неправильном синтаксисе или недопонимании принципов работы ОписаниеОповещения, а в ограничении (или баге) самой платформы 1С:Предприятие. Осознание этого критически важно, так как позволяет не тратить время на поиск несуществующих ошибок в собственном коде.
ОткрытьФорму с ОписаниеОповещенияПоскольку ПоказатьЗначение не работает с ссылочными типами из-за ошибки платформы, нам необходимо найти альтернативный способ открытия формы с последующей асинхронной обработкой ее закрытия. Наиболее подходящим и надежным методом в данном случае является ОткрытьФорму.
Метод ОткрытьФорму позволяет явно указать имя формы, которую мы хотим открыть, и передать ей параметры. Он также поддерживает механизм ОписаниеОповещения для обработки события закрытия формы, и, в отличие от ПоказатьЗначение, корректно работает с передачей параметров и вызовом процедур оповещения.
ОткрытьФормуОдин из ключевых моментов, который часто вызывает затруднения, — это правильная сигнатура процедуры, указанной в ОписаниеОповещения. Документация 1С четко определяет, что для ОткрытьФорму процедура оповещения должна быть экспортной и принимать **два параметра**:
Закрыть открываемой формы. Это позволяет форме передать в обработчик свой "результат" работы. Если форма закрывается без явного указания результата, в этот параметр может быть передано Неопределено.ОписаниеОповещения (третий параметр конструктора Новый ОписаниеОповещения()). Это очень удобно для передачи контекстной информации из вызывающей процедуры в обработчик.Таким образом, процедура-обработчик должна выглядеть следующим образом:
&НаКлиенте
Процедура МояПроцедураОповещения(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
// Здесь выполняем необходимые действия после закрытия формы.
// Например, обновляем табличную часть, используя ДополнительныеПараметры,
// если в них была передана какая-либо полезная информация.
// Если РезультатЗакрытия важен, его тоже можно проанализировать.
// Пример:
// Если ДополнительныеПараметры.Свойство("ИмяТабличнойЧасти") Тогда
// ЭтаФорма[ДополнительныеПараметры.ИмяТабличнойЧасти].Очистить();
// ОбновитьДанныеТабличнойЧасти(ДополнительныеПараметры.ИмяТабличнойЧасти);
// КонецЕсли;
КонецПроцедуры
Если мы забудем указать оба параметра или укажем их неправильно, платформа выдаст ошибку, например: "В методе МояПроцедураОповещения количество параметров 0. Ожидаемое количество – 2". Это хороший индикатор того, что мы ошиблись в сигнатуре процедуры-обработчика.
ОткрытьФормуТеперь, когда мы знаем о правильной сигнатуре процедуры-обработчика и о том, что ПоказатьЗначение имеет ограничения, перепишем наш исходный код, используя ОткрытьФорму:
ОткрытьФорму принимает параметры формы в виде структуры. Для открытия существующего объекта обычно используется параметр "Ключ", в который передается ссылка на объект.ОписаниеОповещения: Аналогично исходной задаче.ОткрытьФорму: С указанием имени формы, параметров формы и ОписаниеОповещения.Вот как будет выглядеть доработанный код:
&НаКлиенте
Процедура СписокТекущихЗадачВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отменяем стандартную обработку, если таковая есть
// Получаем ссылку на объект из табличной части
СсылкаНаОбъект = Объект.СписокТекущихЗадач[ВыбраннаяСтрока].СсылкаНаЗадачу;
// Проверяем, что ссылка не пустая и определена
Если СсылкаНаОбъект = Неопределено Или СсылкаНаОбъект.Пустая() Тогда
Возврат;
КонецЕсли;
// Определяем имя формы объекта.
// Для универсальности можно использовать Метаданные.
ИмяФормыОбъекта = СсылкаНаОбъект.Метаданные().ПолноеИмя() + ".ФормаОбъекта";
// Создаем структуру параметров для открываемой формы
// "Ключ" - стандартный параметр для открытия существующего объекта
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаОбъект);
// Создаем описание оповещения для процедуры-обработчика
// В третий параметр можно передать ДополнительныеПараметры, например, имя текущей ТЧ
ДополнительныеПараметрыОповещения = Новый Структура;
ДополнительныеПараметрыОповещения.Вставить("ИмяТЧ", "СписокТекущихЗадач");
Оповещение = Новый ОписаниеОповещения("СтартОбновленияТекДанных", ЭтотОбъект, ДополнительныеПараметрыОповещения);
// Вызываем ОткрытьФорму
// Обратите внимание на порядок параметров и их количество.
// ПараметрыФормы - это второй параметр, Оповещение - седьмой.
ОткрытьФорму(ИмяФормыОбъекта, ПараметрыФормы, , , , , Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура СтартОбновленияТекДанных(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
// Сюда мы гарантированно попадем после закрытия формы,
// если все параметры и сигнатура процедуры указаны верно.
// Можно проанализировать РезультатЗакрытия,
// который вернула закрываемая форма (например, ОК, Отмена)
// Используем ДополнительныеПараметры, переданные при создании Оповещения
Если ДополнительныеПараметры <> Неопределено И ДополнительныеПараметры.Свойство("ИмяТЧ") Тогда
Сообщить("Форма закрыта. Обновляем табличную часть: " + ДополнительныеПараметры.ИмяТЧ);
// Пример вызова серверной процедуры для обновления данных
// Или клиентской, если это возможно
ОбновитьДанныеТекущихЗадачНаСервере();
Иначе
Сообщить("Форма закрыта. Дополнительные параметры не получены.");
КонецЕсли;
КонецПроцедуры
// Пример серверной процедуры для обновления данных
&НаСервереБезКонтекста
Процедура ОбновитьДанныеТекущихЗадачНаСервере()
// Здесь получаем текущий объект формы или данные, необходимые для запроса
// Например, можно передать их как параметр в процедуру СтартОбновленияТекДанных
// и затем на сервер.
// Пример:
// Запрос = Новый Запрос;
// Запрос.Текст = "ВЫБРАТЬ ... ИЗ ... ГДЕ ...";
// РезультатЗапроса = Запрос.Выполнить().Выгрузить();
//
// Возврат РезультатЗапроса; // Если нужно вернуть данные на клиент
КонецПроцедуры
// Пример клиентской процедуры, вызывающей серверную и обновляющей ТЧ
&НаКлиенте
Процедура ОбновитьДанныеТекущихЗадач()
// Здесь мы могли бы вызвать серверную процедуру для обновления данных
// и затем обновить нашу табличную часть
// Например:
// НовыеДанные = ПолучитьДанныеДляТабличнойЧастиНаСервере();
// Если НовыеДанные <> Неопределено Тогда
// Объект.СписокТекущихЗадач.Загрузить(НовыеДанные);
// КонецЕсли;
КонецПроцедуры
В этом примере мы демонстрируем, как можно использовать ОткрытьФорму для решения нашей задачи. Критически важно убедиться, что имя формы объекта определено правильно, особенно если в табличной части могут быть ссылки на различные типы объектов. Для универсальности мы можем получить имя формы объекта, используя метаданные ссылки: СсылкаНаОбъект.Метаданные().ПолноеИмя() + ".ФормаОбъекта".
Как только мы внедрили предложенное решение с ОткрытьФорму, проблема была успешно решена. Процедура СтартОбновленияТекДанных стала корректно вызываться после закрытия формы редактирования элемента, позволяя нам обновить табличную часть.
ОписаниеОповещенияДля более глубокого понимания рассматриваемой ситуации и асинхронной работы в 1С, давайте более детально разберем объект ОписаниеОповещения.
ОписаниеОповещения – это фундаментальный объект встроенного языка 1С:Предприятие, используемый для организации асинхронного выполнения кода. Он является своего рода "обратным вызовом" (callback), который указывает платформе, какую процедуру и в каком модуле необходимо вызвать после наступления определенного события. Этот механизм стал особенно важным с появлением управляемых форм и веб-клиента, поскольку позволяет избегать модальных окон (которые блокируют интерфейс до своего закрытия) и обеспечивает плавность работы пользовательского интерфейса.
Основные события, для которых используется ОписаниеОповещения:
ОткрытьФорму).ВыполнитьАсинхронно).ВыбратьИзСписка).Конструктор объекта ОписаниеОповещения может принимать до пяти необязательных параметров:
Новый ОписаниеОповещения([ИмяПроцедуры], [Модуль], [ДополнительныеПараметры], [ИмяПроцедурыОбработкиОшибки], [МодульОбработкиОшибки])
ИмяПроцедуры (Тип: Строка): Это имя экспортной процедуры, которая будет вызвана в случае успешного завершения операции или события. Обязательно убедитесь, что процедура является экспортной! В противном случае платформа выдаст ошибку "Не найден экспортируемый метод: <ИмяПроцедуры>".Модуль (Тип: КлиентскийМодуль или МодульОбъекта): Это модуль, в котором расположена вызываемая процедура. Чаще всего это ЭтотОбъект (для процедур в модуле формы), но может быть и общий модуль. Процедура должна быть доступна в клиентском контексте, так как сам объект ОписаниеОповещения доступен только на клиенте.ДополнительныеПараметры (Тип: Произвольный): Это произвольное значение (например, структура, массив, строка), которое будет передано в процедуру, указанную в ИмяПроцедуры, в качестве последнего параметра. Это очень удобно для передачи контекстной информации, которая может понадобиться обработчику события. Для ОткрытьФорму это будет второй параметр процедуры-обработчика.ИмяПроцедурыОбработкиОшибки (Тип: Строка): Имя экспортной процедуры, которая будет вызвана в случае возникновения ошибки при выполнении асинхронной операции. Эта процедура также должна быть экспортной и принимать свои специфические параметры (подробнее см. в синтакс-помощнике).МодульОбработкиОшибки (Тип: КлиентскийМодуль или МодульОбъекта): Модуль, в котором расположена процедура обработки ошибки.Важные аспекты использования ОписаниеОповещения:
ИмяПроцедуры, должна быть помечена директивой компиляции &НаКлиенте, поскольку вызов обратного оповещения происходит на стороне клиента.Экспорт после имени).ОткрытьФорму это два параметра: РезультатЗакрытия и ДополнительныеПараметры.Неправильное количество параметров в процедуре-обработчике — одна из самых частых ошибок. Платформа очень строго к этому относится и выдает информативные сообщения об ошибке, что помогает быстро ее исправить.
При работе с ОписаниеОповещения и асинхронными вызовами, могут возникать различные ситуации, требующие отладки. Вот несколько рекомендаций:
СтартОбновленияТекДанных). Если отладчик не останавливается на этой точке после закрытия формы, это означает, что процедура оповещения вообще не была вызвана. В этом случае сосредоточьтесь на коде, который создает ОписаниеОповещения и вызывает основной метод (ОткрытьФорму, ПоказатьЗначение).&НаКлиенте) и что указанный модуль (второй параметр ОписаниеОповещения) является правильным (например, ЭтотОбъект для модуля формы, или ссылка на общий модуль).ОписаниеОповещения. Там детально описаны ожидаемые параметры процедуры-обработчика.ПоказатьЗначение, попробуйте передать в метод простой тип данных (например, строку "Привет"). Если в этом случае оповещение сработает, а со ссылкой нет, это может указывать на специфическую ошибку платформы.Мы подробно разобрали проблему с неработоспособностью ПоказатьЗначение в связке с ОписаниеОповещения для ссылочных типов в 1С:Предприятие 8.3. Ключевые выводы, которые мы можем сделать:
ПоказатьЗначение с ссылочными типами и ОписаниеОповещения: На данный момент (согласно информации об ошибках платформы 1С) этот сценарий не работает из-за известной ошибки платформы (000149127, 600111424). Избегайте использования ПоказатьЗначение, если вам нужна асинхронная обработка закрытия формы со ссылочным типом.ОткрытьФорму как альтернативу: Метод ОткрытьФорму является надежным и полностью рабочим решением для открытия форм с последующей асинхронной обработкой их закрытия через ОписаниеОповещения. Он позволяет передавать необходимые параметры и корректно вызывает процедуру-обработчик.ОткрытьФорму процедура оповещения должна быть экспортной и принимать два параметра: РезультатЗакрытия и ДополнительныеПараметры. Неправильное количество или отсутствие ключевого слова Экспорт приведет к ошибкам.ОписаниеОповещения: Этот механизм крайне важен для разработки современных управляемых приложений в 1С, обеспечивая немодальное взаимодействие и улучшая пользовательский опыт. Изучите его принципы работы и параметры конструктора, чтобы эффективно использовать в своих проектах.Применяя эти знания и рекомендации, мы сможете эффективно реализовывать асинхронное взаимодействие в ваших 1С-приложениях, обеспечивая стабильную и предсказуемую работу, даже в условиях известных ограничений платформы.