При работе с обычными формами в 1С часто возникает задача программно добавить временную колонку в табличную часть документа. Например, вам может потребоваться дополнительное поле для ввода комментария или других данных, которые нужны только для текущей сессии работы с формой и не должны сохраняться в базе данных. Однако, пользователи часто сталкиваются с тем, что добавленная колонка остается пустой, а данные в нее не записываются или не отображаются корректно. Мы рассмотрим эту проблему подробно и предложим решения.
Когда вы программно добавляете колонку в табличное поле обычной формы, например, с помощью методов типа Форма.ЭлементыФормы.Товары.Колонки.Добавить(...), вы создаете лишь визуальный элемент. Эта колонка не имеет автоматической связи с источником данных, который бы ее заполнял или сохранял введенные значения. В отличие от управляемых форм, где многие вещи происходят "магически" благодаря декларативному подходу, в обычных формах требуется более явное управление данными.
Давайте выясним основные причины, по которым данные не отображаются, и что необходимо сделать:
ПолеВвода.Для начала, давайте посмотрим, как правильно добавить колонку и назначить ей элемент управления. В первом сообщении автор пытался установить тип значения колонки напрямую, что не сработало для отображения данных. Правильный подход включает создание колонки и установку для нее элемента управления:
// Добавляем колонку в табличную часть 'Товары'
Перем НоваяКолонка;
НоваяКолонка = Форма.ЭлементыФормы.Товары.Колонки.Добавить("ТипКонтакта", "Тип контакта");
// Устанавливаем элемент управления для новой колонки
// Это необходимо, чтобы в ней можно было что-то вводить или отображать
// Если нужен выбор из справочника, то тип значения ПолеВвода будет работать с ним
НоваяКолонка.УстановитьЭлементУправления(Тип("ПолеВвода"));
// Можно также задать заголовок и ширину
НоваяКолонка.Заголовок = "Тип контакта (временный)";
НоваяКолонка.Ширина = 20;
// Если нужно, чтобы колонка была доступна для редактирования
НоваяКолонка.Доступность = Истина;
Однако, даже после этих действий колонка будет пустой, и введенные вручную данные не будут сохраняться при прокрутке или обновлении формы. Это происходит потому, что данные не имеют постоянного места хранения.
Для работы с временными данными в программно добавленных колонках в обычных формах мы применяем двухэтапный подход:
ТаблицаЗначений. Эта таблица будет хранить данные для нашей временной колонки, сопоставляя их со строками основной табличной части документа.ПриВыводеСтроки или ПриПолученииДанных, чтобы брать информацию из нашей временной ТаблицыЗначений и отображать ее в программно добавленной колонке.Давайте разберем этот процесс по шагам.
Прежде всего, нам нужен контейнер для наших временных данных. Мы добавляем новый реквизит формы, который будет иметь тип ТаблицаЗначений. Он не будет виден на форме напрямую, но будет служить хранилищем. Важно, чтобы у этой таблицы значений была колонка, которая может служить "ключом" для сопоставления со строками основной табличной части документа (например, номер строки или ссылка на объект).
// В модуле формы (например, в процедуре ПриОткрытии или при инициализации)
// Добавляем реквизит формы, если его нет
// Для этого нужно изменить реквизиты формы, что требует изменения конфигурации
// Если изменение конфигурации невозможно, то можно использовать глобальную переменную модуля формы
// (но это менее предпочтительно, так как не будет видно в отладчике как реквизит формы)
// Предположим, что мы можем добавить реквизит формы через ИзменитьРеквизиты
// Это делается на сервере и приводит к изменению структуры формы.
// Если же это не вариант, используем просто переменную модуля формы.
// Например: Перем ВременныеДанныеКолонки Экспорт;
// Пример добавления реквизита формы:
// Требует серверного вызова и прав на изменение реквизитов формы.
// Обычно делается в ПриСозданииНаСервере или при открытии формы
// Если мы не можем менять конфигурацию, то пропустим этот шаг и будем использовать просто глобальную переменную
// модуля формы:
// Перем ВременныеДанныеКолонки; // Объявляем в начале модуля формы
// В процедуре ПриОткрытии()
// ВременныеДанныеКолонки = Новый ТаблицаЗначений;
// ВременныеДанныеКолонки.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число")); // Ключ для связи
// ВременныеДанныеКолонки.Колонки.Добавить("ЗначениеКолонки", Новый ОписаниеТипов("Строка")); // Или нужный тип
// Если колонка должна быть справочником, то:
// ВременныеДанныеКолонки.Колонки.Добавить("ЗначениеКолонки", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
В случае, если изменение реквизитов формы или добавление глобальных переменных в модуль формы документа невозможно из-за ограничений типовой конфигурации (как в случае автора), тогда вам придется использовать *внешнюю обработку*, которая может создать свою собственную ТаблицуЗначений и передавать данные в/из формы. Однако, для *отображения* этих данных на форме, мы все равно приходим к необходимости использования обработчиков событий.
Как мы уже обсудили, добавляем колонку и устанавливаем для нее элемент управления. Это обычно делается в процедуре ПриОткрытии() формы документа.
// В процедуре ПриОткрытии() формы документа
Перем НоваяКолонка;
НоваяКолонка = Форма.ЭлементыФормы.Товары.Колонки.Добавить("ВременнаяКолонка", "Моя временная колонка");
НоваяКолонка.УстановитьЭлементУправления(Тип("ПолеВвода")); // Для возможности ввода
НоваяКолонка.Доступность = Истина;
НоваяКолонка.Редактировать = Истина; // Разрешаем редактирование
// Если колонка должна отображать справочник, то можно указать тип
// Внимание: Тип здесь влияет на визуальное представление (кнопка выбора, отбор),
// но данные все равно будут браться из нашей ВременныеДанныеКолонки
НоваяКолонка.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");
После открытия формы или после загрузки данных основной табличной части, нам нужно заполнить нашу вспомогательную ТаблицуЗначений. Мы можем инициализировать ее пустыми строками, соответствующими количеству строк в основной табличной части, или заполнить данными из какого-либо внешнего источника.
// В процедуре ПриОткрытии() или ПриЗагрузкеДанных() после загрузки основной табличной части
// Предполагаем, что ВременныеДанныеКолонки - это реквизит формы или глобальная переменная модуля формы
ВременныеДанныеКолонки.Очистить();
Для Каждого СтрокаТЧ Из Объект.Товары Цикл // Объект - это сам документ
НоваяСтрока = ВременныеДанныеКолонки.Добавить();
// Мы можем использовать УникальныйИдентификатор строки табличной части
// или ее номер для связывания. Номер строки - более простой вариант для обычных форм.
НоваяСтрока.НомерСтроки = ВременныеДанныеКолонки.Количество(); // Номер строки в ТаблицеЗначений
НоваяСтрока.ЗначениеКолонки = ""; // Начальное пустое значение или значение по умолчанию
КонецЦикла;
Это самый критичный шаг. Мы используем событие табличного поля, чтобы "нарисовать" данные в нашей временной колонке. Для этого нам потребуется добавить соответствующий обработчик в модуль формы документа. Это действие требует изменения конфигурации.
// В модуле формы документа, в процедуре-обработчике события табличного поля "Товары"
// Процедура ТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// // Определяем индекс строки в основной табличной части
// Перем НомерСтрокиТЧ;
// Если ТипЗнч(ДанныеСтроки.Ссылка) = Тип("ДокументСсылка.ИмяВашегоДокумента") Тогда
// // Если ДанныеСтроки привязана к объекту, можно найти по УИД, но в ОФ чаще проще по индексу
// // Проще всего найти по индексу или по уникальному идентификатору, если такой есть.
// // В ОФ часто просто ДанныеСтроки.НомерСтроки - это индекс в видимой ТЧ.
// НомерСтрокиТЧ = ДанныеСтроки.НомерСтроки;
// Иначе
// // Если источник данных не ссылка на объект, а например, ТаблицаЗначений
// НомерСтрокиТЧ = ДанныеСтроки.НомерСтроки;
// КонецЕсли;
// // Находим соответствующую строку в нашей временной ТаблицеЗначений
// Перем НайденнаяСтрока;
// НайденнаяСтрока = ВременныеДанныеКолонки.Найти(НомерСтрокиТЧ, "НомерСтроки");
// Если НайденнаяСтрока <> Неопределено Тогда
// // Устанавливаем значение для нашей программно добавленной колонки
// ОформлениеСтроки.Ячейки.ВременнаяКолонка.Значение = НайденнаяСтрока.ЗначениеКолонки;
// // Если колонка должна быть редактируемой, нужно обрабатывать ввод пользователя.
// // Для обычных форм это обычно делается через обработчик "ПриИзменении"
// // или "ПриОкончанииРедактирования" для самого табличного поля,
// // где мы перехватываем изменение и обновляем нашу ВременныеДанныеКолонки.
// КонецЕсли;
// КонецПроцедуры
// Более надежный способ для получения номера строки в ОФ:
// Процедура ТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Перем ИндексСтроки;
// ИндексСтроки = Элемент.ТекущиеДанные.НомерСтроки - 1; // НомерСтроки начинается с 1
// Если ИндексСтроки >= 0 И ИндексСтроки < ВременныеДанныеКолонки.Количество() Тогда
// // Получаем строку из нашей временной ТаблицыЗначений по индексу
// Перем СтрокаВременныхДанных;
// СтрокаВременныхДанных = ВременныеДанныеКолонки[ИндексСтроки];
//
// // Устанавливаем значение в ячейку программно добавленной колонки
// ОформлениеСтроки.Ячейки.ВременнаяКолонка.Значение = СтрокаВременныхДанных.ЗначениеКолонки;
// КонецЕсли;
// КонецПроцедуры
// Если нам нужно, чтобы пользователь мог ВВОДИТЬ данные,
// то помимо ПриВыводеСтроки, нужно еще обрабатывать событие ПриОкончанииРедактирования
// табличного поля, чтобы сохранить введенные данные в нашу ВременныеДанныеКолонки.
// Процедура ТоварыПриОкончанииРедактирования(Элемент, НоваяСтрока, Колонка, Отказ)
// Если Колонка.Имя = "ВременнаяКолонка" Тогда
// Перем ИндексСтроки;
// ИндексСтроки = Элемент.ТекущиеДанные.НомерСтроки - 1;
//
// Если ИндексСтроки >= 0 И ИндексСтроки < ВременныеДанныеКолонки.Количество() Тогда
// Перем СтрокаВременныхДанных;
// СтрокаВременныхДанных = ВременныеДанныеКолонки[ИндексСтроки];
// СтрокаВременныхДанных.ЗначениеКолонки = Элемент.ТекущиеДанные.ВременнаяКолонка;
// КонецЕсли;
// КонецЕсли;
// КонецПроцедуры
// Внимание: Чтобы Элемент.ТекущиеДанные.ВременнаяКолонка была доступна для чтения,
// нужно, чтобы у табличного поля 'Товары' было свойство 'Данные' привязано
// к источнику, который МОЖЕТ иметь этот реквизит. Но если колонка полностью динамическая
// и не является реквизитом источника, то прямое чтение через ТекущиеДанные
// может не работать. В этом случае придется считывать значение из самой ячейки
// или из элемента управления колонки.
// Однако, часто проще всего сохранить значение, которое пользователь ввел,
// прямо в обработчике ПриОкончанииРедактирования, используя прямое присвоение
// значения, которое ПОЛЬЗОВАТЕЛЬ ввел.
// То есть, Элемент.ТекущаяКолонка.ТекущееЗначение() или подобное.
Обработчик ПриПолученииДанных может использоваться для более оптимизированного заполнения, когда данные для нескольких строк готовятся заранее, что может быть полезно для больших таблиц.
Важный момент: Использование обработчиков ПриВыводеСтроки и ПриПолученииДанных для табличного поля требует добавления этих процедур в модуль формы документа через конфигуратор. Это является изменением типовой конфигурации.
Автор в обсуждении ясно выразил свое нежелание (или невозможность) изменять типовую конфигурацию, а именно – добавлять обработчики событий в модуль формы документа. Это создает существенное препятствие, поскольку описанный выше классический подход является основным для интерактивного отображения и ввода временных данных в обычных формах.
Давайте проанализируем ситуацию:
ПриВыводеСтроки/ПриПолученииДанных без изменения конфигурации:
Без модификации модуля формы документа мы не можем добавить обработчики событий, которые позволяют динамически устанавливать значения ячеек при их отображении. Эти обработчики – единственный надежный механизм для "рисования" временных данных в колонках табличного поля.
В отличие от управляемых форм, где мы можем динамически добавлять реквизиты формы и связывать их с колонками табличных полей, в обычных формах такой прямой механизм для табличных частей документа отсутствует. Колонки табличной части жестко привязаны к реквизитам этой табличной части или к специальным системным колонкам (например, для сумм).
Если мы просто добавим колонку и попытаемся записать в нее значение через ТекущиеДанные.ИмяКолонки = Значение;, это не сработает, потому что ИмяКолонки не является реквизитом ни объекта документа, ни его табличной части, ни даже реквизитом самой формы, к которому было бы привязано табличное поле. Это лишь визуальная колонка без источника данных.
Вывод по ограничению: Если категорически запрещено изменять конфигурацию (включая добавление обработчиков событий в модуль формы), то реализовать интерактивный ввод и отображение временных данных в программно добавленной колонке табличной части **невозможно** напрямую. Любой механизм, который позволяет вам управлять отображением или записью данных в ячейку табличного поля, требует либо:
Если эти два пути закрыты, мы вынуждены искать обходные пути, которые, скорее всего, изменят саму концепцию задачи:
ТаблицаЗначений на форме). В этой таблице вы могли бы создать нужные колонки, а затем заполнить их данными из документа. Пользователь вводил бы данные в этой отдельной форме, а по нажатию кнопки эти данные могли бы быть использованы или перенесены в документ каким-либо другим способом (например, через временные файлы или через регистр сведений, если нужно временно хранить в базе).
Подводя итог, для программного добавления временной колонки в табличную часть формы документа в обычных формах 1С и обеспечения ее интерактивного поведения (отображение, ввод данных), **обязательно требуется** использование обработчиков событий ПриВыводеСтроки (для отображения) и ПриОкончанииРедактирования (для сохранения ввода пользователя) с использованием временного хранилища данных (например, ТаблицыЗначений). Это действие подразумевает изменение конфигурации, в частности, модуля формы документа. Без таких изменений, задача становится крайне сложной или невыполнимой в рамках интерактивной работы с табличным полем на форме.