При разработке внешних обработок в среде 1С:Предприятие 8.3 (Управляемые формы) программисты часто сталкиваются с необходимостью передать данные из одной обработки в другую или программно заполнить табличную часть (ТЧ) существующей формы. Типичная ошибка новичка — попытка вызвать метод ПолучитьФорму() на сервере и напрямую манипулировать её элементами. Это неизбежно приводит к ошибке «Интерактивные операции недоступны». В этой статье мы подробно разберем, почему возникает эта проблема и как правильно организовать заполнение данных, используя современные механизмы платформы.
Прежде всего, проанализируем ситуацию. В управляемом приложении существует четкое разделение между клиентским и серверным контекстом. Форма — это объект клиентского уровня. Когда мы пытаемся выполнить процедуру &НаСервере и вызываем ПолучитьФорму(), платформа пытается инициализировать визуальный объект в контексте, где нет графического интерфейса пользователя (серверный сеанс). Даже если форма возвращается как объект, она не имеет связи с тем реальным окном, которое видит пользователь.
Основные причины ошибки:
Рассмотрим правильные подходы к решению этой задачи.
Это наиболее надежный и «чистый» способ передачи данных. Вместо того чтобы пытаться «взломать» форму снаружи, мы подготовим данные на сервере, поместим их в специальный контейнер и передадим адрес этого контейнера форме при её открытии.
Разберем по шагам:
ОткрытьФорму().ПриСозданииНаСервере, получаем данные по адресу и загружаем в ТЧ.Пример кода для вызывающей обработки:
&НаКлиенте
Процедура ЗаполнитьИОткрытьОбработку(Команда)
// Подготавливаем данные на сервере
РезультатЗаполнения = ПодготовитьДанныеНаСервере();
// Формируем структуру параметров для открытия формы
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("АдресДанных", РезультатЗаполнения.Адрес);
ПараметрыФормы.Вставить("Организация", Объект.Организация);
// Открываем форму целевой обработки
ОткрытьФорму("Обработка.ДокументыПоПартнеруИСделке.Форма.ДокументыПоПартнеру", ПараметрыФормы);
КонецПроцедуры
&НаСервере
Функция ПодготовитьДанныеНаСервере()
// Создаем таблицу значений для передачи
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Документ");
ТЗ.Колонки.Добавить("Дата");
ТЗ.Колонки.Добавить("Сумма");
// Здесь ваш запрос к базе данных
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ..."; // Текст запроса
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Помещаем результат во временное хранилище (УникальныйИдентификатор формы обеспечит жизнь хранилища)
Адрес = ПоместитьВоВременноеХранилище(РезультатЗапроса, ЭтаФорма.УникальныйИдентификатор);
Возврат Новый Структура("Адрес", Адрес);
КонецФункции
Теперь проанализируем код в целевой обработке (та, которую открываем):
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем наличие параметра с адресом данных
Если Параметры.Свойство("АдресДанных") Тогда
// Получаем таблицу из хранилища
ДанныеИзХранилища = ПолучитьИзВременногоХранилища(Параметры.АдресДанных);
Если ТипЗнч(ДанныеИзХранилища) = Тип("ТаблицаЗначений") Тогда
// Загружаем данные в табличную часть (реквизит формы)
Объект.ТаблицаДокументов.Загрузить(ДанныеИзХранилища);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Если форма внутренней обработки уже открыта на экране пользователя, и нам нужно обновить её содержимое из другой (например, внешней) обработки, используется механизм оповещений. Это позволяет избежать прямого обращения к контексту формы, что запрещено в управляемом интерфейсе.
Алгоритм работы:
Оповестить().ОбработкаОповещения.Пример кода вызывающей стороны:
&НаКлиенте
Процедура ПередатьДанныеВОткрытуюФорму(Команда)
ДанныеДляПередачи = Новый Структура;
ДанныеДляПередачи.Вставить("Контрагент", Объект.Контрагент);
// Посылаем сигнал всем открытым окнам
Оповестить("ОбновитьСписокДокументов", ДанныеДляПередачи, ЭтаФорма);
КонецПроцедуры
Код в форме внутренней обработки (которую нужно заполнить):
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ОбновитьСписокДокументов" Тогда
// Вызываем серверную процедуру для пересчета данных
ОбновитьДанныеТЧНаСервере(Параметр.Контрагент);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ОбновитьДанныеТЧНаСервере(Контрагент)
// Очищаем текущую ТЧ
Объект.ТаблицаДокументов.Очистить();
// Выполняем запрос и заполняем ТЧ
// Используем ЗаполнитьЗначенияСвойств для соответствия колонок
// ... логика запроса ...
КонецПроцедуры
В исходном вопросе автор использовал ЗаполнитьЗначенияСвойств(НовСтр, Выборка). Рассмотрим подробнее, как работает этот метод. Он крайне эффективен, но требует строгого совпадения имен колонок в выборке запроса и имен реквизитов в табличной части. Если в запросе колонка называется КонтрагентСсылка, а в ТЧ — Контрагент, данные не будут скопированы.
Рекомендация: Всегда проверяйте псевдонимы полей в запросе. Также помните, что на сервере при работе с табличными частями внутри модуля формы мы обращаемся к ним через Объект.ИмяТаблицы.
Выясним причину, почему работа через Объект правильнее, чем работа через Форму. В управляемом приложении форма — это лишь «маска» над данными. Сами данные хранятся в реквизите Объект (для документов, справочников и обработок).
Если вы создаете экземпляр обработки программно на сервере, вы должны работать с ней как с объектом:
&НаСервере
Процедура ЗаполнитьОбработкуКакОбъект()
// Создаем объект обработки
МояОбработка = Обработки.ДокументыПоПартнеруИСделке.Создать();
// Заполняем ТЧ объекта
НоваяСтрока = МояОбработка.ТаблицаДокументов.Добавить();
НоваяСтрока.Сумма = 100;
// Если нужно показать это пользователю, придется открывать форму и передавать данные (см. Решение 1)
КонецПроцедуры
Для успешного заполнения табличных частей внутренних обработок из внешнего кода придерживайтесь следующих правил:
ПолучитьФорму() на сервере для манипуляции данными.ЗначениеВРеквизитФормы и РеквизитФормыВЗначение, если вам нужно выполнить сложные вычисления с объектом внутри его же формы.Соблюдение этих архитектурных принципов не только избавит вас от ошибки «Интерактивные операции недоступны», но и сделает ваш код более производительным и устойчивым к изменениям платформы.