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

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

В процессе разработки на платформе 1С:Предприятие 8 часто возникает необходимость временно изменить данные в табличной части (например, для специфического алгоритма расчета или печати чека с корректировками), а затем вернуть всё в исходное состояние. Основная сложность заключается в том, что на управляемом клиенте коллекция ДанныеФормыКоллекция (которой является табличная часть) не имеет метода Выгрузить() в привычную таблицу значений, а прямое копирование ссылок не создает независимого «слепка» данных.

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

Способ 1. Передача на сервер и использование временной Таблицы Значений

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

Рассмотрим реализацию через функции на сервере:


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

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

Этот метод хорош тем, что ЗначениеВРеквизитФормы корректно обрабатывает типы данных и связи. Однако помните, что хранить саму ТаблицуЗначений на клиенте нельзя — при передаче с сервера на клиент она должна быть либо помещена во временное хранилище, либо сериализована.

Способ 2. Сериализация в строку (ЗначениеВСтрокуВнутр или JSON)

Если вам нужно сохранить состояние таблицы в обычную переменную на клиенте, можно прибегнуть к сериализации. Ранее часто использовался метод ЗначениеВСтрокуВнутр, но в современных версиях платформы более правильным считается использование JSON.

Разберем алгоритм с использованием ЗначениеВСтрокуВнутр, как предлагалось в обсуждении:


&НаСервере
Функция ПолучитьСтрокуДанныхНаСервере()
    ТЗ = Объект.Товары.Выгрузить();
    Возврат ЗначениеВСтрокуВнутр(ТЗ);
КонецФункции

&НаСервере
Процедура ВосстановитьИзСтрокиНаСервере(СтрокаДанных)
    ТЗ = ЗначениеИзСтрокиВнутр(СтрокаДанных);
    Объект.Товары.Загрузить(ТЗ);
КонецПроцедуры

Важный нюанс: Метод ЗначениеВСтрокуВнутр является системным и его формат может меняться в разных версиях платформы. Для долгосрочного хранения данных лучше использовать СериализаторXDTO или JSON-сериализацию. Для кратковременного «слепка» в рамках одного сеанса работы формы этот метод вполне допустим.

Способ 3. Создание массива структур на клиенте

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

Проанализируем пример кода для клиентской части:


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

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

Способ 4. Использование временного хранилища

Это «золотой стандарт» для временного хранения больших объемов данных между вызовами сервера. Мы помещаем таблицу значений в хранилище и оперируем только адресом (строкой).

Рассмотрим шаги реализации:

  1. На сервере выгружаем ТЧ в таблицу значений.
  2. Используем функцию ПоместитьВоВременноеХранилище(ТЗ, ЭтаФорма.УникальныйИдентификатор). Передача идентификатора формы гарантирует, что данные будут очищены автоматически при закрытии формы.
  3. Сохраняем адрес в реквизит формы (типа Строка).
  4. При необходимости восстановления извлекаем ТЗ по адресу и загружаем обратно.

Способ 5. Скрытый реквизит формы

Иногда проще всего добавить на форму еще один реквизит с типом «Таблица значений» (или аналогичную коллекцию ДанныеФормыКоллекция), но не выносить его в элементы формы.

Разберем, почему это удобно:

Для копирования данных между основным и вспомогательным реквизитами на сервере используйте метод Объект.Товары.Выгрузить() и ВспомогательнаяТаблица.Загрузить().

Важные замечания по модифицированности формы

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

Если вы не хотите, чтобы при закрытии формы программа спрашивала «Данные были изменены. Сохранить?», обязательно сбросьте этот флаг после завершения всех манипуляций:

ЭтаФорма.Модифицированность = Ложь;

Однако будьте осторожны: если пользователь действительно что-то менял в документе до вашего алгоритма, жесткая установка в Ложь приведет к потере его данных без предупреждения.

Альтернативный архитектурный подход

Как справедливо заметили участники обсуждения, манипуляции с экранной формой — это всегда риск «уронить» интерфейс или запутать пользователя. Рассмотрим более чистый подход: Печать из копии объекта.

Вместо того чтобы менять данные в текущем объекте формы, выполните следующие действия на сервере:

  1. Создайте копию текущего объекта: КопияОбъекта = РеквизитФормыВЗначение("Объект").Скопировать();
  2. В КопияОбъекта измените цены по вашему алгоритму.
  3. Вызовите процедуру печати или пробития чека, передав туда КопияОбъекта.
  4. Ничего не записывайте в базу данных.

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

← На главную