Почему пропадают добавленные колонки в расширении 1С после обновления и как решить эту проблему раз и навсегда?

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

Механизм расширений конфигурации в платформе «1С:Предприятие 8.3» — это мощный инструмент, который позволяет кастомизировать систему без снятия типового решения с поддержки. Однако многие разработчики сталкиваются с крайне неприятной ситуацией: после очередного обновления типовой конфигурации (например, «Бухгалтерии предприятия 3.0» или «ERP») добавленные в расширение колонки табличных частей внезапно исчезают из интерфейса, а в конфигураторе загорается желтая полоса с предупреждением «Обновить форму». При этом сам программный код расширения остается нетронутым.

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

Выясняем причину: почему ломается визуальное заимствование форм?

Когда мы заимствуем форму из основной конфигурации в расширение для визуального редактирования, платформа создает внутри расширения две логические структуры:

  1. Сохраненный слепок оригинальной формы — состояние формы на момент её заимствования.
  2. Модифицированная форма расширения — форма, в которую мы визуально добавили свои колонки, кнопки или реквизиты.

В режиме «1С:Предприятие» платформа выполняет так называемое трехстороннее сравнение (3-way merge). Она сопоставляет текущую форму из обновившейся основной конфигурации поставщика, сохраненный слепок в расширении и наши доработки. Если поставщик в обновлении изменил структуру формы (например, переименовал родительскую группу, изменил состав реквизитов или тип данных), платформа сообщает о конфликте желтой полосой «Обновить форму».

При попытке обновить форму интерактивно в конфигураторе часто срабатывает давняя проблема платформы 1С: связи элементов формы с реквизитами затираются. Поля визуально остаются в дереве элементов расширения, но их свойство ПутьКДанным (DataPath) очищается. Как результат — элементы просто исчезают с экрана в пользовательском режиме, так как они больше не связаны с данными объекта.

---

Способ 1. Быстрое восстановление связей вручную (Временное решение)

Если проект небольшой, а форму нужно починить прямо сейчас, мы можем восстановить привязки визуально. Разберем этот процесс по шагам:

  1. Откроем проблемную форму в расширении. При появлении предупреждения нажмем кнопку «Обновить форму» (или перейдем в меню Форма — Обновить расширение формы).
  2. После обновления перейдем к дереву элементов формы в левой части редактора.
  3. Найдем наши добавленные колонки или поля. Обратим внимание на их свойства: поле ПутьКДанным, скорее всего, окажется пустым.
  4. Вручную укажем правильный путь к данным для каждого элемента (например, Объект.Товары.МойРеквизитКолонки).
  5. Проверим свойства событий (например, ПриИзменении). Если имя процедуры-обработчика стерлось, выберем ее заново из списка процедур модуля формы расширения.

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

---

Способ 2. Программное создание элементов управления (Лучшая практика)

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

Рассмотрим подробнее, как реализовать этот подход на практике.

Шаг 1. Добавление реквизитов в расширение

Если для новых колонок требуются новые реквизиты в табличной части, мы добавляем их непосредственно в объект метаданных (например, в табличную часть Товары документа ПоступлениеТоваровУслуг) внутри расширения. Саму форму при этом заимствовать визуально не нужно.

Шаг 2. Перехват события создания формы

Заимствуем в расширение только модуль формы документа (без визуального заимствования самой формы) и используем аннотацию &После для перехвата стандартного обработчика события ПриСозданииНаСервере. Напишем код, который динамически добавит колонку в нужную таблицу.

Проанализируем пример кода:


&После("ПриСозданииНаСервере")
Процедура Ист_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Шаг 1: Находим целевую таблицу на форме по ее имени в конфигурации поставщика
    ТаблицаТовары = Элементы.Найти("Товары");
    
    Если ТаблицаТовары <> Неопределено Тогда
        
        ИмяНовойКолонки = "ТоварыМойДополнительныйРеквизит";
        
        // Предотвращаем дублирование элемента при повторном вызове события
        Если Элементы.Найти(ИмяНовойКолонки) = Неопределено Тогда
            
            // Шаг 2: Создаем новый элемент формы типа "ПолеФормы" и помещаем его внутрь таблицы
            НоваяКолонка = Элементы.Добавить(ИмяНовойКолонки, Тип("ПолеФормы"), ТаблицаТовары);
            НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
            
            // Шаг 3: Связываем поле с реквизитом объекта
            НоваяКолонка.ПутьКДанным = "Объект.Товары.МойДополнительныйРеквизит";
            
            // Шаг 4: Настраиваем визуальные свойства элемента
            НоваяКолонка.Заголовок = "Доп. Реквизит (Расш.)";
            НоваяКолонка.РежимРедактирования = РежимРедактированияКолонки.ВХвостеКоридора;
            НоваяКолонка.Ширина = 12;
            
            // Шаг 5: Назначаем обработчик события при изменении значения в этой колонке
            НоваяКолонка.УстановитьДействие("ПриИзменении", "Подключаемый_МойРеквизитПриИзменении");
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Шаг 3. Описание обработчика событий на клиенте

Теперь нам необходимо описать процедуру-обработчик Подключаемый_МойРеквизитПриИзменении, которую мы зарегистрировали для нашей колонки на предыдущем шаге. Эта процедура должна располагаться в модуле формы расширения с директивой компиляции &НаКлиенте.

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


&НаКлиенте
Процедура Подключаемый_МойРеквизитПриИзменении(Элемент)
    
    // Получаем строку таблицы, в которой пользователь изменил значение
    ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
    
    Если ТекущаяСтрока <> Неопределено Тогда
        
        // Выполняем требуемый алгоритм пересчета
        Если ТекущаяСтрока.МойДополнительныйРеквизит > 0 Тогда
            // Например, корректируем сумму или выполняем иные расчеты
            ТекущаяСтрока.Сумма = ТекущаяСтрока.Количество * ТекущаяСтрока.Цена * ТекущаяСтрока.МойДополнительныйРеквизит;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

---

Способ 3. Интеграция через механизмы БСП (Без заимствования формы вообще)

Если вы разрабатываете расширение для современной конфигурации, построенной на базе Библиотеки Стандартных Подсистем (БСП), например, «1С:ERP», «Комплексная автоматизация» или «Бухгалтерия предприятия 3.0», можно пойти еще дальше и полностью отказаться даже от заимствования модуля формы.

В БСП предусмотрены специальные переопределяемые модули для кастомизации интерфейса программными методами. Мы можем использовать общий модуль МодификацияКонфигурацииПереопределяемый.

Давайте разберем, как это сделать:

  1. Заимствуем в расширение общий модуль МодификацияКонфигурацииПереопределяемый.
  2. Добавим метод-расширение для процедуры ПриСозданииНаСервере с аннотацией &Вместо или &После.
  3. Внутри процедуры выполним проверку имени открываемой формы и добавим колонки программно через переданный в параметрах контекст формы.

Посмотрим на пример реализации в расширении общего модуля:


&После("ПриСозданииНаСервере")
Процедура Мой_ПриСозданииНаСервере(Форма, Отказ, СтандартнаяОбработка) Экспорт
    
    // Проверяем, что открывается именно интересующая нас форма документа поступления
    Если Форма.ИмяФормы = "Документ.ПоступлениеТоваровУслуг.Форма.ФормаДокумента" Тогда
        
        ТаблицаТовары = Форма.Элементы.Найти("Товары");
        Если ТаблицаТовары <> Неопределено Тогда
            
            ИмяЭлемента = "ТоварыПрограммноеПоле";
            Если Форма.Элементы.Найти(ИмяЭлемента) = Неопределено Тогда
                
                // Создаем элемент, обращаясь к коллекции элементов переданной формы
                НовоеПоле = Форма.Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"), ТаблицаТовары);
                НовоеПоле.Вид = ВидПоляФормы.ПолеВвода;
                НовоеПоле.ПутьКДанным = "Объект.Товары.МойДополнительныйРеквизит";
                НовоеПоле.Заголовок = "Программное поле";
                
                // Для подключения действий в БСП используется перенаправление на общие клиентские модули
                НовоеПоле.УстановитьДействие("ПриИзменении", "ОбщегоНазначенияБСПКлиент.Подключаемый_ВыполнитьПереопределяемуюКоманду");
                
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

---

Резюме: правила безопасной разработки расширений

Для создания отказоустойчивых расширений в среде 1С рекомендуем придерживаться следующих правил:

← На главную