Интерфейс
На форме документа/справочника – две кнопки Сохранить как шаблон и Заполнить из шаблона.
По нажатию на кнопку Сохранить как шаблон открывается форма:
Пользователь вводит наименование шаблона, отмечает нужные реквизиты и нажимает кнопку Сохранить. Настройки записываются в ХранилищеОбщихНастроек в разрезе пользователя и типа текущего документа/справочника. Значения реквизитов сохраняются также в ХранилищеОбщихНастроек в разрезе пользователя, типа документа/справочника и имени шаблона.
Соответственно, при нажатии на кнопку Заполнить из шаблона открывается форма:
Пользователь выбирает шаблон, при желании изменяет состав заполняемых реквизитов и нажимает кнопку Заполнить. Реквизиты текущего документа заполняются значениями из выбранного шаблона.
Серым цветом выделяются реквизиты объекта возможно неразмещенные на форме.
Команды работают также и из форм списков.
Реализация
Далее речь пойдет о реализации в расширении, но, наверное, будет лишним говорить о том, что то же самое делается и в обычной конфигурации с включенной возможностью изменения.
Рассматриваемая конструкция может быть реализована в двух вариантах.
Вариант 1
В расширение добавлена одна общая форма, две общие команды и (для красоты) группа команд.
Для подключения документа/справочника к рассматриваемому механизму, нужно просто указать тип параметра команды. Для этого следует добавить в расширение соответствующий объект, причем только корневой элемент, так как в расширении у добавленного объекта ничего не изменяется, никакие события не перехватываются. Добавление необходимо только для указания типа параметра команды.
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
Если НЕ ПараметрыВыполненияКоманды.Источник.ВладелецФормы = Неопределено
И Тип(ПараметрыВыполненияКоманды.Источник.ВладелецФормы) = Тип("ТаблицаФормы")
Тогда
ОткрытаИзФормыСписка = Ложь;
Иначе
ОткрытаИзФормыСписка = Истина;
Если ЭтоГруппаСправочника(ПараметрКоманды) Тогда
Сообщить("Нужно выбрать элемент, а не группу!");
Возврат;
КонецЕсли;
КонецЕсли;
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ОткрытаИзФормыСписка", ОткрытаИзФормыСписка);
ПараметрыФормы.Вставить("ЭтоСохранениеШаблона", Истина);
ПараметрыФормы.Вставить("ИсточникЦель", ПараметрКоманды);
ОткрытьФорму("ОбщаяФорма.ЗаполнениеПоШаблону_Форма",
ПараметрыФормы, ПараметрыВыполненияКоманды.Источник,
ПараметрыВыполненияКоманды.Уникальность,
ПараметрыВыполненияКоманды.Окно,
ПараметрыВыполненияКоманды.НавигационнаяСсылка);
КонецПроцедуры
&НаСервере
Функция ЭтоГруппаСправочника(ПараметрКоманды)
ЭтоГруппаСправочника = Ложь;
Если Метаданные.Справочники.Содержит(ПараметрКоманды.Метаданные())
И ПараметрКоманды.ЭтоГруппа
Тогда
ЭтоГруппаСправочника = Истина;
КонецЕсли;
Возврат ЭтоГруппаСправочника;
КонецФункции
Код модулей команд Сохранить… и Заполнить… отличается только значением параметра ЭтоСохранениеШаблона.
Форма заполнения/сохранения в конфигураторе выглядит следующим образом:
В форме – две таблицы значений, связанных по строковому ключу, и несколько служебных реквизитов.
Код модуля формы с комментариями:
#Область ОбработчикиСобытийФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ОткрытаИзФормыСписка") Тогда
ОткрытаИзФормыСписка = Параметры.ОткрытаИзФормыСписка;
Иначе
Отказ = Истина;
КонецЕсли;
Если Параметры.Свойство("ЭтоСохранениеШаблона") Тогда
ЭтоСохранениеШаблона = Параметры.ЭтоСохранениеШаблона;
Иначе
Отказ = Истина;
КонецЕсли;
Если Параметры.Свойство("ИсточникЦель") Тогда
// Помещаем в реквизит формы ссылку на документ/справочник из формы которого открыли эту форму
// ("источник" сохранения / "цель" заполнения)
ИсточникЦель = Параметры.ИсточникЦель;
ИмяЗаполняемогоОбъекта = ИсточникЦель.Метаданные().ПолноеИмя();
Иначе
Отказ = Истина;
КонецЕсли;
КнопкаСохранитьЗаполнить = Элементы.Шаблоны.КоманднаяПанель.ПодчиненныеЭлементы.ШаблоныСохранитьЗаполнить;
КомандаСохранитьЗаполнить = ЭтаФорма.Команды.СохранитьЗаполнить;
Если ЭтоСохранениеШаблона Тогда
Заголовок = "`79; Сохранить как шаблон " + СокрЛП(ИсточникЦель);
КнопкаСохранитьЗаполнить.Заголовок = "Сохранить";
КомандаСохранитьЗаполнить.Подсказка = "Сохранить " + СокрЛП(ИсточникЦель) + " как шаблон для заполнения";
Иначе
Заголовок = "`60; Заполнить из выделенного шаблона " + СокрЛП(ИсточникЦель);
КнопкаСохранитьЗаполнить.Заголовок = "Заполнить";
КомандаСохранитьЗаполнить.Подсказка = "Заполнить " + СокрЛП(ИсточникЦель) + " из выделенного шаблона";
КонецЕсли;
// Префиксы для формирования ключей объекта в хранилище
ПрефиксНастройки = "ЗаполнениеПоШаблону_Настройка_";
ПрефиксШаблона = "ЗаполнениеПоШаблону_Шаблон_";
ЗагрузитьНастройки();
// Если это заполнение по шаблону, то блокируем кнопки Добавить и Удалить
Элементы.Шаблоны.ИзменятьСоставСтрок = ЭтоСохранениеШаблона;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормыШаблоны
&НаКлиенте
Процедура ШаблоныПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, Группа, Параметр)
// Возможность редактирования имени шаблона даем только при его создании
// пользователю несложно создать новый шаблон, а кода меньше
Элемент.ПодчиненныеЭлементы.ШаблоныШаблон.ТолькоПросмотр = Ложь;
КонецПроцедуры
&НаКлиенте
Процедура ШаблоныПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
Если НоваяСтрока Тогда
Элемент.ТекущиеДанные.ОбъектШаблон = ИсточникЦель;
Элемент.ТекущиеДанные.Ключ = Новый УникальныйИдентификатор;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ШаблоныПередОкончаниемРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования, Отказ)
Если НЕ ОтменаРедактирования Тогда
Если СокрЛП(Элемент.ТекущиеДанные.Шаблон) = "" Тогда
Отказ = Истина;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Введите имя шаблона или нажмите Esc!";
Сообщение.Поле = "Шаблоны.Шаблон";
Сообщение.Сообщить();
ИначеЕсли Шаблоны.НайтиСтроки(Новый Структура("Шаблон", Элемент.ТекущиеДанные.Шаблон)).Количество() > 1 Тогда
Отказ = Истина;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Шаблон с таким именем уже существует. Введите другое имя шаблона или нажмите Esc!";
Сообщение.Поле = "Шаблоны.Шаблон";
Сообщение.Сообщить();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ШаблоныПриОкончанииРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования)
Если НЕ ОтменаРедактирования И НоваяСтрока Тогда
ЗаполнитьСписокРеквизитов(Элемент.ТекущиеДанные.Ключ);
УдалитьСтрокиРеквизитовНедоступныхВДанныхФормы();
// Реквизиты объекта, которые (возможно) не выведены на форму, выделим серым цветом шрифта.
// Для этого установим признак
УстановитьПризнакВозможноНеОтображенНаФорме();
// Отбираем в таблице Реквизиты, соответствующие выделенному шаблону в таблице Шаблоны
УстановитьОтборИменРеквизитов();
КонецЕсли;
Элемент.ПодчиненныеЭлементы.ШаблоныШаблон.ТолькоПросмотр = Истина;
КонецПроцедуры
&НаКлиенте
Процедура ШаблоныПриАктивизацииСтроки(Элемент)
УстановитьОтборИменРеквизитов();
КонецПроцедуры
&НаКлиенте
Процедура ШаблоныПередУдалением(Элемент, Отказ)
Отбор = Новый Структура("Ключ", Элемент.ТекущиеДанные.Ключ);
УдаляемыеСтроки = Реквизиты.НайтиСтроки(Отбор);
Для каждого Строка из УдаляемыеСтроки Цикл
Реквизиты.Удалить(Строка);
КонецЦикла;
ИмяШаблона = Элемент.ТекущиеДанные.Шаблон;
КлючОбъекта = ПрефиксШаблона + ИмяЗаполняемогоОбъекта + "_" + ИмяШаблона;
УдалитьШаблонИзХранилища(КлючОбъекта);
КонецПроцедуры
&НаКлиенте
Процедура ШаблоныПослеУдаления(Элемент)
СохранитьНастройки();
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормыРеквизиты
// Блокируем удаление по клавише Del
&НаКлиенте
Процедура РеквизитыПередУдалением(Элемент, Отказ)
Отказ = Истина;
КонецПроцедуры
// Блокируем добавление по клавише Insert
&НаКлиенте
Процедура РеквизитыПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, Группа, Параметр)
Отказ = Истина;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиКомандФОрмы
&НаКлиенте
Процедура СохранитьЗаполнить(Команда)
ТекущиеДанные = Элементы.Шаблоны.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
ИмяШаблона = ТекущиеДанные.Шаблон;
КлючОбъекта = ПрефиксШаблона + ИмяЗаполняемогоОбъекта + "_" + ИмяШаблона;
Если ЭтоСохранениеШаблона Тогда
ТекущиеДанные.ОбъектШаблон = ИсточникЦель;
// Интересное, на мой взгляд, место. Передаем с клиента на сервер во внеконтекстную процедуру
// значения из ДанныеФормыСтруктура, причем не текущей формы, а объекта формы-владельца.
// Выручает то, что уже имеем список реквизитов, которые и обходим в цикле.
//
// Сохраняем все реквизиты, независимо от установленных флажков,
// чтобы пользователь при заполнении мог выбрать другие реквизиты
Если НЕ ОткрытаИзФормыСписка Тогда
ВладелецФормыОбъект = ВладелецФормы.Объект;
Иначе
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Ключ", ИсточникЦель);
ФормаВладельца = ПолучитьФорму(ИмяЗаполняемогоОбъекта + ".ФормаОбъекта", ПараметрыФормы, Истина);
ВладелецФормыОбъект = ФормаВладельца.Объект;
КонецЕсли;
// Пакуем значения реквизитов формы-владельца в структуру
ДанныеШаблона = Новый Структура();
Для каждого Стр из Реквизиты Цикл
ЗначениеРеквизита = Неопределено;
Выполнить("ЗначениеРеквизита = ВладелецФормыОбъект." + Стр.Реквизит);
ДанныеШаблона.Вставить(Стр.Реквизит, ЗначениеРеквизита);
КонецЦикла;
// и передаем на сервер
СохранитьДанныеШаблона(КлючОбъекта, ДанныеШаблона);
//
// Если пользователь ввел новый шаблон, потом активизировал другую строку таблицы Шаблоны,
// и нажал кнопку Сохранить, то новый шаблон сохранен не будет.
// Поэтому нужен флаг, чтобы не сохранять в настройке формы строку с именем несохраненного шаблона.
ТекущиеДанные.Сохранен = Истина;
Иначе // Заполняем выбранные реквизиты формы-владельца из шаблона
// Проверка: есть ли хотя бы один отмеченный реквизит
Отбор = Новый Структура;
Отбор.Вставить("Ключ", ТекущиеДанные.Ключ);
Отбор.Вставить("Пометка", Истина);
Если Реквизиты.НайтиСтроки(Отбор).Количество() = 0 Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не выбрано ни одного реквизита!";
Сообщение.Поле = "Реквизиты";
Сообщение.Сообщить();
Возврат;
КонецЕсли;
//
ДанныеШаблона = ПолучитьДанныеШаблона(КлючОбъекта);
// На всякий случай
Если ДанныеШаблона = Неопределено Тогда
Сообщить("Шаблон " + ИмяШаблона + " не был сохранен!");
Возврат;
КонецЕсли;
// Формируем строку выбранных реквизитов - параметр функции ЗаполнитьЗначенияСвойств
ВыбранныеРеквизиты = Новый Массив;
Ключ = Элементы.Шаблоны.ТекущиеДанные.Ключ;
Для каждого Стр Из Реквизиты Цикл
Если Стр.Ключ = Ключ И Стр.Пометка Тогда
ВыбранныеРеквизиты.Добавить(Стр.Реквизит);
КонецЕсли;
КонецЦикла;
ВыбранныеРеквизитыСтрока = СтрСоединить(ВыбранныеРеквизиты, ", ");
Если НЕ ОткрытаИзФормыСписка Тогда // Заполняем реквизиты в форме
ЗаполнитьЗначенияСвойств(ВладелецФормы.Объект, ДанныеШаблона, ВыбранныеРеквизитыСтрока);
ВладелецФормы.Модифицированность = Истина;
Иначе // Если открыта из формы списка, то получаем форму, заполняем объект формы, открываем форму
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Ключ", ИсточникЦель);
ФормаВладельца = ПолучитьФорму(ИмяЗаполняемогоОбъекта + ".ФормаОбъекта", ПараметрыФормы);
ЗаполнитьЗначенияСвойств(ФормаВладельца.Объект, ДанныеШаблона, ВыбранныеРеквизитыСтрока);
ФормаВладельца.Модифицированность = Истина;
ФормаВладельца.Открыть();
КонецЕсли;
КонецЕсли;
СохранитьНастройки();
Закрыть();
КонецПроцедуры
&НаКлиенте
Процедура УстановитьФлажки(Команда)
Если НЕ ЕстьРеквизиты() Тогда
Возврат;
КонецЕсли;
Ключ = Элементы.Шаблоны.ТекущиеДанные.Ключ;
Для каждого Стр Из Реквизиты Цикл
Если Стр.Ключ = Ключ Тогда
Стр.Пометка = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура СнятьФлажки(Команда)
Если НЕ ЕстьРеквизиты() Тогда
Возврат;
КонецЕсли;
Ключ = Элементы.Шаблоны.ТекущиеДанные.Ключ;
Для каждого Стр Из Реквизиты Цикл
Если Стр.Ключ = Ключ Тогда
Стр.Пометка = Ложь;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
&НаСервере
Процедура СохранитьНастройки()
ШаблоныЗначение = РеквизитФормыВЗначение("Шаблоны");
РеквизитыЗначение = РеквизитФормыВЗначение("Реквизиты");
// Шаблоны, которые не сохранены (по кнопке Сохранить), соответственно, в настройках не сохраняем
УдалитьСтрокиНесохраненныхШаблонов(ШаблоныЗначение, РеквизитыЗначение);
ХранилищеОбщихНастроек.Сохранить(ПрефиксНастройки + ИмяЗаполняемогоОбъекта,
"Шаблоны",
Новый ХранилищеЗначения(ШаблоныЗначение, Новый СжатиеДанных(9)));
ХранилищеОбщихНастроек.Сохранить(ПрефиксНастройки + ИмяЗаполняемогоОбъекта,
"Реквизиты",
Новый ХранилищеЗначения(РеквизитыЗначение, Новый СжатиеДанных(9)));
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьНастройки()
ШаблоныХранилищеЗначения = ХранилищеОбщихНастроек.Загрузить(ПрефиксНастройки + ИмяЗаполняемогоОбъекта, "Шаблоны");
Если НЕ ЗначениеЗаполнено(ШаблоныХранилищеЗначения) Тогда
Возврат;
КонецЕсли;
ШаблоныЗначение = ШаблоныХранилищеЗначения.Получить();
ЗначениеВРеквизитФормы(ШаблоныЗначение, "Шаблоны");
РеквизитыХранилищеЗначения = ХранилищеОбщихНастроек.Загрузить(ПрефиксНастройки + ИмяЗаполняемогоОбъекта, "Реквизиты");
Если ЗначениеЗаполнено(РеквизитыХранилищеЗначения) Тогда
РеквизитыЗначение = РеквизитыХранилищеЗначения.Получить();
ЗначениеВРеквизитФормы(РеквизитыЗначение, "Реквизиты");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура СохранитьДанныеШаблона(КлючОбъекта, ДанныеШаблона)
ХранилищеОбщихНастроек.Сохранить(КлючОбъекта,,ДанныеШаблона);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьДанныеШаблона(КлючОбъекта)
Возврат ХранилищеОбщихНастроек.Загрузить(КлючОбъекта);
КонецФункции
&НаСервереБезКонтекста
Процедура УдалитьШаблонИзХранилища(КлючОбъекта)
ИмяПользователяИБ = СокрЛП(ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
ХранилищеОбщихНастроек.Удалить(КлючОбъекта,,ИмяПользователяИБ);
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьСписокРеквизитов(Ключ)
Для каждого Реквизит Из ИсточникЦель.Метаданные().Реквизиты Цикл
НоваяСтрока = Реквизиты.Добавить();
НоваяСтрока.Реквизит = Реквизит.Имя;
НоваяСтрока.Синоним = Реквизит.Синоним;
НоваяСтрока.Ключ = Ключ;
КонецЦикла;
Реквизиты.Сортировать("Синоним");
КонецПроцедуры
// Удаляем строки с именами реквизитов объекта формы-владельца, недоступные в данных формы,
// например, реквизиты с типом ХранилищеЗначения.
// Возможно, существует иной способ удаления таковых реквизитов (не через Попытка-Исключение).
// Если кто-то подскажет, как программно проверить доступность типа в данных формы, буду очень признателен.
//
&НаКлиенте
Процедура УдалитьСтрокиРеквизитовНедоступныхВДанныхФормы()
Если НЕ ОткрытаИзФормыСписка Тогда
ПодстрокаКодаПроверки = "А = ВладелецФормы.Объект.";
Иначе
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Ключ", ИсточникЦель);
ФормаВладельца = ПолучитьФорму(ИмяЗаполняемогоОбъекта + ".ФормаОбъекта", ПараметрыФормы, Истина);
ПодстрокаКодаПроверки = "А = ФормаВладельца.Объект.";
КонецЕсли;
мКУдалению = Новый Массив();
Для каждого Стр Из Реквизиты Цикл
Попытка
Выполнить(ПодстрокаКодаПроверки + Стр.Реквизит);
Исключение
мКУдалению.Добавить(Стр);
КонецПопытки;
КонецЦикла;
Для Каждого Элемент из мКУдалению Цикл
Реквизиты.Удалить(Элемент);
КонецЦикла;
КонецПроцедуры
// Ищем в элементах формы поля совпадающие по имени с реквизитом объекта.
// Если не находим, то устанавливаем признак ВозможноНеОтображенНаФорме.
// Понятно, что у поля формы в общем случае может быть имя, отличное от имени реквизита,
// однако иного способа проверить, отображен ли реквизит на форме, придумать/найти не удалось :(
// Если кто-то подскажет, как программно проверить выведен ли реквизит на форму (серый квадрат), буду очень признателен.
//
// (В условном оформлении формы настраиваем выделение неотображенных реквизитов серым цветом)
//
&НаКлиенте
Процедура УстановитьПризнакВозможноНеОтображенНаФорме()
Для каждого Стр Из Реквизиты Цикл
Стр.ВозможноНеОтображенНаФорме = Истина;
Для каждого Элемент Из ВладелецФормы.Элементы Цикл
Если ТипЗнч(Элемент) = Тип("ПолеФормы")
И Стр.Реквизит = Элемент.Имя
Тогда
Стр.ВозможноНеОтображенНаФорме = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура УстановитьОтборИменРеквизитов()
Данные = Элементы.Шаблоны.ТекущиеДанные;
Если Данные = Неопределено Тогда
Возврат;
КонецЕсли;
Элементы.Реквизиты.ОтборСтрок = Новый ФиксированнаяСтруктура("Ключ", Данные.Ключ);
КонецПроцедуры
// Если пользователь вводил имена шаблонов, не нажимая кнопку Сохранить,
// то строки с именами несохраненных шаблонов удаляем, чтобы исключить ошибки при заполнении
&НаСервере
Процедура УдалитьСтрокиНесохраненныхШаблонов(ШаблоныЗначение, РеквизитыЗначение)
Отбор = Новый Структура("Сохранен", Ложь);
Если ШаблоныЗначение.НайтиСтроки(Отбор).Количество() = 0 Тогда
Возврат;
КонецЕсли;
МассивКлючейНесохраненныхШаблонов = Новый Массив;
// Удаляем строки из таблицы значений с именами шаблонов
мКУдалению = Новый Массив();
Для каждого Стр Из ШаблоныЗначение Цикл
Если НЕ Стр.Сохранен Тогда
мКУдалению.Добавить(Стр);
МассивКлючейНесохраненныхШаблонов.Добавить(Стр.Ключ);
КонецЕсли;
КонецЦикла;
Для Каждого Элемент из мКУдалению Цикл
ШаблоныЗначение.Удалить(Элемент);
КонецЦикла;
// Удаляем соответсвующие строки из таблицы значений с именами реквизитов
мКУдалению = Новый Массив();
Для каждого Стр Из РеквизитыЗначение Цикл
Если НЕ МассивКлючейНесохраненныхШаблонов.Найти(Стр.Ключ) = Неопределено Тогда
мКУдалению.Добавить(Стр);
КонецЕсли;
КонецЦикла;
Для Каждого Элемент из мКУдалению Цикл
РеквизитыЗначение.Удалить(Элемент);
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Функция ЕстьРеквизиты()
ТекущиеДанные = Элементы.Шаблоны.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Отбор = Новый Структура("Ключ", ТекущиеДанные.Ключ);
Возврат Реквизиты.НайтиСтроки(Отбор).Количество() > 0;
КонецФункции
#КонецОбласти
Вариант 2
Вариант 2 отличается от первого тем, что форму заполнения/сохранения добавляем в каждый нужный нам документ/справочник.
У формы устанавливаем свойство АвтоматическоеСохранениеДанныхВНастройках – "Использовать" и расставляем флажки "Сохранение". Платформа сама позаботится о сохранении настроек. Соответственно, код по сохранению настроек не нужен.
Команды добавляем в форму самого документа. Здесь больше возможностей по размещению кнопок. Можно разместить их, например, только в меню Ещё.
В этом варианте код модуля формы существенно сокращается. Однако могут возникнуть проблемы, если панели формы подключаемого объекта заполняются динамически.
Кроме того, в коде команд уже не нужно проверять, откуда открыта форма сохранения/заполнения: из формы списка или из формы объекта.
Следует отметить преимущества и недостатки представленных вариантов.
Вариант 1
Плюсы:
1. Простое подключение к документу/справочнику - добавить тип параметра команды и все.
2. Возможность заполнения/сохранения из формы списка. Хотя, на мой взгляд, это скорее недостаток. Дело в том, что глобальные параметризуемые команды размещаются в формах списка автоматически (если в форме списка – объекты одного типа). И обойти этот платформенный сервис не удается.
Минусы:
1. Для того чтобы исключить из заполняемых реквизитов те, которые заполнять не требуется априори, нужно прикручивать дополнительный нетривиальный механизм.
2. При сохранении/заполнении нового объекта платформа требует предварительной его записи. Это также следствие использования команд глобального интерфейса. И это тоже не удается обойти.
Вариант 2
Плюсы:
1. Кнопки можно разместить почти в любом разумном месте формы.
2. Для каждого подключаемого объекта легко добавить персональный список незаполняемых реквизитов.
3. Шаблоны можно сохранять из незаписанного в базу нового объекта.
Минусы:
1. Более трудоемкое подключение.Необходимо копировать одну и ту же форму в ветку форм каждого нужного объекта метаданных. Необходимо добавить в форму заполняемого объекта две команды-кнопки.
2. Пользователь может сохранить пустой шаблон.
Рассмотренная задача может быть полезной начинающим осваивать особенности работы управляемых форм. Несмотря на простоту, она содержит ряд не совсем очевидных моментов. В частности таких, как:
- передача с клиента на сервер данных владельца текущей формы (тип ДанныеФормыСтруктура);
- программная проверка типа реквизита на доступность в данных формы;
- программная проверка: "А размещен ли реквизит на форме?". Используемый вариант вполне работоспособный, но однозначно достоверного ответа на вопрос не дает. Буду весьма признателен, если ветераны жанра подскажут достойное решение.
Расширение первого варианта работоспособно в режиме совместимости 8.3.10 и выше, поскольку в этом релизе появилась возможность добавлять общие команды. Расширение второго варианта работоспособно, начиная с режима совместимости 8.3.6.
Механизм (вариант 2) опробован в интеграционном решении для основных типовых конфигураций. Включался в интегрируемую конфигурацию непосредственно (не через расширение). Отзывы пользователей положительные.
В прилагаемом архиве - расширения по обоим вариантам и выгрузки демонстрационной конфигурации "Управляемое приложение" с подключенными расширениями (итого 4 файла).