Перевод функционала со стандартных обычных форм на управляемые формы платформы 1С:Предприятие 8 часто вызывает затруднения у начинающих разработчиков. Управляемый интерфейс строится на принципиально иной архитектуре: четком разделении контекста выполнения на клиентский и серверный, использовании командного интерфейса и строгих правилах работы с типами данных и файловой системой. Разберем по шагам, как решить базовые задачи при создании внешней обработки на управляемых формах.
В обычных формах элементы управления можно было напрямую привязать к переменным модуля или создать кнопку без привязки к отдельной сущности. В управляемых формах логика изменилась:
ПутьКФайлу с типом Строка) и перетащить его в левое дерево элементов формы.ЗагрузитьДанные), назначим ей обработчик действия на клиенте (&НаКлиенте) и перетащим созданную команду в дерево элементов или на командную панель формы.КнопкаВыбора = Истина и создадим обработчик события НачалоВыбора.Рассмотрим типовую проблему: интерактивный диалог выбора файла выполняется на стороне клиента, однако чтение тяжелых табличных данных и запись в информационную базу должны производиться на сервере. Для этого файл помещается во временное хранилище на клиенте и извлекается на сервере.
Посмотрим на пример организации выбора файла и передачи его на сервер:
&НаКлиенте
Процедура ПутьКФайлуНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Заголовок = "Выберите файл для загрузки";
Диалог.Фильтр = "Файл Excel (*.xls;*.xlsx)|*.xls;*.xlsx|Табличный документ (*.mxl)|*.mxl";
Диалог.ПолноеИмяФайла = Объект.ПутьКФайлу;
Оповещение = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект);
Диалог.Показать(Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
Если ВыбранныеФайлы = Неопределено Или ВыбранныеФайлы.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// Записываем путь в реквизит формы для отображения в поле
Объект.ПутьКФайлу = ВыбранныеФайлы[0];
// Помещаем файл во временное хранилище для передачи на сервер
ОповещениеПомещения = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайлаНаСервер(ОповещениеПомещения, , , , Объект.ПутьКФайлу, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(ОписаниеПомещенногоФайла, ДополнительныеПараметры) Экспорт
Если ОписаниеПомещенногоФайла = Неопределено Тогда
Возврат;
КонецЕсли;
// Вызываем серверную процедуру обработки файла
ОбработатьФайлНаСервере(ОписаниеПомещенногоФайла.Адрес);
ПоказатьОповещениеПользователя("Загрузка завершена", , "Данные успешно обработаны");
КонецПроцедуры
На стороне сервера двоичные данные извлекаются из хранилища и загружаются в ТабличныйДокумент без необходимости использования нестабильных COM-объектов:
&НаСервере
Процедура ОбработатьФайлНаСервере(АдресВХранилище)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХранилище);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
ДвоичныеДанные.Записать(ИмяВременногоФайла);
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
УдалитьФайлы(ИмяВременногоФайла);
ВызватьИсключение "Ошибка чтения файла: " + ОписаниеОшибки();
КонецПопытки;
УдалитьФайлы(ИмяВременногоФайла);
// Обработка строк таблицы
КоличествоСтрок = ТабДок.ВысотаТаблицы;
Для НомерСтроки = 2 По КоличествоСтрок Цикл
НомерЛС = СокрЛП(ТабДок.ПолучитьОбласть("R" + НомерСтроки + "C1").ТекущаяОбласть.Текст);
НомерЕЛС = СокрЛП(ТабДок.ПолучитьОбласть("R" + НомерСтроки + "C2").ТекущаяОбласть.Текст);
Если ЗначениеЗаполнено(НомерЛС) Тогда
ОбновитьДанныеЛицевогоСчета(НомерЛС, НомерЕЛС);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Частая ошибка при переходе с обычных форм — попытка вызвать менеджер справочника (Справочники.КУ_ЛицевыеСчета) в процедуре с директивой &НаКлиенте. На клиенте глобальная коллекция Справочники недоступна. Все операции чтения и записи объектов должны выполняться исключительно в контексте &НаСервере или &НаСервереБезКонтекста.
Кроме того, полный перебор справочника через Справочники.КУ_ЛицевыеСчета.Выбрать() является крайне неоптимальным. Для поиска конкретной записи следует использовать объект Запрос или метод НайтиПоРеквизиту.
Рассмотрим оптимальный вариант обновления данных с контролем транзакций:
&НаСервере
Процедура ОбновитьДанныеЛицевогоСчета(НомерЛС, НомерЕЛС)
// Оптимальный поиск ссылки через запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КУ_ЛицевыеСчета.Ссылка КАК Ссылка,
| КУ_ЛицевыеСчета.Помещение КАК Помещение
|ИЗ
| Справочник.КУ_ЛицевыеСчета КАК КУ_ЛицевыеСчета
|ГДЕ
| КУ_ЛицевыеСчета.НомерЛицевогоСчета = &НомерЛицевогоСчета";
Запрос.УстановитьПараметр("НомерЛицевогоСчета", НомерЛС);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
НачатьТранзакцию();
Попытка
ОбъектЛС = Выборка.Ссылка.ПолучитьОбъект();
ОбъектЛС.ГИСЖКХЕдиныйЛицевойСчет = НомерЕЛС;
ОбъектЛС.Записать();
Если ЗначениеЗаполнено(Выборка.Помещение) Тогда
ОбъектПомещение = Выборка.Помещение.ПолучитьОбъект();
ОбъектПомещение.ИдентКодВ_ГИС_ЖКХ = НомерЕЛС;
ОбъектПомещение.Записать();
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("ЗагрузкаЕЛС", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Если при вызове метода Записать() возникает ошибка контекста выполнения, проанализируем основные причины:
ПередЗаписью или ПриЗаписи срабатывает встроенная бизнес-логика конфигурации (например, проверка обязательного заполнения полей, проверка уникальности номера или формата данных), выставляющая флаг Отказ = Истина.-debug) и в конфигураторе включить режим «Остановка по ошибке» в меню «Отладка».В качестве временной меры при загрузке нормативно-справочной информации используют установку свойства ОбменДанными.Загрузка = Истина:
ОбъектЛС = Выборка.Ссылка.ПолучитьОбъект();
ОбъектЛС.ОбменДанными.Загрузка = Истина;
ОбъектЛС.ГИСЖКХЕдиныйЛицевойСчет = НомерЕЛС;
ОбъектЛС.Записать();
Важно понимать последствия: включение режима загрузки отключает выполнение обработчиков событий модуля объекта, игнорирует системные проверки заполнения реквизитов и подавляет авторегистрацию изменений в планах обмена. Применять данный режим следует только тогда, когда точно известна причина блокировки записи и гарантируется целостность записываемых данных.