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