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