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