Как исправить ошибку «Недопустимое значение параметра (параметр номер '1')» при вызове РеквизитФормыВЗначение в форме списка 1С?

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

При переходе к разработке на управляемых формах в среде «1С:Предприятие 8.3» одной из самых частых преград для программистов становится понимание контекста выполнения кода и разницы между типами данных на клиенте, сервере и в различных видах форм. Типичный пример такой проблемы — попытка выполнить групповую обработку документов из формы списка, используя методы, предназначенные исключительно для формы самого объекта.

В этой статье мы подробно разберем, почему возникает ошибка «Недопустимое значение параметра (параметр номер '1')» при вызове метода РеквизитФормыВЗначение, проанализируем сопутствующие архитектурные ошибки в коде и выработаем правильный, оптимизированный шаблон группового изменения документов на сервере.

Выясняем причину: почему падает РеквизитФормыВЗначение?

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

Основное ограничение метода состоит в следующем: он работает только в контексте формы самого объекта, где существует реквизит с типом, приводимым к объекту (обычно это стандартный реквизит формы Объект).

Когда мы находимся в форме списка, ситуация кардинально меняется:

  1. Основным реквизитом формы списка является Список (тип ДинамическийСписок), а не Объект.
  2. Реквизита с именем Объект в форме списка по умолчанию просто не существует.
  3. Попытка передать строку "Объект" в качестве первого параметра метода РеквизитФормыВЗначение("Объект") вызывает закономерный отказ платформы, так как реквизита с таким именем на форме списка нет.

Поэтому использование РеквизитФормыВЗначение внутри формы списка для изменения выбранных документов — это грубая методологическая ошибка.

Анализ сопутствующих ошибок в коде

Давайте посмотрим на исходный код, который часто пытаются написать начинающие разработчики:


&НаКлиенте
Процедура ЗаполнитьПриложениями(Команда)
    
    ВыделенныеСтроки = Элементы.СписокПиломат.ВыделенныеСтроки;
    
    Для каждого Элемент из ВыделенныеСтроки Цикл
        Если НЕ Элемент.СпецификацияКатВ.Количество() = 0 Тогда // ОШИБКА 1
            // ... вызов сообщения
            Возврат;
        КонецЕсли;
        СпецификацияЗаполнитьПриложенияСервер(); // ОШИБКА 2
    КонецЦикла;
    
КонецПроцедуры

Помимо неверного вызова преобразования реквизита на сервере, в этой процедуре скрываются еще две критические ошибки, которые приведут к падению системы или крайне медленной работе:

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

Ошибка 2. Вызовы сервера в цикле (низкая производительность). Программа совершает сетевой вызов (round-trip) на сервер для каждого выделенного документа. Если пользователь выделит 50 документов, система сделает 50 обращений к серверу. Это приведет к сильным зависаниям интерфейса. По стандартам разработки «1С» все данные должны передаваться на сервер одной порцией, а цикл обработки должен выполняться целиком на стороне сервера.

Правильный алгоритм групповой обработки документов

Чтобы реализовать задачу корректно, нам нужно применить совершенно другой подход, отказавшись от РеквизитФормыВЗначение в пользу классического получения объектов из базы данных.

Разберем по шагам правильную схему работы:

  1. На клиенте мы получаем массив ссылок на выделенные пользователем документы из элемента формы (таблицы списка).
  2. Передаем этот массив на сервер одним-единственным вызовом.
  3. На сервере в цикле обходим переданные ссылки.
  4. Для каждой ссылки получаем полноценный объект из базы данных с помощью метода ПолучитьОбъект().
  5. Проверяем необходимые условия (например, заполненность табличных частей) прямо на сервере.
  6. Вызываем экспортный метод модуля объекта.
  7. Записываем объект в базу данных с помощью метода Записать().
  8. Возвращаем управление на клиент и обновляем динамический список на форме, чтобы пользователь увидел изменения.

Реализация решения на практике

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

Код в модуле формы списка:


&НаКлиенте
Процедура ЗаполнитьПриложениями(Команда)
    
    // Шаг 1. Получаем массив выделенных строк (ссылок на документы)
    ВыделенныеСтроки = Элементы.СписокПиломат.ВыделенныеСтроки;
    Если ВыделенныеСтроки.Количество() = 0 Тогда
        ПоказатьПредупреждение(, "Пожалуйста, выделите хотя бы один документ в списке!");
        Возврат;
    КонецЕсли;
    
    // Шаг 2. Запрашиваем подтверждение операции у пользователя асинхронно
    ТекстВопроса = НСтр("ru='К выделенным в списке документам будут заполнены приложения. Продолжить?'");
    Оповещение = Новый ОписаниеОповещения("ЗаполнитьПриложениямиЗавершение", ЭтотОбъект, ВыделенныеСтроки);
    ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
    
КонецПроцедуры

&НаКлиенте
Процедура ЗаполнитьПриложениямиЗавершение(РезультатВопроса, ДополнительныеПараметры) Экспорт
    
    // Если пользователь отказался — прекращаем работу
    Если РезультатВопроса <> КодВозвратаДиалога.Да Тогда
        Возврат;
    КонецЕсли;
    
    ОчиститьСообщения();
    
    // Шаг 3. Передаем массив ссылок на сервер для обработки
    МассивДокументов = ДополнительныеПараметры;
    ЗаполнитьПриложенияНаСервере(МассивДокументов);
    
    // Шаг 4. Обновляем динамический список, чтобы отобразить новые статусы и данные
    Элементы.СписокПиломат.Обновить();
    
КонецПроцедуры

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

Важные нюансы работы метода ПолучитьОбъект()

Рассмотрим подробнее важные правила работы с методом ПолучитьОбъект(), которые уберегут вас от других типичных ошибок:

Таким образом, понимание разницы между контекстом формы объекта и формы списка позволяет избегать ошибок приведения типов и создавать быстрые, отказоустойчивые групповые обработки в управляемом интерфейсе 1С.

← На главную