Как в управляемой форме отложить действие до показа диалога
Возникла у меня в ходе работы над проектом клиента задача, вроде бы и простая, но в то же время требующая понимания тонкостей взаимодействия клиента и сервера.
Есть обработчик некоторых действий пользователя, может быть вызван из разных форм. Находится в клиентском модуле.
Нужно, прежде чем выполнить этот обработчик, сначала показать некоторый диалог с данными для заполнения и уже при его заполнении, продолжить вызов стандартного обработчика.
Пришлось повозиться, честно скажу.
Для тех, кто любит конкретику, речь идет о запуске бизнес-процесса, при этом нужно показать дополнительный диалог, где пользователь может выбрать дополнительных согласующих.
Я расширял процедуру СтартоватьИЗакрыть модуля КомандыРаботыСБизнесПроцессамиКлиент:
&Вместо("СтартоватьИЗакрыть") Процедура дор_СтартоватьИЗакрыть(Форма) //Осипов 2021-09-01 ... //Определяем внутренний документ ВнутреннийДокумент = дор_Сервер.ОсновнойВнутреннийДокументБизнесПроцесса(Форма.Объект); Если НЕ ЗначениеЗаполнено(ВнутреннийДокумент) Тогда Перейти ~Стандартно; КонецЕсли; //Открываем форму выбора подразделений ПараметрыФормы = Новый Структура(); ПараметрыФормы.Вставить("ВнутреннийДокумент", ВнутреннийДокумент); ДополнительныеПараметры = Новый Структура(); //При закрытии формы отработают ДополнительныеПараметры.Вставить("Форма", Форма); ДополнительныеПараметры.Вставить("ВнутреннийДокумент", ВнутреннийДокумент); ОписаниеОповещенияОЗакрытии = Новый ОписаниеОповещения("дор_ПослеВыбораПодразделенийДляГрупповогоСогласования", КомандыРаботыСБизнесПроцессамиКлиент, ДополнительныеПараметры); ОткрытьФорму("...Форма.ВыборПодразделенийДляГрупповогоСогласования", ПараметрыФормы, ,,,,ОписаниеОповещенияОЗакрытии, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс); Возврат; //Предыдущий обработчик не вызываем ~Стандартно: ПродолжитьВызов(Форма); КонецПроцедуры &НаКлиенте Процедура дор_ПослеВыбораПодразделенийДляГрупповогоСогласования(РезультатЗакрытия, ДополнительныеПараметры) Экспорт Если РезультатЗакрытия = Неопределено Тогда Возврат КонецЕсли; КомандыРаботыСБизнесПроцессамиКлиент.СтартоватьИЗакрыть(Форма); //Так зацикливание КонецПроцедуры
Как видно из кода, я не делаю вызов стандартной процедуры, делая возврат из процедуры после показа формы ввода дополнительных данных, перед ПродолжитьВызов.
Кстати, при описании обработчика оповещения в коде вместо названия модуля можно использовать ЭтотОбъект, я об этом знал, но сразу не получилось почему-то, поэтому в коде осталось имя модуля.
Но возникает одна проблема — после отработки закрытия формы ввода дополнительных данных управление должно передаться стандартной процедуре. Если ее вызвать непосредственно, она зациклтся.
Сначала я попробовал добавить процедуре необязательный параметр:
&Вместо("СтартоватьИЗакрыть") Процедура дор_СтартоватьИЗакрыть(Форма, ВыполнятьСтандартноСразу = ложь)
Но так 1С не восприняла расширение процедуры и моя процедура просто не вызвалась, т.к. у нее был «лишний» параметр, хотя и не обязательный.
Тогда я решил добавить в форму служебный реквизит, но столкнулся с тем, что не могу передать форму на сервер из клиентского модуля — известная проблема 1С.
Попробовал добавить элемент формы, но не знал, что его нельзя добавлять на клиенте, тоже можно добавлять только на сервере.
Эти попытки заняли минут 40.
Я уже было хотел где-то в клиентском кэше хранить, какие формы у меня надо предварять вводом дополнительных данных, какие нет, т.е. хранить список форм.
Но, к счастью, не стал этим заниматься, а выкрутился по-простому:
&Вместо("СтартоватьИЗакрыть") Процедура дор_СтартоватьИЗакрыть(Форма) ... Если ТипЗнч(Форма) = Тип("Структура") Тогда Форма = Форма.Форма; Перейти ~Стандартно; КонецЕсли; ... ~Стандартно: ПродолжитьВызов(Форма); КонецПроцедуры &НаКлиенте Процедура дор_ПослеВыбораПодразделенийДляГрупповогоСогласования(РезультатЗакрытия, ДополнительныеПараметры) Экспорт Если РезультатЗакрытия = Неопределено Тогда Возврат КонецЕсли; КомандыРаботыСБизнесПроцессамиКлиент.СтартоватьИЗакрыть(Новый Структура("Форма", ДополнительныеПараметры.Форма)); КонецПроцедуры
Я обернул форму в структуру и на входе смотрел — если это форма, значит первый вызов и надо показывать дополнительную форму, а если на входе структура — надо вызывать стандартный обработчик.
Надеюсь, клиент не будет злоупотреблять расширениями и навешивать несколько их на эту злосчастную процедуру общего модуля, иначе результат может быть не предсказуем.
Единственно, хочу заметить, что я пытался еще вызвать процедуру расширения напрямую:
дор_СтартоватьИЗакрыть(Новый Структура("Форма", ДополнительныеПараметры.Форма));
Но 1С так не смогла, она вызвала процедуру, но ругнулась на «ПродолжитьВызов», потому что не «знала», кто вызвал эту функцию.
Вот код, где я пытался добавлять реквизиты и элементы на форме, выкладываю, может пригодится кому:
//МОДУЛЬ дор_КлиентСервер: (клиент-серверный) #Область СлужебныйРеквизит Функция ПолучитьСлужебныйРеквизитФормы(Знач Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64") Экспорт ГарантироватьСлужебныйРеквизитФормы(Форма, Имя); Возврат Форма[Имя]; КонецФункции Функция УстановитьСлужебныйРеквизитФормы(Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64", Значение) Экспорт ГарантироватьСлужебныйРеквизитФормы(Форма, Имя); Форма[Имя] = Значение; КонецФункции Функция ЕстьСлужебныйРеквизитФормы(Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64") Экспорт //Отсюда: https://forum.mista.ru/topic.php?id=844075 ТестЗначение = "52627514-b2e3-48a7-853f-f8047ade8f4c"; Структура = Новый Структура(Имя, ТестЗначение); ЗаполнитьЗначенияСвойств(Структура, Форма); Возврат Структура[Имя] <> ТестЗначение; //МассивРеквизитов = дор_Сервер.ПолучитьРеквизитыФормы(Форма); //Для каждого ТекРеквизит Из МассивРеквизитов Цикл // Если ТекРеквизит.Имя = Имя Тогда // Возврат Истина; // КонецЕсли; //КонецЦикла; //Возврат ложь; КонецФункции Процедура ГарантироватьСлужебныйРеквизитФормы(Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64") Экспорт Если ЕстьСлужебныйРеквизитФормы(Форма, Имя) Тогда Возврат; КонецЕсли; дор_Сервер.ДобавитьРеквизитФормы(Форма, Имя, Новый ОписаниеТипов()); КонецПроцедуры #КонецОбласти #Область СлужебныйФлаг Функция ПолучитьСлужебныйФлагФормы(Знач Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64") Экспорт ГарантироватьСлужебныйФлагФормы(Форма, Имя); Возврат Форма.Элементы[Имя].Подсказка <> ""; КонецФункции Функция УстановитьСлужебныйФлагФормы(Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64") Экспорт ГарантироватьСлужебныйФлагФормы(Форма, Имя); Форма.Элементы[Имя].Подсказка = "!"; КонецФункции Функция ЕстьСлужебныйФлагФормы(Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64") Экспорт Возврат Форма.Элементы.Найти(Имя) <> Неопределено; КонецФункции Процедура ГарантироватьСлужебныйФлагФормы(Форма, Имя = "_532a922e5b11450f96ac6e6b71ea0a64") Экспорт Если ЕстьСлужебныйФлагФормы(Форма, Имя) Тогда Возврат; КонецЕсли; //Добавляем невидимый элемент ТекЭлемент = Форма.Элементы.Добавить(Имя, Тип("ПолеФормы")); ТекЭлемент.Видимость = ложь; КонецПроцедуры #КонецОбласти //МОДУЛЬ дор_Сервер: (серверный) Функция ПолучитьРеквизитыФормы(Знач Форма) Экспорт Возврат Форма.ПолучитьРеквизиты(); КонецФункции Процедура ДобавитьРеквизитФормы(Форма, Имя, Тип) Экспорт ДобавляемыеРеквизиты = Новый Массив(); ТекРеквизит = Новый РеквизитФормы(Имя, Тип); ДобавляемыеРеквизиты.Добавить(ТекРеквизит); Форма.ИзменитьРеквизиты(ДобавляемыеРеквизиты); КонецПроцедуры
Мне в этом коде нравится, как я на клиенте, не обращаясь на сервер через заполнение значение свойств проверяю наличие реквизита у формы. Кстати, я использую GUID для генерации уникального названия реквизита или поля формы.
Но код оказался бесполезен, он работает только на сервере.
Среда: Документооборот 8 КОРП 2.1.26.2 Объем факт: 2 час.
Вот п.э. с 1с все и сваливают у кого мозг отрастает — задалбывает дрочево и бесконечное строительство костылей псли хотелка в типовую не вписывается
да, 1с не для слабых духом.