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