Данная тема уже обсуждалась //infostart.ru/public/305935/, но, столкнувшись с проблемой в реальной разработке, я решил изобретать свой "велосипед" =)
Основной целью являлось:
- создание некого общего модуля, который будет отвечать непосредственно за организацию и контроль цикла ввода данных;
- возможность запустить цикл на любое количество итерации обращений к пользователю и обработать результ ввода в 2 процедуры.
//_____________________________________________________________
#Область ПрограммныйИнтерфейс
// Шаблон структуры, описывающий каждую итерацию ввода данных
//
&НаКлиенте
Функция ПолучитьШаблонОжидаемогоВвода() Экспорт
Результат = Новый Структура;
Результат.Вставить("Ключ", "");
Результат.Вставить("Владелец", Неопределено);
Результат.Вставить("ОбработчикВвода", "");
Результат.Вставить("СписокЗначений", Новый СписокЗначений);
Результат.Вставить("ОткрываемаяФорма", "");
Результат.Вставить("ПараметрыФормы", Новый Структура);
Результат.Вставить("ЧислоДлина", 0);
Результат.Вставить("ЧислоТочность", 0);
Результат.Вставить("Подсказка", "");
Результат.Вставить("ПроизвольныйПараметр", Неопределено);
Результат.Вставить("РежимДиалогаВопрос", РежимДиалогаВопрос.ДаНет);
Результат.Вставить("Обязательный", Ложь);
Результат.Вставить("ФлагЗавершения", Ложь);
Результат.Вставить("ПостОбработка", Ложь);
Результат.Вставить("Результат", Неопределено);
Возврат Результат
КонецФункции
// Главная процедура. Является как и стартом цикла, так и обработкой каждой последующей итерации
//
// - ТочкаВозврата : структура, определяющая объект и имя его экспортной процедуры,
// куда передаются итоги ввода данных
// - МассивОжидаемогоВвода : массив структур из функции "ПолучитьШаблонОжидаемогоВвода",
// определяет действия и их поряд по вводу данных
// - СквозныеДанные : служебная Структура("ФлагЗавершения, Ключ, Результат, ТочкаВозврата, МассивОжидаемогоВвода"),
// через нее возврат введенных в цикл
//
&НаКлиенте
Процедура ЗапуститьЦикл(ТочкаВозврата, МассивОжидаемогоВвода, СквозныеДанные = Неопределено) Экспорт
// проверка возврата в цикл после ввода данных
Если СквозныеДанные <> Неопределено Тогда
// запищем результат
Для Каждого ОбработкаВвода Из МассивОжидаемогоВвода Цикл
Если ОбработкаВвода.Ключ = СквозныеДанные.Ключ Тогда
Если ОбработкаВвода.Обязательный И СквозныеДанные.Результат = Неопределено Тогда
ОбработкаВвода.ФлагЗавершения = Ложь;
Иначе
ОбработкаВвода.ФлагЗавершения = СквозныеДанные.ФлагЗавершения;
ОбработкаВвода.Результат = СквозныеДанные.Результат;
КонецЕсли;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
ВводЗакончен = Истина;
// поиск и запуск следующей итерации ввода данных
Для Каждого ОбработкаВвода Из МассивОжидаемогоВвода Цикл
Если ОбработкаВвода.ФлагЗавершения И НЕ ОбработкаВвода.ПостОбработка Тогда
Продолжить;
ИначеЕсли ОбработкаВвода.ФлагЗавершения И ОбработкаВвода.ПостОбработка Тогда
Выполнить("ТочкаВозврата.Объект." + ТочкаВозврата.ИмяПроцедуры + "(МассивОжидаемогоВвода)");
Возврат;
КонецЕсли;
ВводЗакончен = Ложь;
СквозныеДанные = Новый Структура("ФлагЗавершения, Ключ, Результат, ТочкаВозврата, МассивОжидаемогоВвода");
СквозныеДанные.ФлагЗавершения = Ложь;
СквозныеДанные.Ключ = ОбработкаВвода.Ключ;
СквозныеДанные.Результат = Неопределено;
СквозныеДанные.ТочкаВозврата = ТочкаВозврата;
СквозныеДанные.МассивОжидаемогоВвода = МассивОжидаемогоВвода;
Если ОбработкаВвода.ОбработчикВвода = "ВыборИзФормы" Тогда
ВыборИзФормы(ОбработкаВвода.ОткрываемаяФорма, ОбработкаВвода.ПараметрыФормы, ОбработкаВвода.Владелец, СквозныеДанные);
ИначеЕсли ОбработкаВвода.ОбработчикВвода = "ВыборИзСписка" Тогда
ВыборИзСписка(ОбработкаВвода.СписокЗначений, ОбработкаВвода.Владелец, СквозныеДанные);
ИначеЕсли ОбработкаВвода.ОбработчикВвода = "ВводСтроки" Тогда
ВводСтроки(ОбработкаВвода.Подсказка, СквозныеДанные);
ИначеЕсли ОбработкаВвода.ОбработчикВвода = "ВводЧисла" Тогда
ВводЧисла(ОбработкаВвода.Подсказка, ОбработкаВвода.ЧислоДлина, ОбработкаВвода.ЧислоТочность, СквозныеДанные);
ИначеЕсли ОбработкаВвода.ОбработчикВвода = "ОтветНаВопрос" Тогда
ОтветНаВопрос(ОбработкаВвода.Подсказка, ОбработкаВвода.РежимДиалогаВопрос, СквозныеДанные);
КонецЕсли;
Прервать;
КонецЦикла;
// если все то возвращаем в точку возврата все введенные данные
Если ВводЗакончен Тогда
Выполнить("ТочкаВозврата.Объект." + ТочкаВозврата.ИмяПроцедуры + "(МассивОжидаемогоВвода)");
КонецЕсли;
КонецПроцедуры
#КонецОбласти
//_____________________________________________________________
#Область Диалоги
// Тут довольно все очевидно, обработка необбходимости вода данных
// с шаблонным возвратом в цикл
&НаКлиенте
Процедура ВыборИзФормы(ОткрываемаяФорма, ПараметрыФормы, Владелец, СквозныеДанные)
ОписаниеОповещения = Новый ОписаниеОповещения("ВыборИзФормы_Завершение", ЭтотОбъект, СквозныеДанные);
ОткрытьФорму(ОткрываемаяФорма, ПараметрыФормы, Владелец, , , , ОписаниеОповещения, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
КонецПроцедуры
&НаКлиенте
Процедура ВыборИзСписка(СписокВыбора, Владелец, СквозныеДанные)
ПараметрыФормы = Новый Структура("СписокВыбора", СписокВыбора);
ОписаниеОповещения = Новый ОписаниеОповещения("ВыборИзСписка_Завершение", ЭтотОбъект, СквозныеДанные);
ОткрытьФорму("ОбщаяФорма.ФормаВыбораИзСписка", ПараметрыФормы, Владелец, , , , ОписаниеОповещения, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
КонецПроцедуры
&НаКлиенте
Процедура ВводСтроки(Подсказка, СквозныеДанные)
ОписаниеОповещения = Новый ОписаниеОповещения("ВводСтроки_Завершение", ЭтотОбъект, СквозныеДанные);
ПоказатьВводСтроки(ОписаниеОповещения, "", Подсказка);
КонецПроцедуры
&НаКлиенте
Процедура ВводЧисла(Подсказка, Длина, Точность, СквозныеДанные)
ОписаниеОповещения = Новый ОписаниеОповещения("ВводЧисла_Завершение", ЭтотОбъект, СквозныеДанные);
ПоказатьВводЧисла(ОписаниеОповещения, 0, Подсказка, Длина, Точность);
КонецПроцедуры
&НаКлиенте
Процедура ОтветНаВопрос(Подсказка, Кнопки, СквозныеДанные)
ОписаниеОповещения = Новый ОписаниеОповещения("ОтветНаВопрос_Завершение", ЭтотОбъект, СквозныеДанные);
ПоказатьВопрос(ОписаниеОповещения, Подсказка, Кнопки);
КонецПроцедуры
#КонецОбласти
//_____________________________________________________________
#Область ОбработкиОповещений
// Закрывашки наших диалогов
&НаКлиенте
Процедура ВыборИзФормы_Завершение(ВыбЗнач, СквозныеДанные) Экспорт
СквозныеДанные.Результат = ВыбЗнач;
СквозныеДанные.ФлагЗавершения = Истина;
ЗапуститьЦикл(СквозныеДанные.ТочкаВозврата, СквозныеДанные.МассивОжидаемогоВвода, СквозныеДанные);
КонецПроцедуры
&НаКлиенте
Процедура ВыборИзСписка_Завершение(ВыбЗнач, СквозныеДанные) Экспорт
СквозныеДанные.Результат = ВыбЗнач;
СквозныеДанные.ФлагЗавершения = Истина;
ЗапуститьЦикл(СквозныеДанные.ТочкаВозврата, СквозныеДанные.МассивОжидаемогоВвода, СквозныеДанные);
КонецПроцедуры
&НаКлиенте
Процедура ВводСтроки_Завершение(ВведеннаяСтрока, СквозныеДанные) Экспорт
СквозныеДанные.Результат = ВведеннаяСтрока;
СквозныеДанные.ФлагЗавершения = Истина;
ЗапуститьЦикл(СквозныеДанные.ТочкаВозврата, СквозныеДанные.МассивОжидаемогоВвода, СквозныеДанные);
КонецПроцедуры
&НаКлиенте
Процедура ВводЧисла_Завершение(ВведеннаяСтрока, СквозныеДанные) Экспорт
СквозныеДанные.Результат = ВведеннаяСтрока;
СквозныеДанные.ФлагЗавершения = Истина;
ЗапуститьЦикл(СквозныеДанные.ТочкаВозврата, СквозныеДанные.МассивОжидаемогоВвода, СквозныеДанные);
КонецПроцедуры
&НаКлиенте
Процедура ОтветНаВопрос_Завершение(Ответ, СквозныеДанные) Экспорт
СквозныеДанные.Результат = Ответ;
СквозныеДанные.ФлагЗавершения = Истина;
ЗапуститьЦикл(СквозныеДанные.ТочкаВозврата, СквозныеДанные.МассивОжидаемогоВвода, СквозныеДанные);
КонецПроцедуры
#КонецОбласти
Теперь расмотрим живой пример изспользования данного модуля.
Решим следующую задачу: при выборе товара в корзину нужно сразу запросить необходимое количество, спросить о необходимости поставить товар в резерв и, если будет положительный ответ, то дать выбрать место размещения товара.
Получаем следующие итерации ввода:
- ввести число;
- диалог вопроса;
- если на диалог был ответ да, то выбрать ссылку.
Приступим.
&НаКлиенте
Процедура ТоварыПриИзменении(Элемент)
// Товар был добавлен в корзину.
// Запросим необходимые данные.
ЗапроситьДанные();
КонецПроцедуры
// Можно считать шаблоном. Обязательно экспортная, т.к. тут же происходит
// пост-обработка итерации ввода данных (если была включена такая опция).
//
// - МассивОжидаемогоВвода : параметр как флаг, либо это первый запуск,
// либо пост-обработка, либо завершение цикла
//
&НаКлиенте
Процедура ЗапроситьДанные(МассивОжидаемогоВвода = Неопределено) Экспорт
// возврат происходит в эту же процедуру
ТочкаВозврата = Новый Структура("ИмяПроцедуры, Объект");
ТочкаВозврата.ИмяПроцедуры = "ЗапроситьДанные";
ТочкаВозврата.Объект = ЭтотОбъект;
// проверка параметра
Если МассивОжидаемогоВвода = Неопределено Тогда
// первый запуск
МассивОжидаемогоВвода = Новый Массив;
// ожидаем ввода количества
НовыйВводДаных = ВводДанныхКлинет.ПолучитьШаблонОжидаемогоВвода();
НовыйВводДаных.Ключ = "КоличествоТовара";
НовыйВводДаных.Владелец = ЭтаФорма;
НовыйВводДаных.ОбработчикВвода = "ВводЧисла"; // наш тип обработчика
НовыйВводДаных.ЧислоДлина = 5;
МассивОжидаемогоВвода.Добавить(НовыйВводДаных);
// спрашиваем
НовыйВводДаных = ВводДанныхКлинет.ПолучитьШаблонОжидаемогоВвода();
НовыйВводДаных.Ключ = "Вопрос";
НовыйВводДаных.Владелец = ЭтаФорма;
НовыйВводДаных.ПостОбработка = Истина; // признак пост-обработки перед следующим диалогом
НовыйВводДаных.ОбработчикВвода = "ОтветНаВопрос";
МассивОжидаемогоВвода.Добавить(НовыйВводДаных);
// запускаем цикл
ВводДанныхКлинет.ЗапуститьЦикл(ТочкаВозврата, МассивОжидаемогоВвода);
Иначе
// цикл нам вернул данные, проверим что это: завершение либо пост-обработка
ВводЗакончен = Истина;
ВводОтменен = Ложь;
Для Каждого ОбработкаВвода Из МассивОжидаемогоВвода Цикл
Если ОбработкаВвода.ФлагЗавершения И ОбработкаВвода.ПостОбработка Тогда
ВводЗакончен = Ложь;
Если ОбработкаВвода.Ключ = "Вопрос" Тогда
// если ответили "Да" то добавим еще итерацию ввода данных
Если ОбработкаВвода.Результат = КодВозвратаДиалога.Да Тогда
// выбрать склад
НовыйВводДаных = ВводДанныхКлинет.ПолучитьШаблонОжидаемогоВвода();
НовыйВводДаных.Ключ = "Склад";
НовыйВводДаных.Владелец = ЭтаФорма;
НовыйВводДаных.Подсказка = "Наименование области";
НовыйВводДаных.ОбработчикВвода = "ВводСтроки";
МассивОжидаемогоВвода.Добавить(НовыйВводДаных);
КонецЕсли;
ОбработкаВвода.ПостОбработка = Ложь; // признак завершения пост-обработки
КонецЕсли;
ИначеЕсли ОбработкаВвода.ФлагЗавершения И НЕ ОбработкаВвода.ПостОбработка Тогда
ВводОтменен = (ОбработкаВвода.Результат = Неопределено);
Продолжить;
КонецЕсли;
КонецЦикла;
Если ВводОтменен Тогда
Возврат;
КонецЕсли;
Если ВводЗакончен Тогда
// завершим
ЗапроситьДанные_ОбработкаВвода(МассивОжидаемогоВвода);
Иначе
// продолжим
ВводДанныхКлинет.ЗапуститьЦикл(ТочкаВозврата, МассивОжидаемогоВвода);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ЗапроситьДанные_ОбработкаВвода(МассивОжидаемогоВвода)
// тут уже делаем с результатом ввода что хотим...
КонецПроцедуры
Собственно все =) Надеюсь данный пример раскрывает простоту использованиях представленного модуля.
Вот несколько примеров из рабочего проекта.
Данная разработка представляется как есть. Можете дорабатывать как угодно для своих нужд. Всем успехов!