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