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