Как правильно создать динамические колонки таблицы значений на обычной форме в 1С?

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

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

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

Анализ проблемы: почему пропадают колонки при заполнении

Проанализируем типовую ситуацию. Разработчик объявляет колонки при инициализации формы следующим образом:


Процедура ПриОткрытии()
    Товары.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка",,, Новый КвалификаторыСтроки(25)),, 10);
    Товары.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
    Товары.Колонки.Добавить("ЕдиницаИзмерения", Новый ОписаниеТипов("СправочникСсылка.ЕдиницыИзмерения"), "Ед. изм", 7);
    Товары.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(12, 2)),, 8);
    
    ЭлементыФормы.Товары.Значение = Товары;    
    ЭлементыФормы.Товары.СоздатьКолонки();
КонецПроцедуры

После открытия формы визуально все колонки находятся на своих местах. Однако при последующем выполнении алгоритма заполнения (например, при считывании внешнего файла или добавлении строки через Товары.Добавить()) платформа генерирует исключение: поле или колонка не обнаружена. В отладчике при этом видно, что в ЭлементыФормы.Товары.Колонки список колонок полный, а в коллекции Товары.Колонки созданных полей нет.

Выясним причину этой ошибки. В платформе 1С:Предприятие для обычных форм табличное поле связывается по ссылке с конкретным экземпляром объекта ТаблицаЗначений в оперативной памяти. Если где-то далее по коду (в процедуре загрузки, по нажатию кнопки или при расчете данных) выполняется повторная инициализация переменной вида:

Товары = Новый ТаблицаЗначений;

или переприсваивание результата выполнения другой функции:

Товары = ПолучитьТаблицуИзФайла();

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

Способ 1: Устранение переопределения переменной таблицы

Посмотрим на пример правильной работы с коллекцией данных без разрушения объектной ссылки. Чтобы не терять динамически созданную структуру колонок, ни в коем случае нельзя повторно создавать объект через конструктор Новый или переприсваивать реквизит.

  1. Для очистки данных перед загрузкой используем стандартный метод очистки существующей таблицы: Товары.Очистить();
  2. Если необходимо перенести данные из временной таблицы значений, полученной из другого источника или запроса, применяем метод загрузки строк: Товары.Загрузить(ВременнаяТаблицаЗначений); Метод Загрузить() копирует данные строк по совпадению имен колонок, не изменяя саму ссылку на исходный объект ТаблицаЗначений.
  3. Если в свойствах табличного поля в конфигураторе уже заполнено свойство Данные (указан реквизит Товары), строка ЭлементыФормы.Товары.Значение = Товары является избыточной. Привязка уже установлена платформой автоматически.

Способ 2: Настройка интерактивного выбора данных в динамических колонках

Вторая частая проблема: колонки на форме созданы, строки добавляются, но при попытке интерактивного ввода значений (например, при выборе номенклатуры) поле ячейки не открывает форму выбора или заблокировано для редактирования.

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

Разберем по шагам, как обеспечить полную интерактивность создаваемых колонок:

  1. Включение кнопки выбора для ссылочных типов. Если для колонки задан ссылочный тип (например, СправочникСсылка.Номенклатура), у элемента управления ячейки необходимо явно включить кнопку выбора:
    
    КолонкаНоменклатура = ЭлементыФормы.Товары.Колонки.Номенклатура;
    КолонкаНоменклатура.ЭлементУправления.КнопкаВыбора = Истина;
    
  2. Проверка прав на редактирование. Убедимся, что для самого табличного поля и созданных колонок не выставлены запреты на изменение данных:
    
    ЭлементыФормы.Товары.ТолькоПросмотр = Ложь;
    ЭлементыФормы.Товары.ИзменятьЗначения = Истина;
    ЭлементыФормы.Товары.ИзменятьСоставСтрок = Истина;
    
  3. Исключение типа Null из описания типов. Если описание типов для колонки формируется динамически или передается из результата запроса, убедитесь, что в нем отсутствует тип Null. При наличии типа Null платформа блокирует интерактивный выбор в пустых ячейках.

Способ 3: Явное программное добавление колонок в табличное поле

Для полного контроля над визуальными свойствами и поведением элементов управления надежнее отказаться от автоматического вызова СоздатьКолонки() и создавать колонки табличного поля вручную. Это гарантирует правильное сопоставление данных и типов ввода.

Рассмотрим итоговый пример надежной инициализации структуры таблицы значений и табличного поля:


Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
    
    // 1. Очищаем старые колонки визуального элемента управления
    ЭлементыФормы.Товары.Колонки.Очистить();
    
    // 2. Создаем структуру колонок в источнике данных (ТаблицаЗначений)
    Товары.Колонки.Очистить();
    Товары.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка",,, Новый КвалификаторыСтроки(25)), "Артикул", 10);
    Товары.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Номенклатура", 25);
    Товары.Колонки.Добавить("ЕдиницаИзмерения", Новый ОписаниеТипов("СправочникСсылка.ЕдиницыИзмерения"), "Ед. изм.", 8);
    Товары.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(15, 2)), "Цена", 10);
    
    // 3. Формируем колонки табличного поля и связываем их с источником данных
    Для Каждого КолонкаТЗ Из Товары.Колонки Цикл
        
        КолонкаТП = ЭлементыФормы.Товары.Колонки.Добавить(КолонкаТЗ.Имя, КолонкаТЗ.Заголовок);
        КолонкаТП.Данные = КолонкаТЗ.Имя;
        КолонкаТП.Ширина = КолонкаТЗ.Ширина;
        КолонкаТП.ИзменениеРазмера = ИзменениеРазмераКолонки.НеИзменять;
        КолонкаТП.ТолькоПросмотр = Ложь;
        
        // Настраиваем поле ввода для ячейки
        КолонкаТП.УстановитьЭлементУправления(Тип("ПолеВвода"));
        
        // Включаем кнопку выбора для ссылочных данных
        Если КолонкаТЗ.ТипЗначения.СодержитТип(Тип("СправочникСсылка.Номенклатура"))
            Или КолонкаТЗ.ТипЗначения.СодержитТип(Тип("СправочникСсылка.ЕдиницыИзмерения")) Тогда
            КолонкаТП.ЭлементУправления.КнопкаВыбора = Истина;
        КонецЕсли;
        
    КонецЦикла;
    
    // Настраиваем общие параметры табличного поля
    ЭлементыФормы.Товары.ФиксацияСлева = 2;
    
КонецПроцедуры

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

← На главную