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