Как управлять доступностью элемента строки дерева значений в 1С

Программист 1С v8.3 (Обычные формы)
← На главную

В процессе разработки интерфейсов на обычных формах (не управляемых) часто возникает задача ограничить редактирование конкретных строк или ячеек в дереве значений. Например, если статус объекта в строке отличается от значения Новый, мы должны запретить пользователю изменять флажки или вводить данные в этой строке. В отличие от управляемых форм, где используется "Условное оформление", в обычных формах механизм управления внешним видом и поведением ячеек завязан на событиях табличного поля. Рассмотрим подробно, как правильно реализовать эту логику.

Анализ проблемы: почему стандартная доступность не работает?

Разберем типичную ошибку начинающих разработчиков. Часто пытаются управлять доступностью непосредственно через объект данных строки, например, так: СтрокаДерева.МояКолонка.Доступность = Ложь;. Проанализируем, почему это не сработает: объект СтрокаДерева — это строка ДереваЗначений, которая содержит только данные (числа, строки, ссылки). У этих данных нет свойства Доступность. Это свойство относится исключительно к элементам управления на форме или к оформлению ячеек табличного поля.

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

Решение 1: Использование события ПриВыводеСтроки

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


Процедура ДеревоЗначенийВходногоКонтроляПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    // Проверяем статус из данных текущей строки
    Если ДанныеСтроки.Статус = Перечисления.ТХ_СтатусыВходногоКонтроля.Новый Тогда
        
        // Окрашиваем строку в белый цвет
        ОформлениеСтроки.ЦветФона = WebЦвета.Белый;
        
        // Скрываем флажок в конкретной ячейке, чтобы пользователь не мог его нажать
        ОформлениеСтроки.Ячейки.НачатьПроверку.ОтображатьФлажок = Ложь;
        
    ИначеЕсли ДанныеСтроки.Статус = Перечисления.ТХ_СтатусыВходногоКонтроля.ВыполняетсяПроверка Тогда
        
        ОформлениеСтроки.ЦветФона = WebЦвета.Желтый;
        // Устанавливаем режим "Только просмотр" для ячейки
        ОформлениеСтроки.Ячейки.НачатьПроверку.ТолькоПросмотр = Истина;
        
    ИначеЕсли ДанныеСтроки.Статус = Перечисления.ТХ_СтатусыВходногоКонтроля.ПроверкаПройденаУспешно Тогда
        
        ОформлениеСтроки.ЦветФона = WebЦвета.Зеленый;
        ОформлениеСтроки.Ячейки.НачатьПроверку.ТолькоПросмотр = Истина;
        
    КонецЕсли;
        
КонецПроцедуры

Важные моменты:

  1. Параметр ОформлениеСтроки позволяет нам обращаться к коллекции Ячейки. Каждая ячейка имеет свойства ТолькоПросмотр, Доступность, ОтображатьФлажок, ЦветТекста и другие.
  2. Использование ТолькоПросмотр = Истина предпочтительнее, чем Доступность = Ложь, так как во втором случае ячейка полностью исключается из навигации (на неё нельзя кликнуть), что иногда путает пользователя.
  3. Если в колонке используется тип "Булево" (флажок), то свойство ОтображатьФлажок = Ложь полностью скрывает элемент управления из ячейки.

Решение 2: Рекурсивное управление родительскими ветками

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

Проанализируем алгоритм: нам нужно создать рекурсивную процедуру, которая будет обходить дерево вверх от измененного элемента. Рассмотрим пример реализации:


Процедура УстановитьСостояниеРодителя(РодительскаяВетка)
    
    Если РодительскаяВетка = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ВсеДочерниеЗаблокированы = Истина;
    
    Для Каждого ПодчиненнаяСтрока Из РодительскаяВетка.Строки Цикл
        // Допустим, у нас есть скрытая колонка "РазрешеноРедактирование"
        Если ПодчиненнаяСтрока.РазрешеноРедактирование Тогда
            ВсеДочерниеЗаблокированы = Ложь;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    // Обновляем данные в родителе
    РодительскаяВетка.РазрешеноРедактирование = НЕ ВсеДочерниеЗаблокированы;
    
    // Идем выше по иерархии
    УстановитьСостояниеРодителя(РодительскаяВетка.Родитель);
    
КонецПроцедуры

Эту логику лучше вызывать в момент первоначального заполнения дерева или при изменении статуса в строке. В самом же событии ПриВыводеСтроки мы будем просто считывать значение из колонки РазрешеноРедактирование и устанавливать ОформлениеСтроки.Ячейки.ИмяКолонки.ТолькоПросмотр.

Решение 3: Защита данных в событии ПередНачаломИзменения

Не стоит забывать, что визуальное оформление (серый цвет или скрытый флажок) — это лишь внешняя оболочка. Опытный пользователь может попытаться изменить значение горячими клавишами. Чтобы гарантированно запретить редактирование, проанализируем использование события ПередНачаломИзменения самого табличного поля:


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

Этот метод является самым надежным с точки зрения целостности данных, так как он блокирует саму возможность открытия редактора в ячейке.

Оптимизация производительности: ПриПолученииДанных

Если ваше дерево содержит тысячи строк, событие ПриВыводеСтроки может существенно замедлить работу интерфейса при прокрутке, так как оно вызывается для каждой строки отдельно. В таких случаях рассмотрим альтернативный метод — ПриПолученииДанных.

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

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

  1. Для визуальной блокировки отдельных ячеек используйте ОформлениеСтроки.Ячейки.ИмяЯчейки.ТолькоПросмотр = Истина в событии ПриВыводеСтроки.
  2. Чтобы скрыть флажки, применяйте свойство ОтображатьФлажок = Ложь.
  3. Для надежной защиты данных всегда дублируйте логику в событии ПередНачаломИзменения с параметром Отказ = Истина.
  4. Для управления состоянием веток (родительских узлов) используйте рекурсивный обход строк дерева.

Используя эти методы в совокупности, мы получим отзывчивый и защищенный интерфейс, который четко дает понять пользователю, какие данные доступны для редактирования, а какие — нет.

← На главную