Как сохранить данные промежуточной формы отбора в 1С 8.3 на управляемых формах?

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

При разработке интерфейсов на управляемых формах в среде «1С:Предприятие 8.3» программисты часто сталкиваются с задачей создания вспомогательных (промежуточных) форм. Яркий пример — самописная форма подбора или детального отбора для динамического списка. Пользователь открывает такую форму, настраивает сложные фильтры, нажимает «ОК», и список перестраивается. Однако при повторном открытии формы отбора пользователь ожидает увидеть ранее введенные им значения. Если их не сохранить, поля окажутся пустыми, что крайне неудобно с точки зрения юзабилити.

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

Способ 1. Использование стандартного механизма сохранения настроек формы

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

Рассмотрим по шагам, как настроить автоматическое сохранение:

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

После этих действий платформа начнет автоматически сохранять значения выбранных реквизитов в системное хранилище настроек при закрытии формы и восстанавливать их при её открытии. Это работает прозрачно для разработчика и сохраняет данные даже между сеансами работы пользователя под своей учетной записью.

Способ 2. Программное сохранение для динамически создаваемых реквизитов

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

Для программного управления сохранением настроек мы должны использовать предопределенные серверные процедуры формы:

Проанализируем пример кода, реализующий этот подход:


&НаСервере
Процедура ПередЗаписьюНастроекНаСервере(Настройки)
    
    // Сохраняем значение динамически созданного реквизита "МойДинамическийОтбор"
    // Настройки - это Структура, предоставляемая платформой
    Настройки.Вставить("ЗначениеДинамическогоОтбора", МойДинамическийОтбор);
    
КонецПроцедуры

&НаСервере
Процедура ПриЗагрузкеНастроекИзХранилищаНаСервере(Настройки)
    
    // Восстанавливаем сохраненное ранее значение
    Если Настройки.Свойство("ЗначениеДинамическогоОтбора") Тогда
        МойДинамическийОтбор = Настройки.ЗначениеДинамическогоОтбора;
    КонецЕсли;
    
КонецПроцедуры

Благодаря этим обработчикам вы полностью контролируете жизненный цикл настроек формы, даже если вся форма генерируется "на лету" из программного кода.

Способ 3. Управление очисткой сохраненных настроек (Сброс при новом открытии)

Иногда автоматическое сохранение работает «слишком хорошо» — данные сохраняются между сеансами работы. Бизнес-требования часто формулируются иначе: "Фильтры должны сохраняться, пока пользователь работает со справочником. Но если пользователь закрыл справочник (или перезапустил программу) и открыл список заново — фильтры должны быть пустыми".

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

Для удаления сохраненных настроек из системного хранилища используется объект ХранилищеНастроекДанныхФорм. Ниже представлен пример процедуры очистки настроек формы отбора:


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

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


ОбщегоНазначения.ХранилищеНастроекДанныхФормУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя);

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

Способ 4. Архитектурно правильный подход (Передача данных через параметры и оповещения)

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

Гораздо более правильным в парадигме управляемого приложения является подход "Глупой формы" (Stateless). Форма отбора не должна сама заботиться о сохранении своих данных. Она должна быть лишь визуальным интерфейсом для изменения структуры, которую ей передали сверху.

Давайте подробно разберем по шагам, как это реализовать:

  1. На форме списка создаем реквизит с типом Структура (или несколько реквизитов под каждый фильтр), где будет храниться текущее состояние отборов.
  2. При нажатии кнопки «Отбор» мы открываем форму отбора программно, передавая накопленный отбор в качестве параметров.
  3. Связываем формы через механизм ОписаниеОповещения, чтобы вернуть измененные значения обратно в форму списка при закрытии.

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


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

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

Теперь посмотрим, как должна выглядеть логика работы внутри самой вспомогательной Формы отбора:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Заполняем реквизиты формы значениями, пришедшими из формы списка
    Если Параметры.Свойство("Контрагент") Тогда
        Контрагент = Параметры.Контрагент;
    КонецЕсли;
    
    Если Параметры.Свойство("Договор") Тогда
        Договор = Параметры.Договор;
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура ПрименитьФильтр(Команда)
    
    // Формируем структуру с измененными значениями для возврата
    Результат = Новый Структура;
    Результат.Вставить("Контрагент", Контрагент);
    Result.Вставить("Договор", Договор);
    
    // Закрываем форму, передавая результат в процедуру оповещения формы списка
    Закрыть(Результат);
    
КонецПроцедуры

Почему данный способ является наилучшим?

← На главную