gifts2017

Программная доработка форм, настраиваемая в режиме Предприятия

Опубликовал Алексей Юданов (Alex_YAM) в раздел Программирование - Практика программирования

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

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

Однако во время обновления могут поменяться имена элементов формы, на которые завязаны наши программные доработки. В таком случае форма просто не откроется, и придется выводить emergency релиз. Имена элементов формы в типовых конфигурациях меняются регулярно, отследить это очень трудно. Собственно, доработка заключается в том, чтобы хранить в регистре сведений настройки доработок форм. 

Создаем регистр сведений ДоработкиФорм 

Типы данных:

ИдентификаторОбъектаМетаданных - справочник ИдентификаторыОбъектовМетаданных (если конфигурация не на основе БСП и такого справочника нет, то можно взять тип Строка, будет заполнятся так: Строка(ТипОбъекта)).

Используется, Видимость - Булево 

ИмяФормы, ИмяЭлемента - Строка 128

Все остальные ресурсы - Строка 256

В дорабатываемой форме в процедуре ПриСозданииНаСервере добавляем одну строку:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	//...
	
	ДоработкиФорм.ИзменитьФорму(ЭтаФорма);
	 
КонецПроцедуры

Эта единственная строка кода, которую нужно будет поддерживать при обновлении.

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

Для БП 3.0 и в целом конфигураций основанных на БСП:

УправлениеПечатью.ПриСозданииНаСервере 

или ДополнительныеОтчетыИОбработки.ПриСозданииНаСервере

Для УТ 10, КА 1, УПП 1: МеханизмНумерацииОбъектов.УстановитьДоступностьПоляВводаНомера - вызывается при открытии формы практически всех объектов.

Также можно обрабатывать одно событие у программно добавленных элементов вообще без изменений: 
Для УТ 10, КА 1, УПП 1: практически в любой форме есть метод ДействияФормыРедактироватьНомер(Кнопка), из него идет вызов МеханизмНумерацииОбъектов.ИзменениеВозможностиРедактированияНомера; указываем его в качестве обработчика нужного события, далее в общем модуле делаем что требуется 
БП 3.0: Подключаемый_ВыполнитьКомандуПечати, остальное аналогично 

(thnx Роман Сюзев (sorb))

Добавляем процедуру в серверный общий модуль (у меня называется ДоработкиФорм):

// Изменение формы при создании на сервере
//
// Параметры:
//  Форма  - УправляемаяФорма - изменяемая форма объекта
//
Процедура ИзменитьФорму(ЭтаФорма) Экспорт
	
	ОбъектМетаданныхФорма = Метаданные.НайтиПоПолномуИмени(ЭтаФорма.ИмяФормы);
	ОбъектМетаданных = ОбъектМетаданныхФорма.Родитель();
	ИдентификаторОбъектаМетаданных = Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторОбъектаМетаданных(ОбъектМетаданных);
	Подстроки = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ЭтаФорма.ИмяФормы, ".");
	ИмяФормы = Подстроки[Подстроки.ВГраница()];
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ДоработкиФорм.ИмяЭлемента,
	|	ДоработкиФорм.Используется,
	|	ДоработкиФорм.Видимость,
	|	ДоработкиФорм.ТипЭлемента,
	|	ДоработкиФорм.Родитель,
	|	ДоработкиФорм.ВидПоляФормы,
	|	ДоработкиФорм.ПутьКДанным,
	|	ДоработкиФорм.Заголовок,
	|	ДоработкиФорм.ИмяКоманды,
	|	ДоработкиФорм.ИмяТабличнойЧасти,
	|	ДоработкиФорм.ИмяСобытия,
	|	ДоработкиФорм.Действие,
	|	ДоработкиФорм.ПередЭлементом
	|ИЗ
	|	РегистрСведений.ДоработкиФорм КАК ДоработкиФорм
	|ГДЕ
	|	ДоработкиФорм.ИдентификаторОбъектаМетаданных = &ИдентификаторОбъектаМетаданных
	|	И ДоработкиФорм.ИмяФормы = &ИмяФормы
	|	И ДоработкиФорм.Используется";
	
	Запрос.УстановитьПараметр("ИдентификаторОбъектаМетаданных", ИдентификаторОбъектаМетаданных);
	Запрос.УстановитьПараметр("ИмяФормы", ИмяФормы);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		Если ЗначениеЗаполнено(Выборка.Родитель) Тогда
			
			Если ЭтаФорма.Элементы.Найти(Выборка.Родитель) = Неопределено Тогда
				ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не найден элемент формы " + Выборка.Родитель);
				Продолжить;	
			КонецЕсли; 
			
			Родитель = ЭтаФорма.Элементы[Выборка.Родитель]; 
			
		Иначе
			
			Родитель = ЭтаФорма;
			
		КонецЕсли; 
		
		Если ЗначениеЗаполнено(Выборка.ИмяКоманды) Тогда
			
			Команда = ЭтаФорма.Команды.Найти(Выборка.ИмяКоманды);
			
			Если Команда = Неопределено Тогда
				
				Команда = ЭтаФорма.Команды.Добавить(Выборка.ИмяКоманды);
				Команда.Действие = Выборка.ИмяКоманды;
				Команда.Заголовок = Выборка.Заголовок;
				
				Элемент = ЭтаФорма.Элементы.Добавить(Выборка.ИмяЭлемента, Тип(Выборка.ТипЭлемента), Родитель);
				Элемент.ИмяКоманды = Выборка.ИмяКоманды;
				Элемент.Заголовок = Выборка.Заголовок;
				
			Иначе
				
				Команда.Действие = Выборка.Действие;
				
			КонецЕсли; 
			
		ИначеЕсли ЗначениеЗаполнено(Выборка.ИмяТабличнойЧасти) Тогда
			
			ЭлементТаблица = ЭтаФорма.Элементы.Добавить(Выборка.ИмяЭлемента, Тип(Выборка.ТипЭлемента), Родитель);
			ЭлементТаблица.ПутьКДанным = Выборка.ПутьКДанным;
			ЭлементТаблица.Отображение = ОтображениеТаблицы.Список;
			
			Колонки = ОбъектМетаданных.ТабличныеЧасти[Выборка.ИмяТабличнойЧасти].Реквизиты;
			
			Для каждого Колонка Из Колонки Цикл
				
				ЭлементКолонка = ЭтаФорма.Элементы.Добавить(Выборка.ИмяТабличнойЧасти + Колонка.Имя, Тип("ПолеФормы"), ЭлементТаблица);
				ЭлементКолонка.Вид = ВидПоляФормы.ПолеВвода;
				ЭлементКолонка.ПутьКДанным = "Объект." + Выборка.ИмяТабличнойЧасти + "." + Колонка.Имя;
				
			КонецЦикла; 
			
		Иначе                  
			
			Элемент = ЭтаФорма.Элементы.Найти(Выборка.ИмяЭлемента);
			
			Если Элемент = Неопределено Тогда
			
				Элемент = ЭтаФорма.Элементы.Добавить(Выборка.ИмяЭлемента, Тип(Выборка.ТипЭлемента), Родитель);
				Элемент.Вид = ВидПоляФормы[Выборка.ВидПоляФормы];
				Элемент.ПутьКДанным = Выборка.ПутьКДанным;
				Элемент.Заголовок = Выборка.Заголовок;
				
			КонецЕсли; 
			
			Элемент.Видимость = Выборка.Видимость;
			
			Если ЗначениеЗаполнено(Выборка.ИмяСобытия) Тогда
				Элемент.УстановитьДействие(Выборка.ИмяСобытия, Выборка.Действие);
			КонецЕсли;
			
			Если ЗначениеЗаполнено(Выборка.ПередЭлементом) Тогда
				ЭтаФорма.Элементы.Переместить(Элемент, Родитель, ЭтаФорма.Элементы.Найти(Выборка.ПередЭлементом));
			КонецЕсли; 
				
		КонецЕсли; 
		
	КонецЦикла;
	
КонецПроцедуры 

Что позволяет такая доработка:

1) Добавление/изменение элемента формы.

2) Добавление/изменение табличной части на форме.

3) Добавление/переопределение команды формы.

При этом форма остается полностью типовой, кроме одной строки в процедуре ПриСозданииНаСервере. 

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

Примеры.

1) Добавить свой реквизит формы с обработчиком ПриИзменении

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

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

ВидПоляФормы - системное перечисление (ПолеВвода, ПолеФлажка и т.п.)

Действие - имя команды  (в модуле формы должна быть процедура МойОбработчикКоманды(Команда)). Можно переопределить существующий типовой обработчик.

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

2) Добавить свою табличную часть

ИдентификаторОбъектаМетаданных Справочник1 (Справочник)
ИмяФормы ФормаЭлемента
ИмяЭлемента "МояТЧ"
Используется Истина
Видимость Истина
ТипЭлемента "ТаблицаФормы"
Родитель
ВидПоляФормы
ПутьКДанным "Объект.НоваяТабличнаяЧасть"
Заголовок
ИмяКоманды
ИмяТабличнойЧасти "НоваяТабличнаяЧасть"
ИмяСобытия
Действие
ПередЭлементом

3)Добавить свою кнопку

ИдентификаторОбъектаМетаданных Справочник1 (Справочник)
ИмяФормы ФормаЭлемента
ИмяЭлемента "НоваяКоманда"
Используется Истина
Видимость Истина
ТипЭлемента "КнопкаФормы"
Родитель
ВидПоляФормы
ПутьКДанным
Заголовок "Моя команда"
ИмяКоманды "МойОбработчикКоманды"
ИмяТабличнойЧасти
ИмяСобытия
Действие "МойОбработчикКоманды"
ПередЭлементом

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

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Сергей Соловьев (sergey512) 09.11.16 17:05
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

//...

ДоработкиФорм.ИзменитьФорму(ЭтаФорма, Тип("СправочникСсылка.Справочник1"));

КонецПроцедуры
Эта единственная строка кода, которую нужно будет поддерживать при обновлении.


Не согласен, что это будет единственная строка за которой нужно будет следить.
Команды, обработчики элементов формы - за этим кодом кто будет следить?
Если добавить одну универсальную команду и один обработчик, а сам код команд и обработчиков хранить по аналогии в регистре сведений, и выполнять его посредством оператора "Выполнить". В таком случае придется следить за одной командой, одним обработчиком и строкой указанной выше. Но не стоит забывать, что режиме запуска веб-клиент оператор "Выполнить" не поддерживается.
2. Алексей Юданов (Alex_YAM) 09.11.16 17:44
(1) sergey512,

При обновлении добавленные обработчики команд никуда не пропадут, если, конечно, их не пометить вручную на удаление. При этом естественно в имена процедур своих обработчиков нужно добавлять какой-нибудь специальный префикс, чтобы не совпасть с типовой.
А если Вы имеете ввиду код внутри обработчиков - то , да, его нужно поддерживать, как и любой другой собственный код в конфигурации.
В целом, с обработчиками команд нужно быть осторожнее, потому что сейчас разработчики типовых конфигураций любят переопределять их "на лету", например при изменении вида операции.
По поводу Выполнить() - на мой взгляд, хранить код в базе данных - это всегда худший вариант из всех возможных.
Сурикат; +1 Ответить
3. Виталий Попов (Сурикат) 10.11.16 15:56
В последних типовых конфигурация такие функции уже встроены.
Все обработчики есть в модуле МодификацияКонфигурацийПереопределяемый. Принцип абсолютно такой же, только без регистра сведений, который на мой взгляд усложняет схему, т.к. при обновлении сложно будет отследить ошибки.
И у вас второй параметр лишний, т.к. по имени формы понятно какая форма к нам попала
4. Алексей Юданов (Alex_YAM) 10.11.16 17:53
(3) Сурикат,

У меня в Бухгалтерии 3.0 такого модуля нет.
Весь смысл в регистре сведений. Потому что можно исправить ошибку без конфигуратора.
Как Вы отследите то, что в типовой поменяли имя группы элементов с ГруппаЛеваяКолонка на ГруппаКолонкаЛевая ? Конфигуратор никаких ошибок не увидит. Проверять все используемые в коде элементы по очереди? Если доработок много, то это очень долго.

у вас второй параметр лишний, т.к. по имени формы понятно какая форма к нам попала

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


5. Виталий Попов (Сурикат) 10.11.16 22:42
(4) Alex_YAM,
проверьте события при создании на сервере, может как-то по-другому называется =)
Я меняю программно. Тем более есть обработка по декомпозиции управляемых форм, которая формирует код создания новых элементов. Все-таки для обработки новых метаданных я сторонник программного решения, не завязанного на какие-то таблицы БД.
И если ваши доработки выполняют функции модификации данных, то их полностью можно заменить на "Внешние обработки заполнения"
6. Артем Иванов (artemusII) 14.11.16 21:16
7. tregard Trugada (tregard) 16.11.16 09:39
На один элемент формы может быть несколько обработчиков событий. Правильней создавать два регистра - один на создание элементов, а второй для назначения обработчиков.
К тому же у элементов формы намного больше свойств, которые потребуется изменять. Сходу вижу, что данная структура регистра не достаточно для отрисовки страниц и групп. Получается все возможные свойства элементов форм должны быть представлены ресурсами регистра. Или сделать какой-то ресурс с типом ХранилищеЗначений и там это как-то хранить.

Для изменения формы всегда использую общий модуль МодификацияКонфигурацийПереопределяемый. В БП раньше его точно не было, и выходил из ситуации используя УправлениеПечатью. Там тоже какой-то переопределяемый модуль или процедура есть, который вызывался при создании формы документов.
Хотя идея интересная.
8. Роман Сюзев (sorb) 16.11.16 12:59
Чтобы вообще не трогать модули форм, достаточно в конфигурации найти процедуру общего модуля, вызываемую из всех (или хотя бы из большинства) форм.
Примеры:
УТ 10, КА 1, УПП 1: МеханизмНумерацииОбъектов.УстановитьДоступностьПоляВводаНомера - вызывается при открытии формы практически всех объектов.
БП 3.0 (точнее практически любая конфигурация на БСП): ДополнительныеОтчетыИОбработки.ПриСозданииНаСервере - есть практически везде, требует включения ФО доп. отчетов и обработок.

Также можно обрабатывать одно событие у программно добавленных элементов вообще без изменений:
Для УТ 10, КА 1, УПП 1: практически в любой форме есть метод ДействияФормыРедактироватьНомер(Кнопка), из него идет вызов МеханизмНумерацииОбъектов.ИзменениеВозможностиРедактированияНомера; указываем его в качестве обработчика нужного события, далее в общем модуле делаем что требуется
БП 3.0: Подключаемый_ВыполнитьКомандуПечати, остальное аналогично

В итоге если очень припекло, то в 90% случаев вообще ничего не меняем,кроме одного-двух общих модулей.
9. Алексей Юданов (Alex_YAM) 16.11.16 15:29
(7) tregard,

Да, не получится создавать группы формы, страницы и переопределять несколько обработчиков. Я добавлял ресурсы по мере необходимости, надобности в других свойствах не было. Обычно либо требуется несколько небольших изменений на форме, либо проще сделать свою.
Можно просто создать справочник НастройкиЭлементовФормы в который включить все нужные свойства, он будет единственным ресурсом.
10. Алексей Юданов (Alex_YAM) 16.11.16 15:33
(7) tregard,
(8) sorb,

Да, в БП 3.0 в любой форме документа есть:
УправлениеПечатью.ПриСозданииНаСервере
ДополнительныеОтчетыИОбработки.ПриСозданииНаСервере
ВерсионированиеОбъектов.ПриСозданииНаСервере

Но как на счет форм Справочников? Обработок? ПВХ? Плана счетов? Регистров? и т.п.
11. Роман Сюзев (sorb) 16.11.16 19:58
(10) Alex_YAM, на счет форм справочников все действительно, проверьте. ПВХ, планы счетов и регистры - за 15 лет так и не понадобилось, поэтому решение не искал. Для остального в случае УФ разумней использовать расширения, и только для ОФ иногда приходится трогать формы. Это имхо, но основанное на личном опыте.
Я специально отметил, что "в 90% случаев вообще ничего не меняем,кроме одного-двух общих модулей", то есть крайне редко, в совсем исключительных случаях, форму трогать приходится. Но это не значит, что стоит их трогать без необходимости, верно?
12. Алексей Юданов (Alex_YAM) 17.11.16 21:05
(7) tregard,
(8) sorb,
(3) Сурикат,

Спасибо за комментарии.
Убрал лишний параметр, дописал про общие модули, действительно их использовать намного удобнее.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа