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