В практике разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуациями, когда стандартные механизмы ведут себя непредсказуемо. Одной из таких проблем является работа составного типа данных (например, когда реквизит может принимать значения нескольких типов документов и перечислений) именно в колонках табличной части управляемой формы. В то время как на основной форме такой реквизит работает безупречно, в таблице выбор перечисления может просто «зависать» или требовать повторного выбора типа. Проанализируем, почему это происходит и какими способами можно победить данное поведение системы.
Данная проблема не является ошибкой в коде разработчика — это подтвержденный баг платформы 1С, который проявлялся в определенных релизах ветки 8.3.15 (особенно в версии 8.3.15.1700). Суть ошибки заключается в некорректной передаче фокуса и обработки модальных окон выбора типа данных внутри ячеек табличного поля. Когда мы выбираем тип «Перечисление» в системном окне, платформа должна мгновенно инициализировать выпадающий список значений этого перечисления. Однако в проблемных сборках контекст выбора теряется, и вместо списка значений пользователь снова видит окно выбора типа или вовсе пустую реакцию интерфейса.
Если в вашей организации запрещено оперативное обновление платформы (аргумент «работает — не трогай»), нам придется искать программные пути обхода этого ограничения. Рассмотрим несколько стратегий решения задачи.
Самый быстрый способ заставить систему работать — это перехватить момент, когда пользователь уже выбрал тип «Перечисление», и принудительно показать ему список доступных значений. Для этого мы воспользуемся событием ПриИзменении для элемента управления в колонке таблицы.
Разберем логику работы: когда срабатывает событие изменения, мы проверяем, к какому типу относится выбранное значение. Если это наше проблемное перечисление, мы программно формируем список всех его значений и предлагаем пользователю выбрать одно из них через метод ВыбратьИзСписка. Рассмотрим пример реализации:
&НаКлиенте
Процедура ТабличнаяЧасть1Реквизит1ПриИзменении(Элемент)
ТекущаяСтрока = Элементы.ТабличнаяЧасть1.ТекущиеДанные;
// Проверяем, что в реквизит попало значение нужного типа перечисления
Если ТипЗнч(ТекущаяСтрока.Реквизит1) = Тип("ПеречислениеСсылка.СостоянияЗаказов") Тогда
// Получаем список значений (на сервере или подготовить заранее)
СписокВыбора = ПолучитьСписокЗначенийПеречисления();
// Вызываем интерактивное окно выбора из созданного списка
ВыбранноеЗначение = ВыбратьИзСписка(СписокВыбора, Элемент);
// Если пользователь выбрал значение, записываем его в данные
Если ВыбранноеЗначение <> Неопределено Тогда
ТекущаяСтрока.Реквизит1 = ВыбранноеЗначение.Значение;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьСписокЗначенийПеречисления()
Список = Новый СписокЗначений;
// Обходим метаданные перечисления для автоматизации
Для Каждого ЗначениеИзМетаданных Из Метаданные.Перечисления.СостоянияЗаказов.ЗначенияПеречисления Цикл
ИмяЗначения = ЗначениеИзМетаданных.Имя;
Список.Добавить(Перечисления.СостоянияЗаказов[ИмяЗначения]);
КонецЦикла;
Возврат Список;
КонецФункции
Важный нюанс: использование события ПриИзменении может привести к тому, что пользователю придется нажимать лишний раз. Однако это гарантированно «проталкивает» выбор в тех версиях платформы, где стандартный механизм сломан.
Более элегантный и «чистый» способ с точки зрения UX — использование события НачалоВыбора (StartChoice). Этот метод позволяет нам вмешаться в процесс еще до того, как платформа попытается открыть стандартное окно выбора типа. Проанализируем ситуацию: если мы знаем, что пользователю чаще всего нужно именно перечисление, или мы хотим полностью контролировать процесс выбора типов, мы можем установить параметр СтандартнаяОбработка = Ложь.
Давайте посмотрим, как можно реализовать этот механизм:
&НаКлиенте
Процедура ТабличнаяЧасть1Реквизит1НачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Если мы хотим полностью заменить стандартный выбор:
СтандартнаяОбработка = Ложь;
// Создаем свой список типов, включая документы и перечисления
СписокТипов = Новый СписокЗначений;
СписокТипов.Добавить("ТипПеречисление", "Выбрать состояние (Перечисление)");
СписокТипов.Добавить("ТипДокумент", "Выбрать документ (Реализация)");
// Предлагаем пользователю сначала выбрать категорию
ВыбранныйТип = ВыбратьИзСписка(СписокТипов, Элемент);
Если ВыбранныйТип <> Неопределено Тогда
Если ВыбранныйТип.Значение = "ТипПеречисление" Тогда
// Вызываем программный выбор перечисления, как в первом способе
ПоказатьВыборПеречисления(Элемент);
Иначе
// Открываем стандартную форму выбора документа
ОткрытьФормуВыбораДокумента(Элемент);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Использование НачалоВыбора предотвращает появление бажного системного диалога и делает интерфейс более предсказуемым для конечного пользователя.
Иногда проблему удается решить без написания сложного программного кода, просто изменив настройки отображения элемента в конфигураторе или программно при создании формы. Проанализируем влияние свойств БыстрыйВыбор (QuickChoice) и КнопкаСпискаВыбора (ChoiceListButton).
Рассмотрим пошагово, что нужно сделать:
Да.Почему это помогает? Когда включен «Быстрый выбор», платформа пытается сразу подгрузить доступные значения, минуя сложные модальные переходы. Для составного типа это может работать нестабильно, но в сочетании с перечислением часто исправляет ошибку отрисовки выпадающего списка в ячейке таблицы.
Если ни один из программных методов не дает 100% стабильности на вашем релизе платформы, рекомендуем рассмотреть вариант изменения структуры данных. Вместо одного реквизита с составным типом (Документ + Перечисление) можно использовать два отдельных поля, визуально объединенных для пользователя.
Разберем этот подход подробнее:
ТипДанных (тип: ПеречислениеСсылка или Строка) — здесь пользователь выбирает, что он хочет указать: Документ или Состояние.Значение (составной тип).ПриИзменении первого реквизита мы программно устанавливаем Ограничение типа для второго реквизита.Пример программной настройки типа:
&НаКлиенте
Процедура ТипДанныхПриИзменении(Элемент)
ТекущаяСтрока = Элементы.ТабличнаяЧасть1.ТекущиеДанные;
// Очищаем старое значение при смене типа
ТекущаяСтрока.Значение = Неопределено;
// Устанавливаем доступные типы для выбора в соседней колонке
НовыйМассив = Новый Массив;
Если ТекущаяСтрока.ТипДанных = "Документ" Тогда
НовыйМассив.Добавить(Тип("ДокументСсылка.РеализацияТоваровУслуг"));
Иначе
НовыйМассив.Добавить(Тип("ПеречислениеСсылка.СостоянияЗаказов"));
КонецЕсли;
ОписаниеТипов = Новый ОписаниеТипов(НовыйМассив);
// Теперь при нажатии кнопки выбора в колонке "Значение"
// платформа не будет спрашивать тип, а сразу откроет нужное окно
Элементы.ТабличнаяЧасть1Значение.ОграничениеТипа = ОписаниеТипов;
КонецПроцедуры
Этот метод является наиболее надежным, так как он полностью исключает использование «проблемного» диалога выбора типа платформы 8.3.15, заменяя его логичным и понятным бизнес-процессом.
Мы рассмотрели несколько способов решения проблемы выбора перечисления в составном типе данных. Если у вас нет возможности обновить платформу до версии 8.3.15.1830 или выше, где этот баг был исправлен официально, используйте программный вызов списка выбора или разделение реквизитов. Эти методы гарантируют стабильную работу приложения и избавят пользователей от необходимости совершать лишние клики или сталкиваться с «зависанием» интерфейса в табличных частях.