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