Почему 1С:Предприятие вылетает при изменении видимости элементов формы и как это исправить?

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

Разработчики управляемых форм в 1С:Предприятии 8.3 иногда сталкиваются с крайне неприятной проблемой: при выполнении вполне стандартного кода по изменению видимости или доступности элементов интерфейса платформа неожиданно закрывается с критической ошибкой. Операционная система при этом выдает стандартное окно с сообщением о том, что работа программы прекращена, и Windows осуществляет поиск способа устранения этой ошибки.

Особенно часто это происходит в версиях платформы начиная с 8.3.14. В этой статье мы подробно разберем, почему возникает данная проблема, проанализируем внутренние механизмы работы платформы и рассмотрим четыре надежных способа обхода этой системной ошибки.

Выясняем причину: почему падает платформа?

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

Посмотрим на исходный код обработчиков событий:


&НаКлиенте
Процедура КлиентОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, СтандартнаяОбработка)
     Если Клиент.Пустая() Тогда
         Ответ = Вопрос("Данного клиента нет в базе. Создать нового?", РежимДиалогаВопрос.ДаНет);
         Если Ответ = КодВозвратаДиалога.Да Тогда
             КлиентФИО = Текст;
             Переключатель = 1;
             ПереключательПриИзменении(Неопределено);
         КонецЕсли; 
     КонецЕсли; 
КонецПроцедуры

&НаКлиенте   
Процедура ПереключательПриИзменении(Элемент)
    СтруктураЗаголовков = ПолучитьЗаголовкиФормы(); // Вызов сервера
    Если Переключатель = 0 Тогда
        Элементы.Шаг12.Видимость = Ложь;
        Заголовок = СтруктураЗаголовков.Заголовок11;
        Элементы.Шаг11.Видимость = Истина;
    ИначеЕсли Переключатель = 1 Тогда
        Элементы.Шаг11.Видимость = Ложь; // Точка сбоя!
        Заголовок = СтруктураЗаголовков.Заголовок12;
        // ... дальнейшая серверная логика заполнения данных ...
        Элементы.Шаг12.Видимость = Истина;
    КонецЕсли;
КонецПроцедуры

На первый взгляд код выглядит логичным, однако в нем кроется фундаментальное нарушение правил работы клиент-серверного взаимодействия управляемого интерфейса 1С. Выделим три ключевые причины, по которым этот код заставляет платформу аварийно завершать работу:

  1. Недопустимый контекст выполнения события: Обработчик события ОкончаниеВводаТекста выполняется в интерактивном режиме ожидания ввода. В соответствии со встроенной справкой платформы (Синтаксис-Помощником), в обработчике этого события строго запрещено использовать контекстные серверные вызовы формы (методы с директивой &НаСервере).
  2. Рекурсивное изменение структуры UI-дерева: Когда мы изменяем свойство Видимость для элемента формы, на котором в данный момент сфокусирован ввод (или который находится в процессе завершения редактирования), платформа инициирует немедленный пересчет геометрии всей формы. Пытаясь перестроить интерфейс в тот момент, когда поле ввода еще не завершило передачу данных и не потеряло фокус, движок отрисовки (UI-поток тонкого клиента) уходит в бесконечную рекурсию или обращается к некорректным адресам памяти. Это вызывает ошибку нарушения доступа (Access Violation) на уровне операционной системы.
  3. Интерактивные диалоги внутри обработчиков ввода: Использование синхронного метода Вопрос() блокирует выполнение потока в момент ввода текста. Это нарушает стандартную последовательность системных событий фокуса ввода и усугубляет нестабильность платформы.

Рассмотрим подробнее четыре практических способа решения этой проблемы, которые позволят сделать ваш код стабильным и безопасным.

---

Решение 1: Использование однократного обработчика ожидания (Рекомендуемый способ)

Самый надежный способ предотвратить падение платформы — это разорвать непрерывный цикл выполнения интерфейсных событий. Мы можем отложить выполнение тяжелой логики переключения видимости и серверных вызовов. Для этого отлично подходит встроенный механизм платформы ПодключитьОбработчикОжидания.

Идея заключается в том, чтобы в самом событии ОкончаниеВводаТекста лишь зафиксировать намерение изменить интерфейс, а саму процедуру переключения вызвать через микроскопическую паузу (например, 0.1 секунды). За это время поле ввода успеет корректно завершить свою работу, передать данные в фоновом режиме и безопасно освободить системные ресурсы.

Реализуем этот подход на практике. Изменим наш код следующим образом:


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

&НаКлиенте
Процедура ПослеВопросаОСозданииКлиента(РезультатВыбора, ДополнительныеПараметры) Экспорт
    Если РезультатВыбора = КодВозвратаДиалога.Да Тогда
        КлиентФИО = ДополнительныеПараметры; // Переносим текст в реквизит формы
        Переключатель = 1;
        
        // Подключаем однократный обработчик ожидания с задержкой 0.1 секунды
        ПодключитьОбработчикОжидания("ВыполнитьПереключениеИнтерфейса", 0.1, Истина);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьПереключениеИнтерфейса() Экспорт
    // Данный метод вызывается вне контекста ввода текста. Платформа находится в состоянии покоя.
    // Теперь мы можем безопасно вызывать серверные методы и менять видимость любых элементов.
    ПереключательПриИзменении(Неопределено);
КонецПроцедуры

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

---

Решение 2: Замена управления видимостью на переключение страниц формы

Если специфика вашей задачи требует частого и динамического переключения экранов (например, при реализации пошагового мастера ввода данных "Мастер настройки" или "Помощник создания"), постоянное изменение свойств Видимость = Истина/Ложь у большого количества элементов перегружает систему отрисовки. Платформа вынуждена каждый раз полностью пересчитывать положение всех соседних элементов формы.

Значительно более производительным и безопасным решением является использование панели страниц со скрытыми закладками:

  1. Добавьте на форму элемент типа Группа - Страницы (например, с именем ГруппаШаги).
  2. Установите у этой группы свойство ОтображениеЗакладок в значение Не отображать.
  3. Внутри этой группы создайте несколько подчиненных элементов типа Группа - Страница (например, СтраницаШаг1 и СтраницаШаг2).
  4. Разместите элементы вашего интерфейса на соответствующих страницах.

Теперь вместо небезопасного изменения видимости отдельных элементов вы можете просто переключать активную страницу одной строкой кода:


&НаКлиенте
Процедура ПереключитьНаВторойШаг()
    // Этот код работает мгновенно и не приводит к перестроению дерева элементов
    Элементы.ГруппаШаги.ТекущаяСтраница = Элементы.СтраницаШаг2;
КонецПроцедуры

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

---

Решение 3: Использование свойства "Доступность" вместо "Видимости"

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

Давайте посмотрим на разницу в поведении платформы:


// Небезопасно в интерактивных обработчиках: вызывает полный пересчет геометрии формы
Элементы.ИмяЭлемента.Видимость = Ложь;

// Безопасно: элемент остается на своем месте, меняется лишь его визуальное состояние блокировки
Элементы.ИмяЭлемента.Доступность = Ложь;

Поскольку при изменении доступности координаты элементов формы не меняются, платформа не выполняет сложных расчетов позиционирования и не обращается к графической подсистеме операционной системы для перерисовки дерева контейнеров. Это гарантирует стабильность работы даже на устаревших релизах платформы 1С.

---

Решение 4: Перенос логики в событие "ПриИзменении" или "ОбработкаВыбора"

Проанализируем архитектуру событий поля ввода. Событие ОкончаниеВводаТекста предназначено исключительно для предобработки строки, которую пользователь набрал на клавиатуре перед тем, как система попытается найти этот объект в базе данных. Выполнять в нем тяжелую бизнес-логику (создавать элементы справочников, открывать новые формы, менять интерфейс) — это архитектурная ошибка.

Если вам нужно отреагировать на то, что пользователь выбрал или ввел определенное значение, гораздо правильнее использовать событие ПриИзменении. В этот момент ввод данных уже завершен, значение записано в реквизит формы, а фокус ввода может быть безопасно передан другому элементу.

Рассмотрим пример правильного распределения логики:


&НаКлиенте
Процедура КлиентПриИзменении(Элемент)
    // Значение реквизита "Клиент" уже заполнено и проверено системой
    Если Не ЗначениеЗаполнено(Клиент) Тогда
        Возврат;
    КонецЕсли;
    
    // Здесь мы можем безопасно вызывать любые процедуры переключения видимости
    ПереключитьИнтерфейсПодКлиента();
КонецПроцедуры

Подведем итоги

Аварийное завершение работы платформы при изменении видимости — это следствие конфликта между активным состоянием фокуса ввода элемента и мгновенным требованием платформы перерисовать интерфейс. Чтобы избежать подобных ошибок в своей практике, придерживайтесь простых правил:

Применение этих подходов сделает ваши управляемые формы надежными, быстрыми и застрахует пользователей от внезапной потери несохраненных данных из-за вылетов программы.

← На главную