Как работать с таблицей значений и асинхронно открывать формы в управляемом приложении 1С 8.3

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

При переходе с обычных форм (или 1С 7.7) на управляемые формы программисты часто сталкиваются с двумя принципиальными особенностями клиент-серверной архитектуры платформы 8.3:

  1. Разделение данных: на клиенте привычного объекта ТаблицаЗначений не существует, вместо него используется специальный тип ДанныеФормыКоллекция.
  2. Асинхронный режим работы интерфейса: прямые вызовы ПолучитьФорму() и ОткрытьМодально() запрещены или крайне не рекомендуются. Взамен используются немодальные вызовы с обработкой закрытия через оповещения.

Рассмотрим подробнее решения этих задач и выясним причину распространенных ошибок.

1. Заполнение таблицы значений на управляемой форме

Разберем ситуацию, когда серверная функция возвращает объект типа ТаблицаЗначений, и ею необходимо заполнить реквизит формы.

При попытке прямой присваивки вида Элементы.Таблица = ВызватьСервернуюФункцию() система вызовет ошибку: «Нельзя изменять поле, содержащее объект данных формы». Это связано с тем, что реквизит формы на сервере связан с объектом ДанныеФормыКоллекция, в который нельзя напрямую записать прикладной тип ТаблицаЗначений.

Посмотрим на правильные способы решения этой проблемы на сервере.

Способ 1. Использование платформенного метода ЗначениеВРеквизитФормы()

Это наиболее быстрый и стандартный метод преобразования прикладного объекта в реквизит формы. Важное условие: имена и типы колонок в таблице значений должны полностью совпадать с колонками реквизита формы.


&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
    
    // Получаем ТаблицуЗначений из внешнего модуля или запроса
    ТаблицаБаллов = Окомпании.ПолучитьИнформациюОКомпании(Объект.КодСкидки);
    
    // Преобразуем объект ТаблицаЗначений в реквизит формы с именем "МояТаблицаНаФорме"
    ЗначениеВРеквизитФормы(ТаблицаБаллов, "МояТаблицаНаФорме");
    
КонецПроцедуры

Способ 2. Использование метода Загрузить()

Реквизит формы представляет собой ДанныеФормыКоллекция, у которого есть встроенный метод Загрузить(). Он принимает на вход объект типа ТаблицаЗначений:


&НаСервере
Процедура ЗаполнитьТаблицуЧерезЗагрузить()
    
    ТаблицаБаллов = Окомпании.ПолучитьИнформациюОКомпании(Объект.КодСкидки);
    
    // Загружаем данные напрямую в коллекцию формы
    ЗначениеВРеквизитФормы(ТаблицаБаллов, "МояТаблицаНаФорме");
    // Или с помощью метода Загрузить():
    // ЭтаФорма.МояТаблицаНаФорме.Загрузить(ТаблицаБаллов);
    
КонецПроцедуры

Способ 3. Построчный обход таблицы

Если требуется дополнительная обработка данных при переносе, можно обойти исходную таблицу циклом:


&НаСервере
Процедура ЗаполнитьТаблицуОбходом()
    
    ТаблицаБаллов = Окомпании.ПолучитьИнформациюОКомпании(Объект.КодСкидки);
    
    МояТаблицаНаФорме.Очистить();
    Для Каждого СтрокаИзСервера Из ТаблицаБаллов Цикл
        НоваяСтрока = МояТаблицаНаФорме.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИзСервера);
    КонецЦикла;
    
КонецПроцедуры

2. Поиск данных в таблице на клиенте

Попытка вызвать метод Найти() на клиенте приведет к ошибке: «Метод не обнаружен». Объект ДанныеФормыКоллекция на клиенте не имеет метода Найти(), однако предоставляет метод НайтиСтроки().

Проанализируем пример выполнения поиска нужной строки на клиенте:


&НаКлиенте
Процедура НайтиЗначениеНаКлиенте()
    
    // Поиск выполняется с использованием структуры отбора
    ПараметрыОтбора = Новый Структура;
    ПараметрыОтбора.Вставить("Поле", "КоличествоИмеющихсяБаллов");
    
    НайденныеСтроки = МояТаблицаНаФорме.НайтиСтроки(ПараметрыОтбора);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        ИскомаяСтрока = НайденныеСтроки[0];
        // Работаем с найденной строкой
    КонецЕсли;
    
КонецПроцедуры

Совет: если вам требуется сложная работа с таблицами (поиск по нескольким условиям, сортировка, агрегатные функции), рекомендуется выполнять эти операции на сервере, предварительно преобразовав реквизит формы обратно в таблицу значений с помощью метода РеквизитФормыВЗначение().

3. Открытие подчиненных форм и обработка результатов без модальности

Рассмотрим вторую частую задачу: открытие дополнительной формы документа (например, формы ввода скидки) с блокировкой интерфейса и ожидания ответа от пользователя.

Использование ПолучитьФорму() и ОткрытьМодально() в современных управляемых формах запрещено. Вместо этого используется функция ОткрытьФорму() в сочетании с объектом ОписаниеОповещения.

Разберем по шагам, как правильно реализовать этот механизм.

  1. При вызове формы передаем структуру параметров, режим блокировки окна и описание процедур-обработчиков.
  2. Для связи со существующим документом в параметр Ключ структуры передаем ссылку на объект: Новый Структура("Ключ", Объект.Ссылка).
  3. Создаем процедуру с ключевым словом Экспорт, которая примет результат закрытия формы.

Посмотрим на пример кода в форме-источнике:


&НаКлиенте
Процедура ОткрытьФормуСкидок(Команда)
    
    // Формируем параметры для открываемой формы
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("Ключ", Объект.Ссылка); // Ссылка на текущий документ
    
    // Создаем описание оповещения, которое сработает после закрытия вызываемой формы
    // Требуемый формат параметров ОписанияОповещения: ("ИмяПроцедуры", ЭтотОбъект)
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗакрытияФормыСкидок", ЭтотОбъект);
    
    // Открываем форму с блокировкой интерфейса
    ОткрытьФорму(
        "Документ.РасходнаяНакладная.Форма.ФормаСкидки", 
        ПараметрыОткрытия, 
        ЭтотОбъект, 
        Истина, 
        , 
        , 
        ОписаниеОповещения, 
        РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс
    );

КонецПроцедуры

&НаКлиенте
Процедура ПослеЗакрытияФормыСкидок(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
    
    // Проверяем, вернула ли закрытая форма данные (пользователь мог просто закрыть окно)
    Если РезультатЗакрытия <> Неопределено Тогда
        // Обрабатываем результат
        Объект.СуммаСкидки = РезультатЗакрытия;
    Иначе
        Сообщить("Ввод скидки передан или отменен пользователем.");
    КонецЕсли;

КонецПроцедуры

В самой открываемой дочерней форме для возврата значения в вызвавшую форму используется метод Закрыть() с передачей результата:


&НаКлиенте
Процедура КомандаОК(Команда)
    
    // Передаем введенные данные назад в форму-владелец
    ЗначениеРезультата = Элементы.ВведенныеБаллы.Значение;
    Закрыть(ЗначениеРезультата);
    
КонецПроцедуры

Таким образом, использование асинхронной модели с объектом ОписаниеОповещения позволяет безопасно и корректно передавать данные между формами в управляемом приложении 1С 8.3, полностью соблюдая требования платформы.

← На главную