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