Почему не устанавливается ограничение типа данных для поля управляемой формы 1С и как это исправить?

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

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

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

Выясняем причину: разница между свойствами ДоступныеТипы и ОграничениеТипа

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

  1. Свойство ДоступныеТипы (AvailableTypes) — это расширение поля ввода, которое доступно и работоспособно только в том случае, если сам реквизит, с которым связано это поле на форме, имеет тип данных ОписаниеТипов. Данное свойство используется, например, когда пользователю нужно предоставить интерфейс для выбора самого типа данных (как при настройке субконто или видов характеристик).
  2. Свойство ОграничениеТипа (TypeRestriction) — это именно то свойство, которое необходимо использовать, если реквизит формы имеет составной тип данных (например, ЛюбаяСсылка, СправочникСсылка.Номенклатура или содержит несколько возможных документов), и нам требуется ограничить этот список на уровне конкретного элемента интерфейса.

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

Почему «ничего не происходит» при ВыбиратьТип = Ложь

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

Проанализируем ситуацию на уровне данных:

  1. В новой строке таблицы или в новом реквизите формы значение поля изначально не заполнено, то есть его значение равно Неопределено.
  2. При нажатии на кнопку выбора платформа видит, что тип значения не определен. Ей нужно понять, форму какого именно объекта открывать.
  3. Так как мы установили ВыбиратьТип = Ложь, мы запретили платформе показывать стандартное диалоговое окно выбора типа.
  4. В результате возникает логический тупик: тип значения равен Неопределено, ограничение на элементе формы напрямую не меняет тип самого значения в источнике данных, а интерактивно выбрать тип нельзя. Платформа просто отменяет дальнейшие действия, и визуально ничего не происходит.

Если же мы временно установим ВыбиратьТип = Истина, то при первом нажатии платформа предложит выбрать тип (даже если он ограничен одним значением), после чего запишет в реквизит пустую ссылку этого типа, и при последующих кликах форма выбора будет открываться мгновенно.

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

Способ 1. Использование ОграничениеТипа и метода ПривестиЗначение()

Рассмотрим наиболее универсальный и надежный метод. Мы заменим использование ошибочного свойства ДоступныеТипы на ОграничениеТипа, а также применим метод ПривестиЗначение() объекта ОписаниеТипов для того, чтобы автоматически инициализировать пустое значение реквизита нужным типом.

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


// 1. Создаем описание типов для ограничения выбора
ОписаниеТипаСправочникНоменклатура = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");

// 2. Устанавливаем корректное ограничение типа для элементов формы
Элементы.Таблица2Номенклатура.ОграничениеТипа = ОписаниеТипаСправочникНоменклатура;
Элементы.Таблица2Номенклатура.ВыбиратьТип = Ложь;

Элементы.Таблица3МатериалыНоменклатура.ОграничениеТипа = ОписаниеТипаСправочникНоменклатура;
Элементы.Таблица3МатериалыНоменклатура.ВыбиратьТип = Ложь;

// 3. Приводим текущие значения в строках таблиц к нужному типу
// Это действие гарантирует, что значение "Неопределено" превратится в пустую ссылку Номенклатуры
ТекущиеДанныеТаблицы2 = Элементы.Таблица2.ТекущиеДанные;
Если ТекущиеДанныеТаблицы2 <> Неопределено Тогда
    ТекущиеДанныеТаблицы2.Номенклатура = ОписаниеТипаСправочникНоменклатура.ПривестиЗначение(ТекущиеДанныеТаблицы2.Номенклатура);
КонецЕсли;

ТекущиеДанныеТаблицы3 = Элементы.Таблица3Материалы.ТекущиеДанные;
Если ТекущиеДанныеТаблицы3 <> Неопределено Тогда
    ТекущиеДанныеТаблицы3.Номенклатура = ОписаниеТипаСправочникНоменклатура.ПривестиЗначение(ТекущиеДанныеТаблицы3.Номенклатура);
КонецЕсли;

Метод ПривестиЗначение() работает очень аккуратно: если в реквизите уже выбрана конкретная номенклатура, она останется нетронутой. Если же там хранилось значение Неопределено (или значение неподходящего типа), метод вернет пустую ссылку справочника Номенклатура. Благодаря этому тип значения будет четко определен, и кнопка выбора сработает штатно.

Способ 2. Инициализация пустой ссылкой при создании строки

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

Посмотрим, как реализовать это в обработчике события таблицы ПриНачалеРедактирования на клиенте:


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

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

Аналогичные проблемы: механизм «Связь по типу»

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

Решается это абсолютно аналогично — в обработчике события ПриИзменении ведущего реквизита необходимо программно очищать ведомый реквизит, приводя его к первому доступному типу или заполняя пустой ссылкой нового разрешенного типа.

Резюме и правила хорошего тона для разработчика

Чтобы избежать подобных интерфейсных тупиков в управляемых формах 1С, рекомендуем придерживаться следующих правил:

  1. Для ограничения выбора в реквизитах составного типа всегда используйте свойство элемента формы ОграничениеТипа вместо ДоступныеТипы.
  2. Если вы отключаете выбор типа через ВыбиратьТип = Ложь, всегда обеспечивайте программное заполнение реквизита пустой ссылкой нужного типа до того, как пользователь нажмет кнопку выбора.
  3. Используйте метод ОписаниеТипов.ПривестиЗначение() при активизации строк или инициализации данных, чтобы корректно преобразовывать Неопределено в пустые ссылки без потери уже выбранных данных.
← На главную