Как исправить ошибку «Поле объекта недоступно для записи» при изменении строки в форме списка документов 1С?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Торговля и дистрибуция
← На главную

При разработке интерфейсов на обычных формах часто возникает задача отметить документ флагом или изменить статус прямо из формы списка. Начинающие разработчики нередко пытаются присвоить значение напрямую свойству текущей строки табличного поля (например, ТекСтрока.СтатусКнопки = Истина;) и сталкиваются с исключением платформы «Поле объекта недоступно для записи». Разберем причины возникновения этой ошибки и детально рассмотрим способы корректной модификации данных и реализации интерфейсных флажков.

Проанализируем природу элементов управления списка и выясним, почему прямое присвоение вызывает ошибку выполнения.

Причины возникновения ошибки

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

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

Способ 1. Изменение реквизита через получение объекта документа

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

  1. Получаем ссылку на текущий выделенный документ из строки списка.
  2. Проверяем заполненность ссылки с помощью функции ЗначениеЗаполнено(), чтобы исключить попытку модификации пустых строк или заголовков группировок.
  3. С помощью метода ПолучитьОбъект() считываем объект документа из базы данных в оперативную память.
  4. Присваиваем новое значение реквизиту объекта.
  5. Записываем измененный объект с обязательной обработкой исключений через конструкцию Попытка ... Исключение.

Посмотрим на пример правильного кода обработчика нажатия кнопки:


ТекСтрока = ЭтаФорма.ЭлементыФормы.Список.ТекущаяСтрока;

Если ТекСтрока <> Неопределено И ЗначениеЗаполнено(ТекСтрока.Ссылка) Тогда
    ДокОбъект = ТекСтрока.Ссылка.ПолучитьОбъект();
    ДокОбъект.ГотовКОтгрузке = Истина;
    
    Попытка
        // Если документ проведен, указываем режим записи без отмены проведения
        ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
    Исключение
        ОбщегоНазначения.СообщитьОбОшибке("Не удалось установить статус: " + ОписаниеОшибки());
    КонецПопытки;
КонецЕсли;

Важный нюанс: Обратите внимание на параметр метода Записать(). Если документ уже проведен, вызов метода без параметров по умолчанию попытается выполнить перепроведение документа. Если требуется лишь обновить значение реквизита без повторного формирования движений по регистрам, следует явно передавать РежимЗаписиДокумента.Запись.

Способ 2. Интерфейсный выбор строк без изменения документов

Нередко флажки в форме списка нужны не для хранения состояния в базе данных, а для временного выделения нескольких строк перед выполнением групповой обработки (например, групповой печати или пакетной выгрузки). В таком случае модифицировать сам документ и создавать лишние реквизиты не требуется. Разберем, как реализовать подобное поведение через событие ПриПолученииДанных.

  1. В модуле формы объявляем переменную для хранения отмеченных ссылок: Перем мОтмеченныеДокументы;
  2. В процедуре ПриОткрытии инициализируем коллекцию: мОтмеченныеДокументы = Новый Соответствие;
  3. В табличное поле списка добавляем колонку флажка (без привязки свойства ДанныеФлажка) и настраиваем обработчик ПриПолученииДанных:
    
    Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
        Для Каждого Оформление Из ОформленияСтрок Цикл
            Оформление.Ячейки.КолонкаФлажка.ОтображатьФлажок = Истина;
            Оформление.Ячейки.КолонкаФлажка.Флажок = (мОтмеченныеДокументы[Оформление.ДанныеСтроки.Ссылка] <> Неопределено);
        КонецЦикла;
    КонецПроцедуры
    
  4. По нажатию кнопки или по клику на ячейку списка инвертируем состояние отметки и принудительно обновляем отображение:
    
    ТекСтрока = ЭлементыФормы.Список.ТекущиеДанные;
    Если ТекСтрока <> Неопределено И ЗначениеЗаполнено(ТекСтрока.Ссылка) Тогда
        Если мОтмеченныеДокументы[ТекСтрока.Ссылка] = Неопределено Тогда
            мОтмеченныеДокументы.Вставить(ТекСтрока.Ссылка, Истина);
        Иначе
            мОтмеченныеДокументы.Удалить(ТекСтрока.Ссылка);
        КонецЕсли;
        ЭлементыФормы.Список.ОбновитьСтроки();
    КонецЕсли;
    

Способ 3. Хранение признака в независимом регистре сведений

Рассмотрим еще один частый сценарий: статус документа должен сохраняться в информационной базе, но изменение самого документа недопустимо (например, документ находится в закрытом для редактирования бухгалтерском периоде или заблокирован другим сеансом). В такой ситуации оптимальным решением является использование независимого регистра сведений:

  1. Создаем непериодический независимый регистр сведений (измерение Документ типа ДокументСсылка, ресурс Статус типа Булево).
  2. Запись статуса производим через менеджер записи регистра, не затрагивая сам документ:
    
    Если ЗначениеЗаполнено(ТекСтрока.Ссылка) Тогда
        МенеджерЗаписи = РегистрыСведений.СтатусыДокументов.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.Документ = ТекСтрока.Ссылка;
        МенеджерЗаписи.Статус   = Истина;
        
        Попытка
            МенеджерЗаписи.Записать(Истина);
            ЭлементыФормы.Список.Обновить();
        Исключение
            Предупреждение("Ошибка при сохранении статуса: " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
    

Таким образом, для устранения ошибки достаточно четко определить задачу: если данные должны сохраняться в самом документе — используем получение объекта через ПолучитьОбъект() с вызовом Записать(); если отметки носят временный характер — используем коллекцию соответствия и событие ПриПолученииДанных; если статус не должен влиять на проведение и период документа — применяем независимый регистр сведений.

← На главную