Как программно добавить кнопки заполнения табличной части на управляемую форму в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При переходе со старых конфигураций 1С (например, УПП, УТ 10.3 или КА 1.1) на управляемые формы разработчики часто сталкиваются с необходимостью переноса сложного и разветвленного интерфейса. Одним из таких вызовов является динамическое создание кнопок для заполнения табличных частей документов. В обычных формах этот процесс решался относительно просто с помощью универсальных механизмов и передачи объекта Действие. В управляемом приложении принципы построения интерфейса кардинально изменились. Разберем подробно, как правильно решать эту задачу в концепции управляемого клиента, рассмотрим технические ограничения платформы и научимся обходить их изящными методами.

Архитектурные ограничения управляемых форм

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

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

Решение проблемы с помощью паттерна «Единый диспетчер»

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

Для обхода этого ограничения применим эффективный паттерн проектирования — «Единый диспетчер». Суть метода заключается в том, что для всех динамически создаваемых команд мы назначаем один и тот же обработчик в модуле формы. Внутри этого обработчика мы анализируем имя вызвавшей его команды и перенаправляем выполнение в общий модуль. Проанализируем по шагам, как это реализовать.

Шаг 1. Программное создание команд и кнопок на сервере

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

Посмотрим на пример реализации серверной процедуры:


&НаСервере
Процедура СоздатьКнопкиЗаполненияНаСервере(ЭтаФорма) Экспорт

    // 1. Создаем команду для сравнения цен
    ИмяКомандыСравнения = "СравнениеЦен";
    КомандаСравнения = ЭтаФорма.Команды.Добавить(ИмяКомандыСравнения);
    КомандаСравнения.Действие = "Подключаемый_ВыполнитьКомандуЗаполнения";
    КомандаСравнения.Заголовок = "Сравнение цен";
    КомандаСравнения.ИзменяетСохраняемыеДанные = Истина;

    // Определяем родителя для кнопки — командную панель таблицы "Товары"
    РодительТовары = ЭтаФорма.Элементы.ТоварыКоманднаяПанель;

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

    // 2. Создаем команду для распределения услуг
    ИмяКомандыРаспределения = "РаспределитьУслуги";
    КомандаРаспределения = ЭтаФорма.Команды.Добавить(ИмяКомандыРаспределения);
    КомандаРаспределения.Действие = "Подключаемый_ВыполнитьКомандуЗаполнения";
    КомандаРаспределения.Заголовок = "Распределить услуги";
    КомандаРаспределения.ИзменяетСохраняемыеДанные = Истина;

    // Определяем родителя для кнопки — командную панель таблицы "Услуги"
    РодительУслуги = ЭтаФорма.Элементы.УслугиКоманднаяПанель;

    // Создаем кнопку в командной панели "Услуги"
    КнопкаРаспределения = ЭтаФорма.Элементы.Добавить(ИмяКомандыРаспределения, Тип("КнопкаФормы"), РодительУслуги);
    КнопкаРаспределения.Вид = ВидКнопкиФормы.КнопкаКоманднойПанели;
    КнопкаРаспределения.ИмяКоманды = ИмяКомандыРаспределения;

КонецПроцедуры

Обратите внимание на важную деталь: обе созданные команды ссылаются на одно и то же действие "Подключаемый_ВыполнитьКомандуЗаполнения".

Шаг 2. Описание обработчика-диспетчера в модуле управляемой формы

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

Добавим в модуль формы следующий код:


&НаКлиенте
Процедура Подключаемый_ВыполнитьКомандуЗаполнения(Команда)
    
    // Передаем управление в общий клиентский модуль, передавая контекст формы и имя команды
    ЗаполнениеТабличныхЧастейКлиент.ОбработатьКомандуЗаполнения(ЭтотОбъект, Команда.Имя);
    
КонецПроцедуры

Шаг 3. Логика обработки и ветвления в общем модуле

В неглобальном общем модуле ЗаполнениеТабличныхЧастейКлиент (у которого в свойствах должны стоять флаги "Клиент (управляемое приложение)") мы реализуем распределение логики в зависимости от того, какая именно кнопка была нажата пользователем.

Рассмотрим пример реализации клиентского диспетчера:


Процедура ОбработатьКомандуЗаполнения(ФормаДокумента, ИмяКоманды) Экспорт

    Если ИмяКоманды = "СравнениеЦен" Тогда
        ВыполнитьСравнениеЦенНаКлиенте(ФормаДокумента);
    ИначеЕсли ИмяКоманды = "РаспределитьУслуги" Тогда
        ВыполнитьРаспределениеУслугНаКлиенте(ФормаДокумента);
    КонецЕсли;

КонецПроцедуры

Процедура ВыполнитьСравнениеЦенНаКлиенте(ФормаДокумента)
    // Пример вызова внешней или встроенной обработки
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("ДокументСсылка", ФормаДокумента.Объект.Ссылка);
    
    ОткрытьФорму("Обработка.СравнениеЦен.Форма", ПараметрыОткрытия, ФормаДокумента);
КонецПроцедуры

Процедура ВыполнитьРаспределениеУслугНаКлиенте(ФормаДокумента)
    // Пример интерактивного заполнения или вызова серверного расчета
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВводаПараметровРаспределения", ЭтотОбъект, ФормаДокумента);
    ПоказатьВводЗначения(ОписаниеОповещения, 0, "Введите коэффициент распределения:");
EndProc

Перенос старых механизмов заполнения (на примере УПП)

При миграции с обычных форм УПП разработчики часто наталкиваются на процедуру УстановитьКнопкиПодменюЗаполненияТЧ(), которая использовала функции общего модуля УниверсальныеМеханизмы. Этот механизм автоматически опрашивал зарегистрированные внешние обработки заполнения табличных частей и строил дерево кнопок в подменю "Заполнить".

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

  1. На сервере получить список зарегистрированных обработок заполнения для данного типа документа.
  2. Программным циклом обойти этот список и создать для каждой обработки команду в коллекции ЭтаФорма.Команды.Добавить(). В имя команды можно зашифровать уникальный идентификатор или имя внешней обработки (например, "УникальныйИдентификаторОбработки_" + СтрЗаменить(НовыйУникальныйИдентификатор(), "-", "")).
  3. Создать соответствующую кнопку в подменю "Заполнить" нужной табличной части.
  4. В едином обработчике на клиенте парсить имя команды, вычленять идентификатор обработки, считывать параметры и запускать ее исполнение.

Современный подход: Использование БСП

Разрабатывая интерфейсы в современных конфигурациях или переводя старые системы на управляемые формы в процессе модернизации, настоятельно рекомендуется отказаться от самописных велосипедов в пользу механизмов Библиотеки стандартных подсистем (БСП). Подсистема «Дополнительные отчеты и обработки» берет на себя всю рутину по выводу кнопок заполнения.

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

  1. В модуле формы в процедуре ПриСозданииНаСервере добавить вызов стандартного метода БСП:
    
    &НаСервере
    Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
                
        // Интеграция подсистемы БСП "Дополнительные отчеты и обработки"
        ДополнительныеОтчетыИОбработки.ПриСозданииНаСервере(ЭтотОбъект);
                
    КонецПроцедуры
    
  2. В модуле формы на клиенте описать подключаемый обработчик команд БСП, который автоматически свяжет интерфейс с логикой выполнения внешних обработок:
    
    &НаКлиенте
    Процедура Подключаемый_ВыполнитьНазначаемуюКоманду(Команда)
                
        ДополнительныеОтчетыИОбработкиКлиент.ВыполнитьНазначаемуюКоманду(ЭтотОбъект, Команда);
                
    КонецПроцедуры
    

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

Подводя итог, можно сказать, что хотя управляемые формы накладывают жесткие ограничения на программирование интерфейса и разделение контекстов, использование правильных паттернов, таких как «Единый диспетчер», или интеграция со стандартными механизмами БСП позволяют решать задачи по динамическому управлению элементами формы легко, красиво и надежно.

← На главную