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