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