1с событие при изменении пользовательских настроек
Здравствуйте. До последнего не хотел писать, так как шансов что помогут с таким бредом мало.
Сразу скажу - вопрос для меня чисто спортивного интереса. Задачу можно решить несколькими "некрасивыми" путями, и я их себе представляю.
Кратко.
Имеется подключаемая команда, результатом работы которой может служить изменение данных произвольного поля ввода на форме. Используется на нескольких формах различной сложности.
И все работает, кроме одного НО: обработчики событий элементов формы НЕ вызываются (естественно, так как мы работаем не интерактивно).
Часть обработчиков событий на формах являются "заграждающими" и провоцируют отказ, если пользователь вводит недопустимые данные, соостветственно, то, что при программном изменении данных не работают такие проверки, является ошибкой.
Как элегантно решить проблему в общем случае?
1) не хочется опираться на то что обработчики заранее известны, может быть в будущем их станет больше;
2) не хочется использовать Выполнить(), так как это небезопасный ограниченный для веб клиента метод;
3) не хочется сильно усложнять процесс стандартного создания обработчиков событий (чтобы приходилось танцевать с бубном воокруг мега-схемы).
Сразу уточню, не нужно про ИзменитьСтроку() и ЗакончитьРедактированиеСтроки(Ложь) . Не подходит. Это работает только для коллекций, для отдельных полей подобного нет, весь СП перерыл. И еще это не работает, если вход в редактирование из текущей ячейки не предусмотрен (например поле флажка). И ПриИзменении через него не работает. И еще есть там нюансы.
Гипотетически представим, что я могу по текущему полю сформировать список имен обработчиков, которые нужно выполнить в последовательности, как бы это интерактивно делала платформа. Пытался придумать что то через ВыполнитьОписаниеОповещения(), но все упирается в то, что таргетный метод ждет ровно 2 параметра, а в стандартных обработчиках их бывает то больше, то меньше, и вызывать напрямую так и не придумал как. Все концы упираются в то что придется писать дурацкий большой Если ИначеЕсли ИначеЕсли ИначеЕсли обработчик, с заранее известными именами обработчиков. Выносить код туда. Из стандартных вызывать этот же код.
Либо можно сделать через программное формирование строки выполнения и Выполнить(), но тогда не будет работать в веб-клиенте. Не катострофа, но неприятно тоже.
Есть элегантное решение? Может я все же чего то не вижу и можно сказать платформе, что я хочу "интерактивно" изменить данные?
Исторически сложилось так, что обработка изменения данных, связанных с реквизитами формы обрабатывалась в обработчиках событий этих реквизитов. Так было в 77, так до сих пор пишется код типовых конфигураций. Однако в 80 появился метод ПодключитьОбработчикИзмененияДанных, с помощью которого код изменений можно писать более прозрачно.
Рассмотрим простейший пример: пусть у документа есть реквизиты "Валюта","Курс","Кратность","Контрагент","Договор","Дата".
При изменении реквизита "Валюта" нужно установить курс и кратность валюты на дату "Дата".
При изменении реквизита "Контрагент" нужно установить в реквизит "Договор" основной договор контрагента.
Классическая схема написания обработчиков событий формы будет такая:
Однако у приведенной схемы есть недостаток.
Допустим, пользователь создал новый документ и в него подставился контрагент по умолчанию.
По идее мы должны смоделировать в этой ситуации интерактивный выбор контрагента, чтобы проставился договор или скопировать код процедуры Реквизит_Контрагент_ПриИзменении.
Это можно сделать так:
[1с]
Выполнить(""+ПолучитьДействие(ЭлементыФормы.Контрагент,"ПриИзменении")+"(ЭлементыФормы.Контрагент)");
[/1с]
Или так:
[1с]
Реквизит_Контрагент_ПриИзменении();
[/1с]
Но хочется большей универсальности чтобы не приходилось дублировать код.
Добиться этого можно другой схемой:
[1с]
Процедура ПриОткрытии()
…
//Назначаем всем данным формы обработчик ИзменениеДанных
Для Каждого Эл из ЭлементыФормы Цикл
Попытка
ПодключитьОбработчикИзмененияДанных(Эл.Данные, "ИзменениеДанных");
Исключение
КонецПопытки;
КонецЦикла;
Процедура ОтображениеДанных(Реквизит)
Если Реквизит="Договор" ИЛИ Реквизит="Контрагент" ИЛИ Реквизит="*" Тогда
ЭлементыФормы.кнВзаиморасчеты.Доступность=Пусто(Договор) Или Пусто(Контрагент);
КонецЕсли;
КонецПроцедуры
Процедура ИзменениеДанных(Реквизит)
Если Реквизит="Контрагент" Тогда
Договор=ПолучитьОсновнойДоговорПоКонтрагенту(Контрагент);
ИначеЕсли Реквизит="Валюта" Тогда
Курс=ПолучитьКурсПоВалюте(Валюта);
Кратность=ПолучитьКратностьПоВалюте(Валюта);
КонецЕсли;
ОтображениеДанных(Реквизит);
КонецПроцедуры
[/1с]
Конечно, было бы идеально, если подобные цепочки событий можно было описывать в модуле объекта, аналогично Delpy с их Property Get, Property Set (события по установке/чтению свойств объекта) но пока еще это не реализовано в 80.
А зачем нужен вызов с реквизитом "*"?
Этот вызов происходит при открытии формы и предназначен для правильного отображения статуса объектов.
Например, по задаче требуется, чтобы если был выбран договор и контрагент, то была доступна кнопка "кнВзаиморасчеты". Понятно, что контролировать доступность (отображение) этой кнопки нужно только при открытии формы и при изменении контрагента или договора. При открытии формы вызывается изменение данных всей формы (Реквизит "*"), в остальных случаях вызывается изменение каждого конкретного реквизита.
Кстати, заметим. В начале договор и контрагент пусты.
Пользователь вызывает договор. Пользователь вводит контрагента, вызывается событие ИзменениеДанных("Контрагент"), после чего проставляется договор и вызывается событие ИзменениеДанных("Договор"), после этого вызывается ОтображениеДанных("Договор"), которое делает кнопку "кнВзаиморасчеты" доступной и еще раз ОтображениеДанных("Контрагент"), которое оставляет кнопку доступной.
Как видно, при такой схеме обработки событий можно очень экономно писать код по обновлению отображения формы в зависимости от данных объекта, сравните с кодом, который вы обычно пишите в ОбновленииОтображения и почуствуйте разницу.
Однако в бочке меда есть ложка дегтя - все вышесказанное не работает для таблиц значения и табличных частей. Обработкик подключить можно, но он не вызывается при изменениях. Это очень печально и надеюсь, в будущих версиях платформы будет исправлено.
Механизм подписок на событие предназначен для назначения обработчика события для одного или нескольких объектов конфигурации платформы «1С:Предприятие». В статье рассматриваются несколько примеров применения данного механизма. Изучив статью, вы узнаете:
Применимость
В статье рассматривается платформа «1С:Предприятие» редакции 8.3. Представленная информация актуальна для текущих релизов платформы.
Подписки на события
В статье рассматриваются несколько примеров применения одного из вспомогательных объектов платформы «1С:Предприятие 8» – подписок на события.
Подписки на события позволяют размещать в общих модулях внешние обработчики, которые будут исполняться после выполнения определенного обработчика события в модуле объекта или модуле менеджера.
При этом не потребуется вносить изменения в модуль объекта или модуль менеджера. Таким образом, возникает возможность программного расширения модулей без их модификации – это очень полезный прием при изменении типовых решений.
Подписки на события описываются в ветке Общие окна объектов конфигурации (Рис.1).
- Выполняется обработчик события ПередЗаписью() в модуле объекта документа.
- Если в ходе выполнения обработчика параметр Отказ принимает значение Истина или вызывается исключение, то обработка события прерывается.
- Если на втором шаге обработка события не прерывалась, то выполняются внешние обработчики (подписки на события), определенные для события ПередЗаписью().
- Если в ходе выполнения внешнего обработчика параметр Отказ принимает значение Истина или вызывается исключение, то выполнение внешнего обработчика прерывается.
С помощью подписок на события можно организовать выполнение различных проверок, выполняющихся при записи объектов в базу данных.
Задача 1
Выполнить проверку дублирования наименования при записи элемента справочника “Контрагенты” – без модификации модулей самого справочника.
Флаг Клиент (обычное приложение) доступен, если в параметрах конфигуратора установлен режим редактирования Управляемое приложение и обычное приложение.
В ветке Общие окна объектов конфигурации создать новую подписку на событие. В палитре свойств ввести имя подписки ПроверкаНаименованияСправочника. В поле выбора Источник отметить тип данных СправочникОбъект.Контрагенты. В поле выбора Событие выбрать событие ПередЗаписью(). После отработки этого события будет срабатывать процедура обработки подписки на событие (Рис. 2).
Листинг процедуры ПроверкаНаименованияСправочникаПередЗаписью()
На практике может встретиться задача выполнения движений по дополнительным регистрам при проведении документов в типовых конфигурациях. Создание дополнительных регистров позволяет избежать модификации существующих регистров и при этом получить возможность дополнительной обработки данных при проведении типовых документов.
Задача 2
Создать оборотный регистр накопления “Выбытия денежных средств” и обеспечить формирование движений по этому регистру при проведении документа “Расходный кассовый ордер”, используя механизм подписок на события.
Создать новый оборотный регистр с именем ВыбытияДенежныхСредств. Выбрать регистратор “Расходный кассовый ордер”. Добавить измерения регистра:
Касса, тип: СправочникСсылка.Кассы;
Статья, тип: СправочникСсылка.СтатьиДвиженияДенежныхСредств.
Создать ресурс регистра:
В документе “Расходный кассовый ордер” создать реквизит СтатьяДвижения с типом данных СправочникСсылка.СтатьиДвиженияДенежныхСредств.
Создать новую подписку на событие:
Имя – ДвиженияПоВыбытиюДенежныхСредств;
Источник – ДокументОбъект.РКО;
Событие – ОбработкаПроведения.
В общем модуле ОбработчикиПодписокНаСобытия создать обработчик ДвиженияПоВыбытиюДенежныхСредствОбработкаПроведения(). В обработчике осуществляется обход табличной части документа “Расходный кассовый ордер” и формируются движения в регистре накопления ВыбытияДенежныхСредств.
Листинг процедуры ДвиженияПоВыбытиюДенежныхСредствОбработкаПроведения()
В типовых конфигурациях может возникнуть необходимость доработки основной формы некоторого объекта, например документа. Эту задачу можно решить с помощью подписок на события. При этом создается копия основной формы документа. В новую форму вносятся необходимые изменения. С помощью механизма подписок на события обеспечивается открытие новой формы вместо основной формы. При этом основная форма, находящаяся на поддержке, остается без изменения.
Задача 3
Обеспечить подмену основной формы документа “Расходный кассовый ордер”.
Создать новую форму документа “Расходный кассовый ордер” с именем ФормаДокументаКлиентская. Внести в форму произвольные изменения, например, поменять порядок элементов управления. Для вызова этой формы необходимо использовать подписку на событие ОбработкаПолученияФормы() в модуле менеджера документа “Расходный кассовый ордер”.
Создать новую подписку на событие:
Имя – ОсновнаяФормаРКО;
Источник – ДокументМенеджер.РКО;
Событие – ОбработкаПолученияФормы.
В общем модуле ОбработчикиПодписокНаСобытия создать обработчик ОсновнаяФормаРКООбработкаПолученияФормы(). В обработчик в качестве параметра ВыбраннаяФорма передается имя открываемой формы.
Параметр СтандартнаяОбработка устанавливается в значении Ложь для отключения открытия основной формы.
Листинг процедуры ОсновнаяФормаРКООбработкаПолученияФормы()
Таким образом, подписки на события предоставляют возможность добавления нового функционала, не изменяя существующие модули объектов. К недостаткам подписок на события можно отнести:
- Увеличение сложности алгоритмов.
- Подписаться можно только на события объектов и менеджеров объектов.
Если необходимо модифицировать какое-либо событие формы, то механизм подписок на события не доступен. В этом случае, необходимо вносить изменения в саму форму или копировать форму и вносить изменения в новый объект.
Хочу в форме настроек отчета СКД, созданной конструктором, поймать изменение настроек. Пишу Процедура ПриОткрытии событие ПриИзмененииКомпоновщикНастроек срабатывает только тогда, когда где-то явно вызывается что-то типа КомпоновщикНастроек.ЗагрузитьНастройки(СериализаторXDTO.ПрочитатьXML(ЧтениеXML)); а хочется, чтобы вызывался и при интерактивном изменении.
вместо апа: если таб.полю "Структура", связанному с КомпоновщикНастроек.Настройки, свойство ИзменяетДанные в Истина, то даже при каких-либо изменениях в других таб.полях на форме (которые связаны с ТП "Структура"), у формы ставится признак модифицированности. Но обработчик не вызывается, хоть тресни.
не пойдет. во-первых, тогда оно вызывается и при первом заполнении, во-вторых, не отлавливаются изменения в других ТП (отборы, сортировки, параметры и т.п.)
почему не подходит? - первый вызов легко игнорировать (флажок например перед открытием поднимать) - можно подключить и к другим ТП на форме (если вручную тяжело можно что-то динамического обработчика замутить)
Так тоже не работает, но что интересно ПодключитьОбработчикИзмененияДанных("ЭлементыФормы.КомпоновщикНастроек.Настройки", "ПриИзмененииКомпоновщикНастроек", Истина); работает, но очень избирательно, т.е. как мигалка на скорой помощи, то работает, то не работает. ПодключитьОбработчикИзмененияДанных("КомпоновщикНастроек.Настройки", "ПриИзмененииКомпоновщикНастроек", Истина); срабатывает при закрытии стандартной формы настройки верхним правым крестиком, но не срабатывает при нажатии кнопки "ОК" .
нужно отследить, что пользователь поменял настройки и предложить их сохранить более того, если открыть форму настройки программно через ПолучитьФормуНастроек(,ЭтаФорма).Открыть, то обработчик не срабатывает вообще
Используй форму "ФормаНастройкиСтруктурыОтчета", почти во всех типовых есть. Сразу стадо зайцев перестреляешь.
Решал схожую задачу, пошел по пути показа юзеру не штатной формы настроек СКД, а общей формы (идет в комплекте конфы Шаблон типового отчета - в последнем ЗиКе встроена она же).
пока остановился на таком варианте: у ТП "Структура" поставил галку ИзменяетДанные, а в нужных местах анализирую Модифицированность и сбрасываю по необходимости
может дать пользователю свободу выбора? А то это грёбаный фашизм какой-то: шаг влево, шаг вправо - сохраняй
и к ней еще десяток модулей, а потом разбираться, чего же там умельцы с Селезневки надумали? не, пасиб
На нашем сайте профессионалы делятся своим опытом и разработками. Вы получаете доступ к уникальному и самому полному хранилищу материалов для 1С, состоящему из более 30 000 отчетов, обработок, видео и т.д.
Рейтинг: 1233
Что, если нужно по расписанию делать что-то, зависящее от кучи параметров? Например, формировать индивидуальные прайсы и отправлять их (или сохранять на ftp), предварительно записав в excel. Технология будет полезна тем, кто уже имеет готовую сложную обработку, которую нужно заставить выполняться по расписанию.
Суть заключается в использовании стандартного механизма рассылки отчётов. Внимание , этот механизм есть не во всех конфигурациях, например его нет в БП.
Переделка обработки состоит из трёх обязательных и одного необязательного этапа (в любом порядке)
Хоть я и буду их подробно описывать (и будет много букв), но делается всё это за 5 минут!
1. Превращаем обработку в отчёт (т.к. стандартный механизм работает исключительно с отчетами), делаем его внешним в соответствии с БСП.
2. Добавляем обработке пустую схему СКД с параметрами, соответствующими реквизитам обработки.
3. При компоновке результата превращаем параметры СКД в реквизиты и выполняем алгоритм обработки.
4. Если нужно унифицировать выполнение по расписанию и ручной запуск обработки, то дописываем в форме обработки изменение параметров СКД при изменении реквизитов формы.
Разберём простой пример. Пусть у нас есть обработка с двумя реквизитами "Каталог" и "ИмяФайла", которая сохраняет файл с текстом " ПРЕВЕД МЕДВЕД". Обработка очень сложная, давно используется в компании и зарекомендовала себя. Но вот возникла необходимость запускать её по расписанию с различными параметрами.
1. Конвертируем обработку в отчёт
В разблокированной конфигурации (можно в копии базы, т.к. эта манипуляция нам нужна только чтобы получить файл erf)
а) в дереве метаданных встаём на любой отчёт и нажимаем пкм -> "Вставить внешнюю обработку, отчёт" , выбираем наш файл epf
б) встаём на вновь добавленный отчет и нажимаем пкм -> "Сохранить как внешнюю обработку, отчёт" , выбираем имя файла, получаем файл erf
в) открываем новорожденный отчёт, добавляем ему форму (не делаем её основной) но ставим галочку "использовать СКД".
Это будет пустая форма, без её создания СКД у меня не заработало.
г) Ну и добавляем в модуль текст, отвечающий за "внешность" нашего отчёта
2. Добавляем схему СКД с параметрами, соответствующими реквизитам обработки
а) Добавляем параметры в схему СКД
б) включаем их в пользовательские настройки
3. При компоновке результата превращаем параметры СКД в реквизиты
В модуль отчёта добавляем процедуру ПриКомпоновкеРезультата, в неё добавляем немножко кода по преобразованию параметров СКД в реквизиты и сам алгоритм обработки (в неизменном виде)
Да, преобразование реквизитов тут приведено для довольно простого случая, но без труда можно доработать алгоритм для списков значений и т.п. Например, у меня СКД хранится (в виде нескольких списков значений) и преобразовывается целая табличная часть.
Обязательные действия выполнены , можно подключить нашу обработку как внешнюю.
Далее зайти в Органайзер->рассылки отчётов, создать новую рассылку, заполнить обязательные поля, выбрать внешний отчёт (выбирается специальной кнопкой)
Заполняем параметры, настраиваем расписание и наслаждаемся. Проверить выполнение можно кнопкой "Выполнить сейчас"
4. Изменение параметров скд при изменении реквизитов формы (тот самый необязательный пункт)
Для наглядности добавим в форму пользовательские настройки (чтобы видеть, что они меняются при изменении реквизитов)
Заполним их при создании формы
и всем элементам формы добавим событие ПриИзменииЭлементаНаКлиенте, в котором и будем изменять настройки СКД
Теперь можно убедиться, что при изменении реквизитов меняются настройки СКД
Мы рассмотрели очень простой пример, но метод можно использовать и для сложных обработок. Например, зная принцип, адаптация этого многофункционального прайса к рассылке занимает 15 минут. А настроек у неё море, да и сам алгоритм сложняцкий.
Возможно, есть и более простые способы, или этот уже был озвучен, если так, прошу в комментарии.
На всякий случай прикладываю обработку - пример, превращённую в рассылаемый отчёт.
Читайте также: