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