Разработчики, работающие с обычными формами в «1С:Предприятии 8», нередко сталкиваются с ситуацией, когда сеанс пользователя аварийно завершается (происходит вылет программы без вывода ошибки) при попытке программно обновить данные в табличном поле. Особенно часто это происходит после создания новых элементов или выполнения тяжелых процедур обновления списков, как в приведенном автором примере с пользователями информационной базы.
В этой статье мы подробно проанализируем, почему происходит критический сбой платформы, какие архитектурные ошибки к этому приводят и как правильно написать процедуру обновления таблицы значений, чтобы гарантировать стабильную работу системы.
Аварийное закрытие процесса 1cv8.exe (часто сопровождающееся ошибкой Access Violation в системном дампе) при выполнении кода автора связано с физическим нарушением работы платформы с памятью. Рассмотрим три основные причины, которые приводят к краху системы в данном сценарии:
Значение элемента управления. Когда мы пишем конструкцию ЭлементыФормы.ПользователиИБ_ТЧ.Значение = ТЗ;, мы пытаемся заменить ссылку на объект в оперативной памяти, которая уже жестко связана с интерфейсным элементом на клиенте. Платформа теряет внутреннюю адресацию, и при последующей попытке перерисовки формы происходит обращение к некорректному адресу памяти, что вызывает мгновенный вылет программы.СоздатьКолонки() в процессе работы формы. Метод СоздатьКолонки() отлично работает на этапе инициализации (например, в обработчике ПередОткрытием или ПриОткрытии). Однако его повторный вызов «на лету» во время интерактивного сеанса пользователя крайне нестабилен. Если у табличного поля изменены свойства колонок (заданы флажки, видимость или свойства только для просмотра), динамическая перестройка метаданных формы приводит к конфликту потоков отрисовки интерфейса.ТекущаяСтрока). Если перед обновлением данных пользователь выделил какую-либо строку в табличном поле, а затем код выполняет Значение.Очистить() или замену таблицы, выделенный объект уничтожается. При выходе из процедуры платформа пытается восстановить фокус на ранее активной строке по старому индексу или указателю. Поскольку объект больше не существует, происходит критический сбой адресации.Чтобы избежать аварийного завершения работы программы, нам необходимо отказаться от прямой замены объекта таблицы значений в элементе управления и правильно организовать передачу данных. Разберем пошагово, как переписать процедуру обновления.
Рекомендуется один раз настроить колонки табличного поля. Сделать это можно интерактивно в конфигураторе, связав табличное поле с реквизитом формы (типа ТаблицаЗначений), у которого уже определены все необходимые колонки (включая Пометка, УникальныйИдентификатор и т.д.). В этом случае нам вообще не понадобится вызывать метод СоздатьКолонки() во время работы пользователя.
Перед очисткой и заполнением таблицы обязательно сбрасываем текущую строку элемента управления, чтобы платформа не пыталась вернуть фокус на несуществующий объект:</p
ЭлементыФормы.ПользователиИБ_ТЧ.ТекущаяСтрока = Неопределено;
Загрузить() вместо переприсвоения значенияВместо работы со свойством Значение элемента формы, мы должны обратиться напрямую к реквизиту формы, который выступает источником данных (в нашем примере это реквизит формы с именем ПользователиИБ_ТЧ). Нам нужно загрузить новые данные в этот реквизит с помощью метода Загрузить(), который корректно обновляет строки, сохраняя структуру объекта в памяти:</p
// Получаем свежие данные
ПользователиИБ = ПолучитьПользователейИБ();
ТЗ = КонвертироватьМассивПользователейВТЗ(ПользователиИБ);
// Загружаем данные в реквизит формы (а не в ЭлементыФормы)
ПользователиИБ_ТЧ.Загрузить(ТЗ);
Если структуры колонок реквизита формы и временной таблицы ТЗ не совпадают идеально, безопаснее использовать построчный перенос данных с очисткой:</p
ПользователиИБ_ТЧ.Очистить();
Для Каждого СтрокаТЗ Из ТЗ Цикл
ЗаполнитьЗначенияСвойств(ПользователиИБ_ТЧ.Добавить(), СтрокаТЗ);
КонецЦикла;
Программная привязка свойств ДанныеФлажка «на лету» часто вызывает сбои. Чтобы безопасно отображать флажки в табличном поле, лучше использовать стандартное событие табличного поля ПриВыводеСтроки.
Для этого в свойствах колонки Пометка убираем динамическую привязку данных, а в модуле формы определяем следующий обработчик:</p
Процедура ПользователиИБ_ТЧПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Устанавливаем отображение флажка на основе данных строки
ОформлениеСтроки.Ячейки.Пометка.ОтображатьФлажок = Истина;
ОформлениеСтроки.Ячейки.Пометка.Флажок = ДанныеСтроки.Пометка;
КонецПроцедуры
Давайте объединим все рекомендации в единую надежную процедуру обновления данных на форме. Предположим, что на форме создан реквизит ПользователиИБ_ТЧ с типом ТаблицаЗначений, колонки которого настроены в конфигураторе:</p
Процедура ОбновитьСписокПользователейНаФорме()
// Предотвращаем падение из-за потери фокуса строки
ЭлементыФормы.ПользователиИБ_ТЧ.ТекущаяСтрока = Неопределено;
// Получаем актуальный массив пользователей ИБ
ПользователиИБ = ПолучитьПользователейИБ();
// Конвертируем в таблицу значений
ТЗ = КонвертироватьМассивПользователейВТЗ(ПользователиИБ);
// Очищаем реквизит формы и загружаем новые данные
ПользователиИБ_ТЧ.Очистить();
Для Каждого СтрокаТЗ Из ТЗ Цикл
ЗаполнитьЗначенияСвойств(ПользователиИБ_ТЧ.Добавить(), СтрокаТЗ);
КонецЦикла;
// Оповещаем элемент управления о необходимости обновить отображение
ЭлементыФормы.ПользователиИБ_ТЧ.ОбновитьСтроки();
КонецПроцедуры
Используя данный подход, вы полностью исключите вероятность аварийного завершения работы платформы 1С при обновлении списков. Данные будут обновляться плавно и безопасно для пользователя.