Как изменить доступность элементов из другой формы в 1С?

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

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

Архитектурная разница: обычные и управляемые формы

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

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

Способ 1: Использование механизма "Оповестить"

Это наиболее корректный и универсальный путь для управляемых форм. Мы отправляем широковещательное сообщение в системе с помощью глобального метода Оповестить. Форма-получатель перехватывает его через обработчик ОбработкаОповещения.

Посмотрим на пример реализации. В форме-отправителе (где мы нажимаем кнопку или выполняем действие) мы пишем следующий код:


&НаКлиенте
Процедура КнопкаИзменитьДоступность(Команда)
    // Отправляем сигнал всем открытым формам
    // 1-й параметр - уникальное имя события
    // 2-й параметр - передаваемые данные (например, флаг Истина/Ложь)
    Оповестить("УстановитьДоступностьЭлемента", Истина);
КонецПроцедуры

Теперь разберем, что делать в форме-получателе. Нам необходимо создать стандартный обработчик события. Выясним причину, почему важно проверять имя события: метод Оповестить является глобальным, его "услышат" абсолютно все формы, открытые в текущем сеансе. Чтобы наша форма не реагировала на чужие команды, мы делаем проверку:


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

Способ 2: Использование экспортных методов формы

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

В модуле формы-получателя пишем метод с ключевым словом Экспорт:


&НаКлиенте
Процедура ОбновитьСостояниеЭлементов(СостояниеДоступности) Экспорт
    // Форма сама решает, как ей менять свои элементы
    Элементы.НужныйЭлемент.Доступность = СостояниеДоступности;
КонецПроцедуры

Из формы-отправителя мы обращаемся к этому методу следующим образом:


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

Важное предупреждение: Метод ПолучитьФорму без указания уникального ключа может создать новую, скрытую (еще не открытую) копию формы. Если пользователь уже работает с этой формой на экране, вам обязательно нужно обращаться именно к существующему экземпляру, передавая ключ уникальности (например, ссылку на объект), иначе изменения не отразятся в интерфейсе пользователя.

Способ 3: Обращение через владельца формы (ВладелецФормы)

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

  1. При открытии дочерней формы мы явно передаем текущую форму в качестве владельца:

&НаКлиенте
Процедура ОткрытьПодчиненнуюФорму(Команда)
    // Параметр ЭтаФорма выступает в роли владельца
    ОткрытьФорму("Обработка.НашаОбработка.Форма.ФормаВвода", , ЭтаФорма);
КонецПроцедуры
  1. В открытой (дочерней) форме мы обращаемся к родительской через свойство ВладелецФормы и вызываем её экспортный метод:

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

Способ 4: Передача параметров при открытии

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

При вызове ОткрытьФорму формируем структуру параметров:


&НаКлиенте
Процедура ОткрытьСПараметром(Команда)
    ПараметрыОткрытия = Новый Структура("БлокироватьКнопку", Истина);
    ОткрытьФорму("Справочник.НашСправочник.Форма.ФормаЭлемента", ПараметрыОткрытия);
КонецПроцедуры

В самой открываемой форме в обработчике ПриСозданииНаСервере мы анализируем эти параметры:


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

Ограничения клиент-серверного взаимодействия

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

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

← На главную