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

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

При разработке интерфейсов на платформе 1С:Предприятие 8.3 (Управляемые формы) перед программистами часто встает задача повышения удобства ввода данных. Один из лучших способов облегчить работу пользователя — предоставить ему ограниченный, динамически формируемый список значений прямо в ячейке таблицы. Это исключает необходимость открывать громоздкие модальные окна выбора справочников и минимизирует вероятность ошибок ручного ввода.

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

Выясняем причину ошибки: разбор некорректного кода

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


// НЕРАБОЧИЙ ВАРИАНТ, ВЫЗЫВАЮЩИЙ ОШИБКУ
Элементы.Товары.Реквизит2.СписокВыбора.Добавить("Ракушка");

Или еще более ошибочный вариант попытки обращения к текущим данным строки:


// НЕРАБОЧИЙ ВАРИАНТ
Элементы.Товары.ТекущиеДанные.Реквизит2.СписокВыбора.Добавить("Ракушка");

Почему этот код вызывает ошибку времени выполнения? Давайте разберемся, как устроена объектная модель управляемой формы 1С. Коллекция Элементы содержит элементы управления формы. В этой коллекции таблица формы (в нашем случае Товары) представлена как единый сложный элемент управления типа ТаблицаФормы. У этого объекта действительно есть свойства и методы, но структура колонок таблицы не вложена внутрь объекта таблицы как обычные подчиненные свойства.

Попытка обратиться к свойству Реквизит2 через точку от элемента Товары возвращает Неопределено (или вызывает ошибку отсутствия свойства в зависимости от контекста), так как у объекта ТаблицаФормы нет свойства с именем конкретной колонки. Соответственно, дальнейшая попытка обратиться к свойству СписокВыбора у значения Неопределено закономерно приводит к падению платформы с ошибкой «Значение не является объектного типа (СписокВыбора)».

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

Простое решение: исправляем обращение к элементу формы

Выяснив причину ошибки, мы можем легко исправить обращение. В управляемых формах 1С все элементы формы, включая колонки таблиц, находятся в «плоской» коллекции Элементы на самом верхнем уровне. Имя колонки таблицы формируется по умолчанию как комбинация имени таблицы и имени реквизита (например, ТоварыРеквизит2).

Таким образом, правильное обращение к элементу интерфейса колонки выглядит следующим образом:


// РАБОЧИЙ ВАРИАНТ ИСПРАВЛЕНИЯ
Элементы.ТоварыРеквизит2.СписокВыбора.Добавить("Ракушка");

Этот код успешно отработает без ошибок, так как Элементы.ТоварыРеквизит2 напрямую возвращает объект типа ПолеФормы (с видом ПолеВвода), у которого действительно есть доступное на запись и чтение свойство СписокВыбора, представляющее собой объект типа СписокЗначений.

В чем скрытая опасность «простого» решения?

Казалось бы, решение найдено, код работает, значения добавляются. Но давайте заглянем глубже и проанализируем поведение интерфейса при реальной работе пользователя. С какими подводными камнями мы неизбежно столкнемся?

Элемент формы ТоварыРеквизит2 — это одна колонка для всей таблицы целиком, а не для каждой конкретной ячейки в отдельности. Физически в памяти клиента существует только один объект этого поля формы. Платформа 1С лишь визуально размножает его для отображения строк таблицы.

Если мы будем динамически изменять СписокВыбора этой колонки в зависимости от текущей строки (например, при активизации строки или в начале выбора), то этот список изменится одновременно для всех строк таблицы. Это приводит к следующим неприятным визуальным багам:

  1. Исчезновение значений или подсветка красным. Если в колонке включено свойство РежимВыбораИзСписка (ChoiceListMode), то платформа отображает в ячейках только те значения, которые присутствуют в текущем списке выбора. Как только пользователь перейдет на строку с другим товаром и код перезаполнит список выбора колонки, в предыдущих строках выбранные значения могут пропасть с экрана или подсветиться красным цветом как ошибочные, так как их больше нет в глобальном списке выбора колонки.
  2. Некорректное поведение при быстром вводе. Пользователь может запутаться, если в разных строках при нажатии на кнопку выбора будет отображаться один и тот же список, сформированный для последней активной строки.

Давайте рассмотрим правильные, профессиональные методы решения этой задачи, которые лишены данных недостатков.

Способ №1 (Рекомендуемый): Использование параметра «ДанныеВыбора» в событии «НачалоВыбора»

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

Разберем реализацию этого механизма по шагам. Для этого нам понадобится использовать предопределенный параметр события ДанныеВыбора.


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

Этот подход идеален. Он работает быстро, не требует серверных вызовов (если данные для условий уже есть на клиенте) и никак не портит визуальное отображение данных в других строках табличной части.

Способ №2: Использование параметра «АвтоПодбор» для ввода с клавиатуры

Если пользователь начнет вводить текст в ячейку с клавиатуры, событие НачалоВыбора не сработает. Чтобы обеспечить такое же удобное выпадающее меню при частичном наборе текста, нам необходимо задействовать событие АвтоПодбор у того же поля формы колонки.

Давайте посмотрим, как это реализовать программно:


&НаКлиенте
Процедура ТоварыРеквизит2АвтоПодбор(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, СтандартнаяОбработка)
    
    // Отменяем стандартный поиск по базе данных
    СтандартнаяОбработка = Ложь;
    
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    СписокПодбора = Новый СписокЗначений;
    
    // Формируем список значений
    Если ТекущиеДанные.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Ракушка") Тогда
        СписокПодбора.Добавить("Белая ракушка");
        СписокПодбора.Добавить("Черная ракушка");
    КонецЕсли;
    
    // Фильтруем список по введенному пользователем тексту
    ОтфильтрованныйСписок = Новый СписокЗначений;
    Для Каждого ЭлементСписка Из СписокПодбора Цикл
        // Проверяем, содержится ли введенный текст в значении (без учета регистра)
        Если СтрНайти(ВРег(ЭлементСписка.Значение), ВРег(Текст)) > 0 Тогда
            ОтфильтрованныйСписок.Добавить(ЭлементСписка.Значение);
        КонецЕсли;
    КонецЦикла;
    
    // Передаем отфильтрованные данные в платформу
    ДанныеВыбора = ОтфильтрованныйСписок;
    
КонецПроцедуры

Совместное использование обработчиков НачалоВыбора и АвтоПодбор гарантирует максимально отзывчивый и дружелюбный к пользователю интерфейс.

Способ №3: Без написания кода через «Связи параметров выбора»

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

Выполните следующие шаги в конфигураторе:

  1. Откройте форму, содержащую вашу таблицу, и выберите элемент-колонку (например, ТоварыХарактеристика).
  2. В панели свойств найдите строку «Связи параметров выбора» (Choice parameter links) и нажмите кнопку открытия (три точки).
  3. В открывшемся окне добавьте новую связь:
    • В колонке Имя параметра строки таблицы укажите параметр отбора, например, Отбор.Владелец (так как характеристики подчинены владельцу-номенклатуре).
    • В колонке Поле выбора укажите путь к данным, от которых зависит отбор: Объект.Товары.Номенклатура.
  4. Нажмите «ОК» и сохраните форму.

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

Способ №4: Использование события «ПриАктивизацииСтроки» с отключенным режимом выбора из списка

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

Мы можем реализовать это через обработчик таблицы ПриАктивизацииСтроки. Но чтобы избежать бага с пропаданием текста в неактивных строках, обязательно нужно выполнить важную настройку элемента формы в конфигураторе: свойство «Режим выбора из списка» (ChoiceListMode) у колонки должно быть установлено в значение Ложь, а свойство «Кнопка списка выбора» (Combo button) — в значение Истина.

Посмотрим на пример кода:


&НаКлиенте
Процедура ТоварыПриАктивизацииСтроки(Элемент)
    
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Очищаем и заново заполняем список выбора конкретной колонки
    СписокВыбораКолонки = Элементы.ТоварыРеквизит2.СписокВыбора;
    СписокВыбораКолонки.Очистить();
    
    Если ТекущиеДанные.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Ракушка") Тогда
        СписокВыбораКолонки.Добавить("Ракушка белая");
        СписокВыбораКолонки.Добавить("Ракушка черная");
    Иначе
        СписокВыбораКолонки.Добавить("Другой товар");
    КонецЕсли;
    
КонецПроцедуры

Благодаря тому, что режим выбора из списка отключен (ChoiceListMode = Ложь), платформа не будет валидировать значения в других строках по текущему составу списка выбора колонки. Текст в неактивных строках останется видимым и не будет подсвечиваться красным цветом.

Резюме и рекомендации

Мы подробно проанализировали проблему ручного добавления значений в список выбора таблицы формы. Простая ошибка в адресации к элементу формы легко исправляется правильным обращением к коллекции Элементы. Однако для создания качественных и надежных решений всегда стоит смотреть на шаг вперед.

Для динамических списков в таблицах рекомендуется использовать Способ №1 (событие НачалоВыбора) — он наиболее надежен, не вызывает визуальных багов в соседних строках и полностью соответствует стандартам разработки фирмы 1С. Если же ваши данные связаны отношениями подчинения в базе данных, всегда отдавайте предпочтение декларативному методу через Связи параметров выбора (Способ №3).

← На главную