Как открыть управляемую форму только для просмотра, оставив один элемент редактируемым?

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

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

Изначально, разработчики могут столкнуться с двумя основными проблемами при попытке реализовать такую логику:

  1. Попытка установить свойство Доступность=Ложь для каждого элемента формы в цикле может привести к ошибке, если на форме присутствуют элементы, для которых это свойство недоступно, например, декорации или группы.
  2. Установка свойства ЭтаФорма.ТолькоПросмотр = Истина не позволяет индивидуально разблокировать отдельные элементы, так как свойство формы имеет более высокий приоритет.

Мы выясним причины этих проблем и предложим несколько методов их решения.

Понимание проблемных сценариев

Проблема 1: Ошибка при установке Доступность=Ложь для всех элементов

Когда мы пытаемся пройти по всем элементам формы и установить для них свойство Доступность = Ложь, используя цикл, как показано в первом сообщении:


Для каждого Элемент из ЭтаФорма.Элементы Цикл 
    Элемент.Доступность=Ложь; 
КонецЦикла; 
ЭтаФорма.Элементы.УдПричина.Доступность=Истина;

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

Проблема 2: Приоритет свойства ТолькоПросмотр на уровне формы

Второй распространенный подход, который кажется логичным, но не работает так, как ожидается, это установка свойства ТолькоПросмотр = Истина для всей формы, а затем попытка разблокировать конкретный элемент — для этой задачи есть инструмент управления видимостью и доступностью полей без кода:


ЭтаФорма.ТолькоПросмотр=Истина; 
ЭтаФорма.Элементы.УдПричина.Доступность=Истина;

Как указано в сообщении 7 и в дополнительной информации, свойство ЭтаФорма.ТолькоПросмотр = Истина имеет более высокий приоритет. Оно блокирует все элементы формы, которые привязаны к данным конфигурации (реквизитам объекта, табличных частей и т.д.), независимо от того, как мы пытаемся установить индивидуальные свойства Доступность или ТолькоПросмотр для отдельных элементов. Это означает, что даже если мы явно укажем ЭтаФорма.Элементы.УдПричина.Доступность=Истина;, элемент УдПричина все равно останется заблокированным, если он привязан к данным объекта.

Теперь, когда мы понимаем причины проблем, давайте рассмотрим рабочие решения.

Решения для открытия формы только для просмотра, за исключением одного элемента

Существует несколько подходов к решению данной задачи. Мы подробно разберем каждый из них.

1. Итерация по элементам с учетом их типа и обработкой исключений

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

Шаг 1: Исключение элементов по типу

Чтобы избежать ошибки "Данное свойство недоступно для декорации...", мы можем добавить проверку типа элемента внутри цикла. Если элемент относится к типу, который не поддерживает свойство Доступность (например, ЭлементФормыДекорация или ГруппаФормы), мы просто пропускаем его.

Давайте посмотрим на пример кода, предложенный в сообщении 4:


&НаСервере
Процедура УстановитьДоступностьЭлементов()
    Для каждого Элемент из ЭтаФорма.Элементы Цикл 
        Если ТипЗнч(Элемент) = Тип("ЭлементФормыДекорация") Тогда 
            Продолжить; // Пропускаем декорации
        КонецЕсли;

        // Также можем исключить группы, если не хотим устанавливать их Доступность/ТолькоПросмотр
        Если ТипЗнч(Элемент) = Тип("ГруппаФормы") Тогда 
            Продолжить; 
        КонецЕсли;
        
        // Устанавливаем ТолькоПросмотр для всех элементов, кроме исключений
        Если Элемент.Имя <> "УдПричина" Тогда
            Элемент.ТолькоПросмотр = Истина;
        Иначе
            Элемент.ТолькоПросмотр = Ложь; // Разрешаем редактирование для УдПричина
        КонецЕсли;
    КонецЦикла; 
КонецПроцедуры

В этом примере мы используем функцию ТипЗнч() для определения типа элемента. Если тип элемента соответствует ЭлементФормыДекорация или ГруппаФормы, мы используем оператор Продолжить, чтобы перейти к следующей итерации цикла, избегая попытки установить недоступное свойство. Обратите внимание, что мы устанавливаем свойство ТолькоПросмотр для элементов, а не Доступность, поскольку ТолькоПросмотр более точно отражает задачу "форма только для просмотра".

Шаг 2: Использование конструкции Попытка...Исключение

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


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

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

Важно помнить, что изменение свойств элементов формы (таких как Доступность и ТолькоПросмотр) может быть выполнено как на сервере (в процедурах с директивой &НаСервере или &НаСервереБезКонтекста), так и на клиенте. В нашем случае, код приведен для выполнения на сервере, как это указано в первом сообщении автора. Для интерактивной проверки и настройки свойств элементов формы в пользовательском режиме можно использовать обработку для редактирования форм в режиме предприятия.

2. Использование реквизитов формы, не привязанных к метаданным

Этот подход является очень эффективным способом обойти приоритет свойства ЭтаФорма.ТолькоПросмотр = Истина. Он основан на том факте, что свойство ТолькоПросмотр на уровне формы блокирует только те элементы, данные которых привязаны к реквизитам объекта метаданных конфигурации (например, к реквизитам документа, справочника).

Как это работает:

Если мы создадим на форме новый реквизит формы (не реквизит объекта!), а затем свяжем с ним наш элемент, который должен оставаться редактируемым (например, поле ввода УдПричина), то установка ЭтаФорма.ТолькоПросмотр = Истина не заблокирует этот элемент.

Шаги реализации:

  1. Переходим в раздел "Реквизиты" формы.
  2. Добавляем новый реквизит формы (например, с именем ПричинаУдаленияФормы) с типом, соответствующим данным, которые будут вводиться в поле (например, Строка).
  3. Переходим в раздел "Элементы" формы.
  4. Создаем новый элемент формы (например, "Поле ввода") и в его свойствах устанавливаем "Путь к данным" на наш новый реквизит формы: ПричинаУдаленияФормы. Если элемент УдПричина уже существует, мы можем изменить его "Путь к данным" на наш реквизит формы.
  5. Теперь мы можем смело устанавливать ЭтаФорма.ТолькоПросмотр = Истина;. Все элементы, привязанные к данным объекта, будут заблокированы, но наш элемент УдПричина (связанный с реквизитом формы ПричинаУдаленияФормы) останется доступным для редактирования.
  6. После того как пользователь введет данные в этот элемент, нам потребуется программно сохранить эти данные в соответствующий реквизит объекта (например, в реквизит объекта ПричинаУдаления) при записи формы или в другой подходящий момент — задача решается через настройку запрета записи и контроля заполнения реквизитов.

&НаСервере
Процедура ПриЗаписиНаСервере(Отказ)
    // Предполагаем, что Объект.ПричинаУдаления - это реквизит объекта,
    // а ПричинаУдаленияФормы - это реквизит формы, к которому привязан элемент УдПричина
    Объект.ПричинаУдаления = ПричинаУдаленияФормы; 
КонецПроцедуры

&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
    // При открытии формы заполняем реквизит формы данными из объекта
    ПричинаУдаленияФормы = Объект.ПричинаУдаления;
    
    // Устанавливаем форму в режим "только просмотр"
    ЭтаФорма.ТолькоПросмотр = Истина; 
КонецПроцедуры

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

3. Группировка элементов для управления доступом

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

Шаги реализации:

  1. Создаем на форме новую группу (например, "ГруппаТолькоПросмотр").
  2. Перемещаем в эту группу все элементы формы, которые должны быть доступны только для просмотра.
  3. Для этой группы устанавливаем свойство ТолькоПросмотр = Истина.
  4. Элемент, который должен оставаться редактируемым (УдПричина), либо оставляем вне этой группы, либо помещаем в отдельную группу, для которой свойство ТолькоПросмотр не установлено или установлено в Ложь.

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

4. Комплексное решение с учетом различных типов элементов и командных панелей

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

Представленный код работает на сервере и позволяет гибко управлять свойствами ТолькоПросмотр и Доступность для различных элементов формы.


&НаСервере 
Процедура УстановитьДоступностьСервер(СписокТолькоПросмотр, МожноРедактировать, МожноРедактироватьПереводЦены) // Параметры для гибкости
    // 1. Итерация по всем элементам формы
    Для каждого Эл Из Элементы Цикл 
        // 2. Исключаем группы формы из обработки, так как для них Доступность/ТолькоПросмотр может устанавливаться иначе
        Если ТипЗнч(Эл)=Тип("ГруппаФормы") Тогда 
            Продолжить; 
        КонецЕсли;

        // 3. Проверка, находится ли элемент внутри табличной части (ТаблицаФормы)
        ЭтоТаблица = Ложь;
        Р = Эл.Родитель;
        Пока ТипЗнч(Р)<>Тип("УправляемаяФорма") Цикл // Поднимаемся по иерархии родителей до самой формы
            Если ТипЗнч(Р)=Тип("ТаблицаФормы") Тогда // Если нашли родителя типа ТаблицаФормы
                ЭтоТаблица = Истина;
                Прервать; // Выходим из внутреннего цикла
            КонецЕсли;
            Р = Р.Родитель;
        КонецЦикла;
        
        // 4. Если элемент находится в табличной части, пропускаем его
        // Доступность элементов табличной части обычно управляется через свойства самой таблицы или ее колонки
        Если ЭтоТаблица Тогда 
            Продолжить; 
        КонецЕсли;
        
        // 5. Попытка установить свойство ТолькоПросмотр
        Попытка 
            // Если имя элемента не содержится в списке исключений (СписокТолькоПросмотр)
            // или если мы в целом не должны редактировать (Не МожноРедактировать)
            Если СписокТолькоПросмотр.НайтиПоЗначению(Эл.Имя)=Неопределено Тогда 
                Эл.ТолькоПросмотр = Не МожноРедактировать; // Устанавливаем ТолькоПросмотр в зависимости от флага
            КонецЕсли;
        Исключение 
            // Если возникла ошибка (например, свойство недоступно для данного типа элемента), пропускаем
        КонецПопытки; 
    КонецЦикла; 
    
    // 6. Управление доступностью конкретных элементов (в данном случае связанных с "Переводом Цены")
    // Это пример индивидуальной настройки для определенных полей
    Если МожноРедактироватьПереводЦены Тогда 
        Элементы.ПереводЦены.Доступность = Истина; 
        Элементы.ПереводЦены.ТолькоПросмотр = Ложь; 
        Элементы.ПереводДни.ТолькоПросмотр = Ложь; 
        Элементы.ПереводДниРабочие.ТолькоПросмотр = Ложь; 
        Элементы.ПереводДата.ТолькоПросмотр = Ложь; 
        Элементы.ПереводОснование.ТолькоПросмотр = Ложь; 
        Элементы.ПереводВыполнен.ТолькоПросмотр = Ложь; 
        Элементы.ПереводВыполненОснование.ТолькоПросмотр = Ложь; 
    КонецЕсли; 
    
    // 7. Управление доступностью элементов командной панели
    // Для кнопок командной панели также можно установить Доступность
    Попытка 
        ЭтаФорма.КоманднаяПанель.ПодчиненныеЭлементы.ФормаПровестиИЗакрыть.Доступность = МожноРедактировать ИЛИ МожноРедактироватьПереводЦены; 
    Исключение 
    КонецПопытки; 
    Попытка 
        ЭтаФорма.КоманднаяПанель.ПодчиненныеЭлементы.ФормаПроведение.ПодчиненныеЭлементы.ФормаПровести.Доступность = МожноРедактировать ИЛИ МожноРедактироватьПереводЦены; 
    Исключение 
    КонецПопытки; 
    Попытка 
        ЭтаФорма.КоманднаяПанель.ПодчиненныеЭлементы.ФормаУстановитьПометкуУдаления.Доступность = МожноРедактировать; 
    Исключение 
    КонецПопытки; 
КонецПроцедуры

Давайте подробно разберем этот комплексный пример:

  1. Итерация по элементам формы: Цикл Для каждого Эл Из Элементы Цикл позволяет нам пройти по всем элементам, размещенным на форме.
  2. Исключение групп формы: Строка Если ТипЗнч(Эл)=Тип("ГруппаФормы") Тогда Продолжить; КонецЕсли; исключает группы из общей обработки. У групп свои особенности по управлению доступностью и свойством ТолькоПросмотр, и их часто настраивают отдельно или через родительские группы.
  3. Проверка принадлежности к табличной части: Этот блок кода определяет, является ли текущий элемент частью табличной части (ТаблицаФормы). Это важно, потому что элементы внутри таблиц обычно управляются через свойства самих колонок или всей таблицы, а не напрямую. Мы поднимаемся по иерархии родителей элемента (Эл.Родитель), пока не достигнем самой формы (Тип("УправляемаяФорма")) или не найдем ТаблицаФормы.
  4. Исключение элементов табличной части: Если элемент находится внутри ТаблицаФормы (флаг ЭтоТаблица истинен), мы его пропускаем, чтобы избежать конфликтов в управлении доступностью.
  5. Установка свойства ТолькоПросмотр с обработкой ошибок:
    • Попытка ... Исключение: Здесь используется конструкция Попытка...Исключение, которая делает код более устойчивым к ошибкам. Если для какого-то элемента свойство ТолькоПросмотр не поддерживается, это не приведет к падению программы.
    • СписокТолькоПросмотр: Это предполагается как параметр процедуры (или реквизит формы), содержащий список имен элементов, для которых не нужно устанавливать ТолькоПросмотр=Истина. Если имя текущего элемента Эл.Имя не найдено в этом списке (СписокТолькоПросмотр.НайтиПоЗначению(Эл.Имя)=Неопределено), то для него применяется правило установки ТолькоПросмотр.
    • Не МожноРедактировать: Это логический флаг, который, вероятно, передается в процедуру как параметр. Если МожноРедактировать истина, то Не МожноРедактировать будет ложью, и элемент не будет только для просмотра. И наоборот. Таким образом, мы глобально управляем режимом просмотра.
  6. Индивидуальная настройка конкретных элементов: Блок Если МожноРедактироватьПереводЦены Тогда ... КонецЕсли; показывает, как можно индивидуально управлять доступностью и режимом просмотра для заранее известных элементов (например, группы полей, связанных с "Переводом Цены"), в зависимости от определенных условий (МожноРедактироватьПереводЦены). Здесь для этих элементов явно устанавливается Доступность=Истина и ТолькоПросмотр=Ложь.
  7. Управление доступностью командной панели: С помощью конструкции Попытка...Исключение и обращения к ЭтаФорма.КоманднаяПанель.ПодчиненныеЭлементы мы можем управлять доступностью кнопок на командной панели формы (например, "Провести и закрыть", "Провести", "Установить пометку удаления"). Это очень важно, так как блокировка полей ввода может быть недостаточной, если пользователь все равно может выполнить действия через кнопки.

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

Резюме и рекомендации

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

  1. Если вы сталкиваетесь с ошибками при переборе элементов, используйте проверку типа элемента (Если ТипЗнч(Элемент) = Тип("ЭлементФормыДекорация") Тогда Продолжить;) или конструкцию Попытка...Исключение.
  2. Помните, что ЭтаФорма.ТолькоПросмотр = Истина блокирует элементы, привязанные к метаданным объекта. Чтобы обойти это, либо устанавливайте ТолькоПросмотр=Истина для каждого элемента индивидуально, либо используйте реквизиты формы, не привязанные к метаданным для редактируемых элементов.
  3. Для больших форм или сложных структур рассмотрите возможность группировки элементов и управления свойством ТолькоПросмотр на уровне групп.
  4. Для максимально гибкого контроля, включая элементы командных панелей и элементы табличных частей, используйте итеративный подход с проверками типов, иерархии и Попытка...Исключение, как показано в комплексном примере.

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

← На главную