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