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