gifts2017

Сохранение произвольных значений реквизитов объекта в реквизите формы

Опубликовал Andrey Smirnov (dusha0020) в раздел Программирование - Практика программирования

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

Хотел написать много красивых и умных слов, но вместо этого решил перейти сразу к делу. По пунктам и коротко:

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

2. Подход к реализации:  Сохранение всех данных в реквизите управляемой формы типа "Список значений". Это удобно тем, что во-первых используется стандартное хранилище и стандартный механизм сохранения, а во-вторых из-за того, что процедуры обработки сохранения и восстановления настроек серверные и мы минимизируем клиентское взаимодействие со сложными типами данных, поддерживаемых не всеми клиентами, и легко добиваемся мультиклиентности.

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

4. Конкретно инструкция:

а) Создаем для управляемой формы реквизит типа СписокЗначений с названием (в моем примере): "СохраняемыеСвойстваОбъекта".

б) Создаем кнопку с процедурой или команду для вызова процедуры "РедактироватьСписокСохраняемыхРеквизитов". В примере это команда формы "РедактироватьСохраняемыеРеквизиты". Размещаем кнопочку для вызова на форме или (как в примере) вызов команды из меню.

в) Инициируем стандартные обработчики событий формы "ПриСохраненииДанныхВНастройкахНаСервере" и "ПриЗагрузкеДанныхИзНастроекНаСервере"

пример

г) После всего вышеизложенного в модуль формы добавляем 2 процедуры: "РедактироватьСписокСохраняемыхРеквизитов" и "ОбработатьСохраняемыеРеквизитыОбъекта" и настраиваем вызов процедуры "ОбработатьСохраняемыеРеквизитыОбъекта" из стандартных обработчиков, а процедуры "РедактироватьСписокСохраняемыхРеквизитов" из специальной команды/процедуры связанной с элементом управления или пунктом меню формы. В качестве аргумента СохраняемыйСписокРеквизитФормы передается название списка значений с сохраняемыми настройками (в примере это "СохраняемыеСвойстваОбъекта", в общем случае - как назовете реквизит формы, так и передаете при вызове)

д) собственно пример текста модуля с командами и процедурами:

&НаСервере
Процедура ОбработатьСохраняемыеРеквизитыОбъекта(НастройкиСохранения, СохраняемыйСписокРеквизитФормы, Сохранить)
	СписокТиповДанныхФормы = Новый СписокЗначений;
	СписокТиповДанныхФормы.Добавить(Тип("ДанныеФормыСтруктура"),"Структура");
	СписокТиповДанныхФормы.Добавить(Тип("ДанныеФормыКоллекция"),"ТаблицаЗначений");
	СписокТиповДанныхФормы.Добавить(Тип("ДанныеФормыСтруктураСКоллекцией"),"СписокЗначений");
	СписокТиповДанныхФормы.Добавить(Тип("ДанныеФормыДерево"), "ДеревоЗначений");
	СтарыйСписок = ЭтаФорма[СохраняемыйСписокРеквизитФормы];
	СписокРеквизитов = ?(СтарыйСписок.Количество()>0, СтарыйСписок[0].Значение, Новый СписокЗначений);
	Если Сохранить Тогда
		НовыйСписок = Новый СписокЗначений;
		НовыйСписок.Вставить(0, СписокРеквизитов);
		Для Каждого СохраняемыйРеквизит Из СписокРеквизитов Цикл
			Если СохраняемыйРеквизит.Пометка Тогда
				ТипДанныхРеквизита = СписокТиповДанныхФормы.НайтиПоЗначению(ТипЗнч(Объект[СохраняемыйРеквизит.Значение]));
				Если НЕ ТипДанныхРеквизита = Неопределено Тогда
					СохраняемоеЗначение = ДанныеФормыВЗначение(Объект[СохраняемыйРеквизит.Значение], Тип(ТипДанныхРеквизита.Представление));
				Иначе
					СохраняемоеЗначение = Объект[СохраняемыйРеквизит.Значение];
				КонецЕсли;
				НовыйСписок.Добавить(СохраняемоеЗначение, СохраняемыйРеквизит.Значение);
			КонецЕсли;
		КонецЦикла;
		НастройкиСохранения[СохраняемыйСписокРеквизитФормы] = НовыйСписок;
	Иначе
		Для Каждого ЭлементСтарогоСписка Из СтарыйСписок Цикл
			Для Каждого Реквизит Из СписокРеквизитов Цикл
				Если Реквизит.Значение = ЭлементСтарогоСписка.Представление  Тогда
					Если НЕ СписокТиповДанныхФормы.НайтиПоЗначению(ТипЗнч(Объект[ЭлементСтарогоСписка.Представление])) = Неопределено Тогда
						ЗначениеВДанныеФормы(ЭлементСтарогоСписка.Значение, Объект[ЭлементСтарогоСписка.Представление]);
						ЭлементСтарогоСписка.Значение = Объект[ЭлементСтарогоСписка.Представление];
					Иначе
						Объект[ЭлементСтарогоСписка.Представление] = ЭлементСтарогоСписка.Значение;
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла; 
	КонецЕсли;	
КонецПроцедуры

&НаКлиенте
Процедура РедактироватьСписокСохраняемыхРеквизитов(СохраняемыйСписокРеквизитФормы)
    СтарыйСписок = ЭтаФорма[СохраняемыйСписокРеквизитФормы];
	СтарыйСписок = ?(СтарыйСписок.Количество()>0, СтарыйСписок[0].Значение, Новый СписокЗначений);
	Если Ложь Тогда
		СтарыйСписок = Новый СписокЗначений;
	КонецЕсли;
	сп = Новый СписокЗначений;
	Для Каждого РеквизитОбъекта Из ЭтаФорма.Элементы Цикл
		
		Попытка // Попытку можно опустить если не будет использоваться веб клиент.
			Если Объект.Свойство(РеквизитОбъекта.Имя) Тогда
				сп.Добавить(РеквизитОбъекта.Имя, РеквизитОбъекта.Заголовок);
				ЭлементСтарогоСписка = СтарыйСписок.НайтиПоЗначению(РеквизитОбъекта.Имя);
				Если НЕ ЭлементСтарогоСписка = Неопределено Тогда
					сп.НайтиПоЗначению(РеквизитОбъекта.Имя).Пометка = ЭлементСтарогоСписка.Пометка;
				КонецЕсли;
			КонецЕсли;
			
		Исключение
		КонецПопытки;
	
	КонецЦикла;
	сп.ОтметитьЭлементы("Выбор сохраняемых реквизитов объекта");
	ЭтаФорма[СохраняемыйСписокРеквизитФормы].Вставить(0, сп);
КонецПроцедуры

&НаСервере
Процедура ПриСохраненииДанныхВНастройкахНаСервере(Настройки)
	// Вставить содержимое обработчика.
	ОбработатьСохраняемыеРеквизитыОбъекта(Настройки, "СохраняемыеСвойстваОбъекта", Истина);
КонецПроцедуры

&НаСервере
Процедура ПриЗагрузкеДанныхИзНастроекНаСервере(Настройки)
	// Вставить содержимое обработчика.
	ОбработатьСохраняемыеРеквизитыОбъекта(Настройки, "СохраняемыеСвойстваОбъекта", Ложь);	
КонецПроцедуры

&НаКлиенте
Процедура РедактироватьСохраняемыеРеквизиты(Команда)
	// Вставить содержимое обработчика.
	РедактироватьСписокСохраняемыхРеквизитов("СохраняемыеСвойстваОбъекта");
КонецПроцедуры

Ну вот собственно и почти все. Осталось сказать несколько слов о некрасивой Попытке и о тестировании метода. Не случайно в текст метода была введена Попытка и не случайно стоит коммент о том, что она нужна только для web клиентов. По ходу тестов под разными клиентами я убедился в полной работоспособности метода для управляемых форм на толстых и тонкуих клиентах, а вот с web пришлось попотеть. Дело в том, что процедура перебирает все элементы формы для поиска данных, но шутка в том, что web клиент не отрисовывает все элементы формы с полным набором свойств в том числе и со свойством Имя. Такая вот фитча (или баг:) у меня наблюдалась в IE. Побеждать то, что обусловлено скорее даже не платформой, а способностями браузеров я не стал, хотя теоретически можно было бы разложить форму на винтики в серверной процедуре и передать web клиенту списком только нужные реквизиты. Это, конечно, избавило бы код от Попытки, но, думаю, не добавило бы в итоге ни простоты ни красоты. Так что я смирился, а Вы как хотите - используйте, дописывайте, переписывайте, критикуйте, ругайте, предлагайте что-то лучшее и т.д. В комментах...:)

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
ObjectPropertiesSave.epf
.epf 9,30Kb
03.03.15
4
.epf 1.01 9,30Kb 4 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Сергей Иванов (u_n_k_n_o_w_n) 04.03.15 12:24
В описании немного слукавили: пишите через 2 функции - в действительности используете 5 процедур! За идею +!
2. Andrey Smirnov (dusha0020) 04.03.15 13:06
(1) u_n_k_n_o_w_n, Есть и лукавство, конечно:)
Однако, рабочих процедур всего 2. Остальные 3 распределяют и направляют работу. Не исполнители, а, так сказать, руководители!
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа