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