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