При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью добавить в интерфейс документа временные элементы управления, такие как флажки выбора или вспомогательные маркеры в табличных частях. Однако стандартное поведение платформы при записи документа может преподнести сюрприз: все данные в таких колонках бесследно исчезают. Разберем подробно, почему это происходит и как правильно организовать сохранение этих данных в рамках сеанса работы с формой.
Для начала проанализируем ситуацию с точки зрения архитектуры управляемого приложения. Процесс записи документа — это не просто сохранение данных в базу, а сложный цикл преобразования типов данных. Рассмотрим этот процесс по шагам:
Объект (тип ДанныеФормыСтруктура) в объект прикладного уровня (например, ДокументОбъект.ЗаказКлиента).ДокументОбъект записывается в базу данных. Здесь важно понимать: в объекте метаданных вашей конфигурации нет той колонки, которую вы создали программно. Платформа просто игнорирует её при конвертации.Объект, чтобы пользователь видел актуальные данные.Поскольку в базе данных и в структуре ДокументОбъект вашей временной колонки не существует, при обратной загрузке данных в форму платформа инициализирует программный реквизит значением по умолчанию (для типа Булево это будет Ложь). Таким образом, визуально флажок сбрасывается сразу после нажатия кнопки сохранения.
Прежде чем решать проблему сохранения, вспомним, как правильно создавать такие колонки. Посмотрим на пример кода, который добавляет флажок в табличную часть Товары:
// В обработчике ПриСозданииНаСервере или через отдельную процедуру
МассивРеквизитов = Новый Массив;
ТипБулево = Новый ОписаниеТипов("Булево");
// Создаем новый реквизит в коллекции Объект.Товары
МассивРеквизитов.Добавить(Новый РеквизитФормы("ПереноситьГалочкаТест", ТипБулево, "Объект.Товары", "Выбрать", Ложь));
ЭтаФорма.ИзменитьРеквизиты(МассивРеквизитов);
// Добавляем элемент управления (колонку) на форму
НовыйЭлемент = Элементы.Вставить("ТоварыПереноситьГалочкаТест", Тип("ПолеФормы"), Элементы.Товары);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеФлажка;
НовыйЭлемент.ПутьКДанным = "Объект.Товары.ПереноситьГалочкаТест";
Важный нюанс: использование пятого параметра метода Новый РеквизитФормы(..., Истина) (сохраняемые данные) в данном случае не поможет восстановить значение после записи, так как он отвечает лишь за флаг модифицированности формы.
Чтобы данные не пропали, нам необходимо реализовать «кэширование» значений перед тем, как платформа начнет трансформацию данных. Рассмотрим подробнее использование обработчика ПередЗаписьюНаСервере. Нам нужно выгрузить состояние наших флажков во временную структуру.
Проанализируем ситуацию: как однозначно идентифицировать строку табличной части? Лучше всего использовать КлючСтроки или уникальный идентификатор, если он есть. Если нет — можно использовать НомерСтроки, но помните, что при записи номера строк могут измениться, если сработали типовые механизмы сортировки или удаления пустых строк.
Пример сохранения данных в реквизит формы (например, типа Произвольный, где мы будем хранить Соответствие):
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Создаем соответствие для хранения: Ключ = ИндексСтроки (или КлючСтроки), Значение = СостояниеФлажка
КэшФлажков = Новый Соответствие;
Для Каждого СтрокаТовары Из Объект.Товары Цикл
// Используем НомерСтроки как временный идентификатор
КэшФлажков.Вставить(СтрокаТовары.НомерСтроки, СтрокаТовары.ПереноситьГалочкаТест);
КонецЦикла;
// Помещаем кэш во временную переменную модуля формы или в параметры записи
ЭтаФорма.Параметры.Вставить("ВременноеХранилищеФлажков", КэшФлажков);
КонецПроцедуры
Теперь, когда документ записан и форма обновила данные из объекта, нам нужно «наложить» сохраненные состояния обратно на табличную часть. Для этого идеально подходит обработчик ПослеЗаписиНаСервере. Именно здесь данные формы уже перечитаны из базы, и наши программные колонки пусты.
Разберем реализацию восстановления:
&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
КэшФлажков = Неопределено;
Если ЭтаФорма.Параметры.Свойство("ВременноеХранилищеФлажков", КэшФлажков) И КэшФлажков <> Неопределено Тогда
Для Каждого СтрокаТовары Из Объект.Товары Цикл
Состояние = КэшФлажков.Получить(СтрокаТовары.НомерСтроки);
Если Состояние <> Неопределено Тогда
СтрокаТовары.ПереноситьГалочкаТест = Состояние;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Обратите внимание: если ваш документ при записи может пересчитывать строки (например, удалять строки с нулевым количеством), идентификация по НомерСтроки может подвести. В таких случаях рекомендуется заранее добавить в табличную часть (через расширение) скрытый реквизит УникальныйИдентификаторСтроки и использовать его для связи.
Рассмотрим еще один подход, предложенный опытными разработчиками. Если вам нужно, чтобы данные флажков сохранялись даже после закрытия и последующего открытия формы (но при этом вы не хотите менять структуру основной конфигурации), можно использовать системный реквизит объекта с типом ХранилищеЗначения (если такой предусмотрен для доп. сведений или уже существует в документе).
В этом случае в ПередЗаписьюНаСервере вы упаковываете таблицу ваших флажков в ХранилищеЗначения и записываете в объект, а в ПриЧтенииНаСервере — извлекаете и заполняете программную колонку. Это более трудозатратный, но надежный метод для постоянного хранения данных без изменения метаданных табличной части.
Проанализировав все «костыльные» методы с кэшированием, важно упомянуть самый современный и правильный способ решения задачи. Если вы работаете на платформе, поддерживающей расширения конфигурации (версия 8.3.6 и выше), лучше всего добавить нужный реквизит в табличную часть через расширение.
Преимущества этого метода:
Мы рассмотрели механизм работы платформы 1С при записи документа и выяснили, почему программные реквизиты формы требуют особого внимания. Выбор метода — временное кэширование в ПослеЗаписиНаСервере или использование расширений — зависит от ваших бизнес-требований. Если флажки нужны только для разовой обработки (например, группового изменения строк перед записью), достаточно программного кэширования. Если же информация должна храниться долго — используйте механизмы расширений или дополнительные свойства объектов.