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