1с отключить обработчик события

Обновлено: 07.07.2024

Механизм подписок на событие предназначен для назначения обработчика события для одного или нескольких объектов конфигурации платформы «1С:Предприятие». В статье рассматриваются несколько примеров применения данного механизма. Изучив статью, вы узнаете:

Применимость

В статье рассматривается платформа «1С:Предприятие» редакции 8.3. Представленная информация актуальна для текущих релизов платформы.

Подписки на события

В статье рассматриваются несколько примеров применения одного из вспомогательных объектов платформы «1С:Предприятие 8» – подписок на события.

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

Подписки на события описываются в ветке Общие окна объектов конфигурации (Рис.1).

  1. Выполняется обработчик события ПередЗаписью() в модуле объекта документа.
  2. Если в ходе выполнения обработчика параметр Отказ принимает значение Истина или вызывается исключение, то обработка события прерывается.
  3. Если на втором шаге обработка события не прерывалась, то выполняются внешние обработчики (подписки на события), определенные для события ПередЗаписью().
  4. Если в ходе выполнения внешнего обработчика параметр Отказ принимает значение Истина или вызывается исключение, то выполнение внешнего обработчика прерывается.

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

Задача 1

Флаг Клиент (обычное приложение) доступен, если в параметрах конфигуратора установлен режим редактирования Управляемое приложение и обычное приложение.

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

Процедура обработки подписки на событие

Листинг процедуры ПроверкаНаименованияСправочникаПередЗаписью()

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

Задача 2

Касса, тип: СправочникСсылка.Кассы;
Статья, тип: СправочникСсылка.СтатьиДвиженияДенежныхСредств.

Создать ресурс регистра:

Создать новую подписку на событие:

Имя – ДвиженияПоВыбытиюДенежныхСредств;
Источник – ДокументОбъект.РКО;
Событие – ОбработкаПроведения.

Листинг процедуры ДвиженияПоВыбытиюДенежныхСредствОбработкаПроведения()

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

Задача 3

Создать новую подписку на событие:

В общем модуле ОбработчикиПодписокНаСобытия создать обработчик ОсновнаяФормаРКООбработкаПолученияФормы(). В обработчик в качестве параметра ВыбраннаяФорма передается имя открываемой формы.
Параметр СтандартнаяОбработка устанавливается в значении Ложь для отключения открытия основной формы.

Листинг процедуры ОсновнаяФормаРКООбработкаПолученияФормы()

Листинг процедуры ОсновнаяФормаРКООбработкаПолученияФормы

Таким образом, подписки на события предоставляют возможность добавления нового функционала, не изменяя существующие модули объектов. К недостаткам подписок на события можно отнести:

  • Увеличение сложности алгоритмов.
  • Подписаться можно только на события объектов и менеджеров объектов.

Если необходимо модифицировать какое-либо событие формы, то механизм подписок на события не доступен. В этом случае, необходимо вносить изменения в саму форму или копировать форму и вносить изменения в новый объект.

(14) еще раз пишу для непонятливых:
Во внешней обработке:
В модуле объекта ДОКУМЕНТА:

(11) при обмене устанавливается автоматом, но никто не мешает вставить установку флага в программу перед записью.

если писали не криворучки, то в подписке первым делом должно стоять отключение по этому флагу всех действий.

(11) и что? По сути это такое же доп. Свойство, но в отличие от от них, на него уже есть реакция в объектах типовых
(16) Получается без вмешательства в конфу не получится. эх а так хотелось
Сдается мне, что там даже при обмене данными формы вылетают
Получится, если типовая и выставить обменданными.загрузка в истину в модуле обработки перед вызовом метода записать() объекта
(21) а что там за форма. ты процедуру покажи. Может форму эту мона обойти
(24) я довольно часто применяю этот способ для обхода типового кода.
+ (29) все этот метод используют постоянно потому что он всем известен и работает

(27) фига се, проверил сейчас, действительно истина.

Откуда у меня взялся стереотип, что программно это свойство не установить?

(33) Фига себе, пятница, почти полночь и ты полез в конфигуратор 1с проверить какую то фигню!
(33) мы не знаем. Объективных предпосылок для того чтобы так думать нет. Более того, например типовая обработка выгрузказагрузкаданныххмл82.епф, которая используется всеми для адресного восстановления объектов и записей регистров из бэкапов, дает выставить это свойство специально, чтобы не выполнялись проверки при записи при загрузке восстанавливаемого объекта
перед
Объект.Записать(РежимЗаписиДокумента.Проведение)
(36) а может вы лукавите и раньше (в другой платформе или релизе) ОбменДанными.Загрузка был доступен только для чтения?
(40) Нет. Более того, мне кажется что это свойство выставлялось всегда исключительно только программнр
(41) не, в при обмене через планы обмена, система его устанавливает в ИСТИНА

(38) в обработчике перед записью, перед открытием вашей формы, должен быть код анализа, как в (16)

(41) нет, в случае обмена с использованием плана обмена оно выставляется движком

(39) тема себя исчерпала, у вас есть все предпосылки чтобы решить проблему.
(47) а если распределенная база, то свойство ОбменДанными тоже доступно не только для чтения?
(47) что может значить эта ошибка:
Действие не может выполняться в режиме загрузки данных
?
(49) у тебя в БД есть план обмена с галкой "распределенная информационная база"?
(51) обработка, случайно, не запускает обмен по этому плану обмена?
(50) те планы обменами, которые для этого документа отмечены без установленного значения Распределенная ИБ.
(52) Короче тут, такая история я не программист 1с, я в поддержке сижу знаю чуть больше других юзеров. и вот наши программисты внесли в конфу некторые изменения, после которых документ перестал создаваться через эту обработку из-за того, что они вызывают модально некоторую форму. я просто хочу 1с-ку изучить вот и решил попытаться обработку изменить, не трогая конфу.
(54) покажи код, которым ты изменяешь документ в обработке

(49) > Действие не может выполняться в режиме загрузки данных

Говорит о том, что что-то написано такое, что не поддерживается Когда свойство ОбменДанными.Загрузка установлено в значение Истина

+(57) Скорее всего это в конфигурации написано.

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

Таких увольнять сразу надо, если они с серьезными вещами работают.

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

Если есть, то оно до открытия формы расположено?

(59) если при выполнении этого кода появляется модальное окно - то гнать этих недоделанных прогов студентов до самого заднего задищенво.

короче пишешь докладную и ссылку на эту ветку.

(59) зачем ты приводишь код в котором нет ошибки? Тебя ведь просили привести код при или перед записи, потому что именно там написано то .авно, которое портит тебе жизнь
(64) прошу прощения, но я не могу этот код скопипастить сюда.
(64) думаю, что у него следующее:
при установленном свойстве ОбменДанными=Истина не может открыться модальное окно той копрокодерской формы и вываливается ошибка "Действие не может выполняться в режиме загрузки данных "
(48) что?
А ты можешь привести пример хоть одного свойства которое вдруг перестает быть доступным для чтения в зависимости от такой эфемерной сущности как план обмена, его наличия и наличия хотя бы одного узла в таких планах обмена, и хотя бы приблизительную причину почему такое могли сделать разработчики?

(68) мне все покоя мысль не дает, откуда я взял, что это свойство только для чтения :)

(66) ты так говоришь, как будто это мы вынудили тебя создать топик на форуме в котором ты у нас спрашиваешь как решить твою проблему.

Нет, это не мы. По прежнему у тебя уже есть все предпосылки чтобы ее решить, ничего нового написано не будет, только перелив из пустого в не более полное

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

Казалось бы, всё это есть в литературе. Зачем словами переписывать? В этой статье собрана и структурирована информация из разных источников. Однако не всегда и не у всех есть эта литература под рукой. А тут информация в открытом источнике и достаточно структурированная, изложенная простым языком. Тем самым делаем эти знания более понятными и доступными.

Будем рассматривать запись документа, чтобы не загромождать статью и не описывать все типы объектов (у них всё также, за небольшим исключением).

Итак, для чего нам вообще нужны эти обработчики?

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

Последовательность запуска событий (в том порядке, в каком они перечислены) и небольшие подробности:

Во многих обработчиках есть параметр «Отказ». Там, где этот параметр присутствует означает, что в этом обработчике ещё можно отказаться от записи, присвоив параметру «Отказ» значение Истина, и тогда запись произведена не будет. И ещё, отдельно отмечу, что п ри программной записи события модуля формы не запускаются!

1) Модуль формы ПередЗаписью(Отказ, ПараметрыЗаписи)

Выполняется на клиенте!

Этот обработчик следует использовать, если необходимо организовать диалог с пользователем перед тем, как записать объект. Запросить дополнительную информацию, предупредить о чём-либо, дать возможность отказаться и т.п.

Второй параметр этого обработчика «ПараметрыЗаписи» имеет тип «Структура». У документов эти параметры заполняются системой предопределенными параметрами РежимЗаписи, РежимПроведения. Можно добавить свои!

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

2) Модуль формы ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты)

3) Модуль объекта ОбработкаПроверкиЗаполнения (Отказ, ПроверяемыеРеквизиты)

Сначала вызывается событие формы ОбработкаПроверкиЗаполненияНаСервере На данном этапе есть доступ к данным формы.

После этого в памяти сервера создается прикладной объект, соответствующий типу основного реквизита формы, и его данные заполняются из данных формы.

Затем вызывается событие прикладного объекта ОбработкаПроверкиЗаполнения .

Эти два обработчика проверки заполнения реализуются через параметр «ПроверяемыеРеквизиты» типа Массив, содержащий реквизиты, которые надо проверять (т.е. которым установлено свойство проверки заполнения «Выдавать ошибку»). И если из этого массива убрать реквизит, то проверяться он не будет, если добавить, то будет выполняться проверка заполнения.

Эти два обработчика событий предназначены :

  1. Для включения в проверку заполнения тех реквизитов, у которых в свойствах «ПроверкаЗаполнения» указано «Не проверять». Для этого надо добавить этот реквизит в массив параметр «ПроверяемыеРеквизиты»
  2. Для того, чтобы исключить из автоматической проверки реквизиты, у которых установлено свойство проверки заполнения «Выдавать ошибку» в зависимости от каких-то условий. Для этого надо удалить этот реквизит из массива параметра «ПроверяемыеРеквизиты»

Имеется несколько особенностей, которые необходимо учитывать:

  1. Если у формы из которой записывается объект в свойствах не установлено «ПроверятьЗаполнениеАвтоматически», то тогда эти обработчики проверки заполнения не вызываются и проверки не происходят!
  2. Вызываются только при интерактивной записи! При программной записи не вызываются. Для проверки нужно использовать метод объекта ПроверитьЗаполнение(), который инициирует запуск этих событий.
  3. Для документов, имеющих возможность проведения, эти события проверки заполнения вызываются только при проведении!

Если данные формы не нужны, то используйте обработчик модуля объекта ОбработкаПроверкиЗаполнения

4) Модуль формы ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)

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

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

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

Параметр ТекущийОбъект имеет тип класса «объект» в зависимости от типа записываемого объекта (в случае записи документа ДокументОбъект). Т.е. экземпляр класса объект создан, и можно обратиться к его свойствам и методам, но в базу данных ещё не записан.

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

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

Также нужно понимать, что при программной записи объекта это событие вызываться не будет.

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

Начало транзакции

5) Модуль объекта ПередЗаписью(Отказ)

В этом обработчике можно провести дополнительные проверки и отказаться от записи.

Для документов в параметры данного обработчика добавляются ещё два параметра: РежимЗаписи, РежимПроведения.

Запись

6) Модуль объекта ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)

Возникает в момент, когда выполняется установка номера нового документа, задачи или бизнес-процесса.

Или ПриУстановкеНовогоКода(СтандартнаяОбработка,Префикс)

Возникает в момент, когда выполняется установка нового кода элемента справочника, узла плана обмена или кода плана видов характеристик.

Эти событии вызываются для объектов у которых указано свойство «Автонумерация» и только для тех объектов, у которых пустой код на момент записи.

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

7) Модуль объекта ОбработкаУдаленияПроведения (Отказ)

Этот обработчик запускается только при отмене проведения документов с целью удаления движений из регистров. При этом неважно как отменяется проведение документа - программно или интерактивно.

8) Модуль объекта ПриЗаписи(Отказ)

Вызывается после записи объекта в базу данных, но до окончания транзакции записи.

Назначение этого обработчика - записать в базу данных дополнительную информацию, связанную с данными записываемого объекта.

Ссылка уже есть и можно записать в базу данных дополнительные данные на основании текущего объекта, используя эту ссылку.

Например, при записи создавать другой документ, содержащий реквизит ссылку на записываемый.

Поскольку это событие обрабатывается в транзакции записи основных данных, гарантируется синхронность изменения основных и дополнительных данных. Либо и те и другие будут записаны, либо и те и другие изменения будут отменены при отмене транзакции.

Можно ещё отказаться от записи.

9) Модуль объекта ОбработкаПроведения (Отказ, РежимПроведения)

Этот обработчик запускается только при проведении документов. При этом неважно как проводится документ - программно или интерактивно.

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

Параметр РежимПроведения определяет как будет проводиться документ: оперативно или неоперативно.

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

10) Модуль формы ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)

Вызывается после записи объекта в базу данных, но до окончания транзакции записи.. Есть последний шанс отказаться от записи.

Назначение этого обработчика – записать в базу данных дополнительную информацию, связанную с данными записываемого объекта.

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

Этот обработчик ещё используется, если нужны данные параметра обработчика ПараметрыЗаписи, которые «приехали» в этом параметре из других обработчиков.

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

Работать следует именно через этот параметр, то есть не путать с основным реквизитом формы Объект, так как там данные, которые были до записи и его изменения бесполезны потому, что после этого обработчика данные из ТекущегоОбъекта запишутся в Объект.

Если это запись нового объекта, то ТекущийОбъект.Ссылка будет содержать уже конкретное значение ссылки на этот элемент в информационной базе. А вот Объект.Ссылка имеет пустое значение на этом этапе.

Итак, по поводу этого обработчика можно сделать следующие выводы:

  • Если нужно выполнять какие-то действия, связанные с записанным объектом, и при этом, например, нужна ссылка на этот объект, необходимо использовать ТекущийОбъект.Ссылка.
  • Основной реквизит формы Объект можно использовать только для сравнения того, что «было», с тем, что «записалось».
  • Если нужно изменить записанные дополнительные данные на основании данных формы и данных объекта, то необходимо использовать в данном обработчике при обращении к данным объекта ТекущийОбъект

Завершение транзакции

11) Модуль формы ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)

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

Этот обработчик используют, когда предполагаются действия над формой. Это те действия, которые должны быть выполнены только в том случае, когда объект 100 % записан (т.е. после транзакции). Например, вывод в форме некоторой дополнительной информации, связанной с данными объекта. Или выполнение каких-либо действий, которые должны быть выполнены только в том случае, когда объект гарантированно записан.

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

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

Доступны ПараметрыЗаписи, данные которых «приехали» в этом параметре из других обработчиков.

12) Модуль формы ПослеЗаписи(ПараметрыЗаписи)

Выполняется на клиенте!

Можно использовать для того, чтобы визуально что-то отобразить на форме или организовать диалог с пользователем, например выдать предупреждение.

Доступны ПараметрыЗаписи, данные которых «приехали» в этом параметре из других обработчиков.

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

Обработчики событий объекта на которые можно сделать подписку на события:
- ПриУстановкеНовогоНомера / ПриУстановкеНовогоКода
- ПриКопировании
- ОбработкаЗаполнения
- ПередЗаписью
- ПриЗаписи
- ПередУдалением
- ОбработкаПроведения
- ОбработкаУдаленияПроведения
- ОбработкаПроверкиЗаполнения

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

Т.е., если для какого-то документа в конфигурации есть две подписки на событие ПриЗаписи, то в начале выполнится та, которая расположена выше.

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

Как вариант указывать в своей подписке источник ДокументОбъект и ставить ее ниже по списку, а в самом обработчике проверять тип документа:
Если ТипЗнч(Источник) <> Тип("ДокументОбъект.МойДокумент") Тогда
Возврат;
КонецЕсли;

Если статья оказалась вам интересной и полезной, то сохраняйте, чтоб не потерять и иметь под рукой- просто нажимайте + и получите от меня + в свою карму :))

После каждого обновления базы в ней должны отработать так называемые обработчики обновления.

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

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

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

А если мы применяем к базе сразу несколько обновлений, то желательно, чтобы соответствующие обработчики были выполнены после каждого из таких промежуточных обновлений. Если этого не сделать, то появляется риск того, что возникнет ошибка при попытке выполнения этих же обработчиков, но уже после всех выполненных промежуточных обновлений.

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

И это, во-первых, позволяет применять сразу несколько обновлений к базе без дополнительного риска появления ошибок при последующем выполнении обработчиков обновления. А, во-вторых, делает возможным начало работы пользователей сразу же после окончания обновления без ожидания выполнения обработчиков.

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

Во всех этих случаях следует чётко следовать инструкции для того, чтобы всё-таки выполнить все обработчики, прежде чем продолжить обновление.

Как отключить их выполнение обновлятором

Если же вы предпочитаете сами видеть весь процесс выполнения обработчиков обновления и не хотите, чтобы эту работу за вас делал обновлятор - выполните следующее:

1. В ыделите базу в списке обновлятора и нажмите кнопку "Свойства базы":


2. Перейдите на закладку "Обновление", раздел "Обработчики" и поставьте галку "Не выполнять обработчики обновления":


Готово. Теперь обработчики обновления будут выполняться уже после запуска базы пользователем.

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

Как помочь сайту: расскажите (кнопки поделиться ниже) о нём своим друзьям и коллегам. Сделайте это один раз и вы внесете существенный вклад в развитие сайта. На сайте нет рекламы, но чем больше людей им пользуются, тем больше сил у меня для его поддержки.

Предлагаемый метод состоит в том, чтобы в модуле формы в процедуре «ПриСозданииНаСервере» переопределить обработчики событий для этой формы, которые будут вызывать старые обработчики (если это нужно) и выполнить нужный код до и после этого вызова. Так же обеспечить возможность вносить изменения в поведения программы на лету – без отключения от базы пользователей и без использования динамического обновления конфигурации, то есть изменения уже будут готовы к использованию. Что же для этого нужно? Рассматриваемый пример работает на конфигурации «Управление торговлей, редакция 11», для любой другой конфигурации адаптировать его не составит большого труда.

1. Нужно создать общий модуль МодульПереназначенияОбра ботчиков, вот такой он у меня:

// Общая процедура перед переназначения обработчиков
//
// Параметры:
// УправляемаяФорма – УправляемаяФорма – Управляемая форма.
//
Процедура ПереназначитьОбработчики ( УправляемаяФорма ) Экспорт
Если ТипЗнч ( УправляемаяФорма ) = Тип ( "УправляемаяФорма" ) Тогда
ОбщаяВнешняяОбработка = ПолучитьВнешнийОбъект ( "Библиотека внешних обработок" );

ВнешняяОбработкаСерийныеНомера = ПолучитьВнешнийОбъект ( "Серийные номера" );
ИмяВнешнейОбработкиСерийныеНомера = ПолучитьИмяВнешнегоОбъекта ( "Серийные номера" );
ВнешняяОбработкаСерийныеНомера . ПодготовитьСерийныеНомераКРаботе ( УправляемаяФорма , ОбщаяВнешняяОбработка , ИмяВнешнейОбработкиСерийныеНомера );

ОбщаяВнешняяОбработка . ПодменитьДействиеУправляемоеПриложение ( УправляемаяФорма , "ПриЗакрытии" , , "ВыполнитьОткатОбработчиков" );

//Пример как можно изменить свойства управляемой формы
УправляемаяФорма . ПоведениеКлавишиEnter = ТипПоведенияКлавишиEnter . ПереходПоЭлементамФормы ;
КонецЕсли;
КонецПроцедуры

// Получаем внешнюю обработку или внешний отчет.
//
// Параметры:
// ИмяВнешнегоОбъекта – Строка - имя внешнего объекта;
// ЭтоОтчет – Булево – Ложь (Внешняя обработка), Истина (Внешний отчет).
//
// Возвращаемое значение:
// – ВнешняяОбработка или ВнешнийОтчет
//
Функция ПолучитьВнешнийОбъект ( ИмяВнешнегоОбъекта , ЭтоОтчет = Ложь) Экспорт
Ссылка = Справочники . ДополнительныеОтчетыИОбработки . НайтиПоНаименованию ( ИмяВнешнегоОбъекта );
Если Ссылка = Неопределено Тогда
ВызватьИсключение "Внешний объект с именем не найден: " + ИмяВнешнегоОбъекта ;
КонецЕсли;
ДвоичныеДанные = Ссылка . ХранилищеОбработки . Получить ();
АдресХранилища = ПоместитьВоВременноеХранилище ( ДвоичныеДанные );
ИмяВнОбработки = ?( ЭтоОтчет , ВнешниеОтчеты , ВнешниеОбработки ). Подключить ( АдресХранилища , , Ложь);
ОбработкаОбъект = ?( ЭтоОтчет , ВнешниеОтчеты , ВнешниеОбработки ). Создать ( ИмяВнОбработки );
Возврат ОбработкаОбъект ;
КонецФункции

// Получаем имя внешней обработки или внешнего отчета.
//
// Параметры:
// ИмяВнешнегоОбъекта – Строка - имя внешнего объекта;
// ЭтоОтчет – Булево – Ложь (Внешняя обработка), Истина (Внешний отчет).
//
// Возвращаемое значение:
// – Строка - Имя внешней обработки или отчета.
//
Функция ПолучитьИмяВнешнегоОбъекта ( ИмяВнешнегоОбъекта , ЭтоОтчет = Ложь) Экспорт
Ссылка = Справочники . ДополнительныеОтчетыИОбработки . НайтиПоНаименованию ( ИмяВнешнегоОбъекта );
Если Ссылка = Неопределено Тогда
ВызватьИсключение "Внешний объект с именем не найден: " + ИмяВнешнегоОбъекта ;
КонецЕсли;
ДвоичныеДанные = Ссылка . ХранилищеОбработки . Получить ();
АдресХранилища = ПоместитьВоВременноеХранилище ( ДвоичныеДанные );
Возврат ?( ЭтоОтчет , ВнешниеОтчеты , ВнешниеОбработки ). Подключить ( АдресХранилища , , Ложь);
КонецФункции

// Получаем ссылку на элемент справочника ДополнительныеОтчетыИОбработки.
//
// Параметры:
// ИмяВнешнегоОбъекта – Строка - имя внешнего объекта;
//
//
// Возвращаемое значение:
// – СправочникСсылка.ДополнительныеОтчетыИОбработки - ссылка на элемент справочника ДополнительныеОтчетыИОбработки.
//
Функция ПолучитьСсылкуНаВнешнийОбъект ( ИмяВнешнегоОбъекта ) Экспорт
Возврат Справочники . ДополнительныеОтчетыИОбработки . НайтиПоНаименованию ( ИмяВнешнегоОбъекта );
КонецФункции

2. Далее, нужно загрузить общую внешнюю обработку в режиме предприятия. Код обработки:

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

Перем ИмяЭлемента , ТипЭлемента ;

Если НЕ ТипЗнч ( Параметры ) = Тип ( "Структура" ) Тогда
ВызватьИсключение "Параметры элемента формы не заданы!" ;
КонецЕсли;

Если НЕ Параметры . Свойство ( "Имя" , ИмяЭлемента ) Тогда
ВызватьИсключение "Имя элемента формы не задано!" ;
КонецЕсли;

Если НЕ Параметры . Свойство ( "ТипЭлемента" , ТипЭлемента ) Тогда
ВызватьИсключение "Тип элемента формы не задан!" ;
КонецЕсли;

Если НЕ Родитель = Неопределено Тогда
Если ТипЗнч ( Родитель ) <> Тип ( "ГруппаФормы" )
И ТипЗнч ( Родитель ) <> Тип ( "ТаблицаФормы" )
И ТипЗнч ( Родитель ) <> Тип ( "УправляемаяФорма" ) Тогда
ВызватьИсключение "Родитель должен иметь один из перечисленных типов: ГруппаФормы; ТаблицаФормы; УправляемаяФорма." ;
КонецЕсли;
КонецЕсли;

ЭлементФормы = ЭлементыФормы . Добавить ( ИмяЭлемента , ТипЭлемента , Родитель );
ЗаполнитьЗначенияСвойств ( ЭлементФормы , Параметры );
Возврат ЭлементФормы ;

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

Если НЕ ТипЗнч ( Параметры ) = Тип ( "Структура" ) Тогда
ВызватьИсключение "Параметры команды не заданы!" ;
КонецЕсли;

Если НЕ Параметры . Свойство ( "Имя" , ИмяЭлемента ) Тогда
ВызватьИсключение "Имя команды не задано!" ;
КонецЕсли;

Команда = Команды . Добавить ( ИмяЭлемента );
ЗаполнитьЗначенияСвойств ( Команда , Параметры );
Возврат Команда ;

Процедура ПереместитьЭлементВКоллекциюЭлементовФормы ( ЭлементыФормы , ИмяЭлемента , ИмяРодителя , МестоРасположения ) Экспорт
ЭлементыФормы . Переместить ( ЭлементыФормы . Найти ( ИмяЭлемента ), ЭлементыФормы . Найти ( ИмяРодителя ), ЭлементыФормы . Найти ( МестоРасположения ));
КонецПроцедуры

// Переопределяет обработчик события формы.
// Сохраняет штатный обработчик события внутри формы и устанавливает новый.
//
// Параметры:
// Форма – УправляемаяФорма – Управляемая форма;
// ИмяСобытияФормы – Строка – имя события;
// ПолноеИмяЭлементаФормы – Строка – полное имя элемента формы;
// НовоеДействие - Строка - имя процедуры обработчика;
// ОбработкаИсключений – Булево – сообщать о наличии старого обработчика.
//
Процедура ПодменитьДействиеУправляемоеПриложение ( Форма , ИмяСобытияФормы = "" , ПолноеИмяЭлементаФормы = "" , НовоеДействие , ОбработкаИсключений = Ложь) Экспорт

Объект = Форма ;
ИмяЭлементаФормы = "" ;
Если НЕ ПустаяСтрока ( ПолноеИмяЭлементаФормы ) Тогда

МассивФрагментов = РазобратьСтрокуВМассивПоРазделителю ( ПолноеИмяЭлементаФормы );
ИмяЭлементаФормы = МассивФрагментов [ 0 ];
Объект = Форма . Элементы . Найти ( ИмяЭлементаФормы );
Если Объект = Неопределено Тогда
ВызватьИсключение "Элемент формы: " + ИмяЭлементаФормы + " не найден!" ;
КонецЕсли;

Если МассивФрагментов . Количество () > 1 Тогда
ИмяЭлементаФормы = ИмяЭлементаФормы + МассивФрагментов [ 1 ];
Если ТипЗнч ( Объект ) = Тип ( "ТаблицаФормы" ) Тогда
Объект = Объект . Колонки [ МассивФрагментов [ 1 ]]. ЭлементУправления ;
ИначеЕсли ТипЗнч ( Объект ) = Тип ( "КоманднаяПанель" ) Тогда
Объект = Объект . Кнопки [ МассивФрагментов [ 1 ]];
Иначе
ВызватьИсключение "Ошибка на этапе получения элемента формы. Тип значения(" + ТипЗнч ( Объект ) + ")" ;
КонецЕсли;
КонецЕсли;
КонецЕсли;

СтарыеОбработчики = "OldHandlers" ;
МассивРеквизитов = Форма . ПолучитьРеквизиты ();
Для Каждого РеквизитФормы Из МассивРеквизитов Цикл
Если РеквизитФормы . Имя = СтарыеОбработчики Тогда
СтарыеОбработчики = Неопределено;
Прервать;
КонецЕсли;
КонецЦикла;

Если НЕ СтарыеОбработчики = Неопределено Тогда
МассивНовыхРеквизитов = Новый Массив ;
МассивНовыхРеквизитов . Добавить (Новый РеквизитФормы ( СтарыеОбработчики , Новый ОписаниеТипов ( "СписокЗначений" )));
Форма . ИзменитьРеквизиты ( МассивНовыхРеквизитов );
КонецЕсли;

Если ТипЗнч ( Объект ) = Тип ( "КнопкаФормы" ) Тогда
СтароеДействие = Объект . ИмяКоманды ;
Иначе
СтароеДействие = Объект . ПолучитьДействие ( ИмяСобытияФормы );
КонецЕсли;

Если ОбработкаИсключений И НЕ СтароеДействие = Неопределено Тогда
ВызватьИсключение "Конфликт обработчиков события """ + ИмяСобытияФормы + """ объекта """ + Строка ( Объект ) + """" ;
КонецЕсли;

Если ТипЗнч ( Объект ) = Тип ( "КнопкаФормы" ) Тогда
Объект . ИмяКоманды = НовоеДействие ;
Иначе
Объект . УстановитьДействие ( ИмяСобытияФормы , НовоеДействие );
КонецЕсли;

OldHandlers = Форма . OldHandlers ;
Если НЕ СтароеДействие = Неопределено И НЕ ПустаяСтрока ( СтароеДействие ) Тогда
OldHandlers . Добавить ( ИмяЭлементаФормы + "." + ИмяСобытияФормы , СтароеДействие );
КонецЕсли;
КонецПроцедуры

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

Объект = Форма ;
ИмяЭлементаФормы = "" ;
Если НЕ ПустаяСтрока ( ПолноеИмяЭлементаФормы ) Тогда

МассивФрагментов = РазобратьСтрокуВМассивПоРазделителю ( ПолноеИмяЭлементаФормы );
ИмяЭлементаФормы = МассивФрагментов [ 0 ];
Объект = Форма . Элементы . Найти ( ИмяЭлементаФормы );
Если Объект = Неопределено Тогда
ВызватьИсключение "Элемент формы: " + ИмяЭлементаФормы + " не найден!" ;
КонецЕсли;

Если МассивФрагментов . Количество () > 1 Тогда
ИмяЭлементаФормы = ИмяЭлементаФормы + МассивФрагментов [ 1 ];
Если ТипЗнч ( Объект ) = Тип ( "ТаблицаФормы" ) Тогда
Объект = Объект . Колонки [ МассивФрагментов [ 1 ]]. ЭлементУправления ;
ИначеЕсли ТипЗнч ( Объект ) = Тип ( "КоманднаяПанель" ) Тогда
Объект = Объект . Кнопки [ МассивФрагментов [ 1 ]];
Иначе
ВызватьИсключение "Ошибка на этапе получения элемента формы. Тип значения(" + ТипЗнч ( Объект ) + ")" ;
КонецЕсли;
КонецЕсли;

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

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

// Функция разбивает строку разделителем.
//
// Параметры:
// Строка - Строка - которую разбиваем;
// Разделитель - Строка - символ-разделитель.
//
// Возвращаемое значение:
// - Массив - содержащий фрагменты, на которые разбивает строку разделитель.
//
Функция РазобратьСтрокуВМассивПоРазделителю ( Строка , Разделитель = "." ) Экспорт
МассивСтрок = Новый Массив ;
СтрокаЗамены = СтрЗаменить ( Строка , Разделитель , Символы . ПС );
Для i = 1 По СтрЧислоСтрок ( СтрокаЗамены ) Цикл МассивСтрок . Добавить ( СтрПолучитьСтроку ( СтрокаЗамены , i )); КонецЦикла;
Возврат МассивСтрок ;
КонецФункции

На данном этапе, все уже готово для использования. Вот видео-пример использования механизма.

Читайте также: