Начальная страница в 1С:Предприятии 8.3 представляет собой мощный инструмент для организации рабочего пространства пользователя — для этого подойдёт конструктор адаптивных рабочих столов 1С. Часто разработчики и пользователи размещают на ней несколько форм, например, списки справочников, журналы документов, мониторы показателей или специализированные обработки. Возникает распространенная задача: как одной форме, находящейся на начальной странице, получить доступ к текущим данным (например, к выделенной строке динамического списка) из другой формы, расположенной рядом на той же начальной странице? Давайте подробно разберем, как мы можем решить эту проблему.
Мы сталкиваемся с ситуацией, когда на начальной странице размещено несколько независимых форм — для организации таких интерфейсов есть панель виджетов и монитор показателей. Представьте, что у нас есть форма со списком "Контрагентов" и форма с "Журналом документов". При обработке события, например, при нажатии кнопки "Создать" в "Журнале документов", нам нужно открыть форму нового документа и автоматически заполнить поле "Контрагент" значением, которое было выделено в списке "Контрагентов" на соседней форме. Это требование продиктовано желанием оптимизировать ввод данных и улучшить пользовательский опыт.
Основная сложность заключается в том, что формы на начальной странице по умолчанию не знают друг о друге напрямую. Они существуют как отдельные элементы в рамках общего окна начальной страницы. Мы не можем просто обратиться к соседней форме по имени, как к реквизиту текущей формы. Именно поэтому нам необходимо найти способ программно "достучаться" до нужной формы и извлечь из нее интересующие данные, в частности, текущее значение динамического списка.
В нашем случае, как уточнили пользователи форума, нас интересует именно текущее значение динамического списка, то есть элемент справочника или документа, который в данный момент выделен пользователем в списке.
ПолучитьОкнаОдним из наиболее прямых и эффективных способов решения этой задачи является использование глобального клиентского метода ПолучитьОкна — для анализа структуры окон и форм пригодится инструментарий для анализа метаданных 1С. Этот метод позволяет нам получить коллекцию всех открытых окон клиентского приложения 1С. Среди этих окон мы можем найти искомое окно начальной страницы, а затем перебрать формы, размещенные на ней.
ПолучитьОкна(), который возвращает коллекцию объектов ОткрытоеОкно. Каждый такой объект представляет собой одно из открытых окон приложения (например, форму списка, форму элемента, обработку или начальную страницу).ОткрытоеОкно мы проверяем его свойство НачальнаяСтраница. Если это свойство истинно, значит, мы нашли то окно, которое нас интересует – рабочую область начальной страницы.ОткрытоеОкно, соответствующий начальной странице, содержит свойство Содержимое. Это свойство представляет собой коллекцию объектов ФормаКлиентскогоПриложения, которые являются непосредственно формами, размещенными на начальной странице. Мы перебираем эту коллекцию, чтобы найти нужную нам форму.Заголовок или другие уникальные признаки. Важно помнить, что заголовок формы может быть изменен пользователем, поэтому для более надежной идентификации можно использовать другие подходы, например, проверять тип формы или добавлять уникальный реквизит формы для идентификации.Элементы. Если на форме есть динамический список с именем, например, "Список", то мы можем получить его текущие данные через Элементы.Список.ТекущиеДанные. Свойство ТекущиеДанные вернет нам объект, соответствующий выделенной строке списка (например, ссылку на элемент справочника или документа), из которого мы уже можем извлечь интересующие нас реквизиты.Давайте посмотрим на пример кода, предложенный одним из участников обсуждения на форуме. Этот пример демонстрирует, как реализовать описанный выше подход:
текО = ПредопределенноеЗначение("Справочник.О.ПустаяСсылка");
Окна = ПолучитьОкна;
Для ио = 0 по Окна.Количество-1 Цикл
текОкно = Окна[ио];
Если текОкно.НачальнаяСтраница Тогда
масФорм = текОкно.Содержимое;
Для иф = 0 по масФорм.Количество-1 Цикл
Если масФорм[иф].Заголовок = "Уплата" Тогда
Попытка
текО = масФорм[иф].Элементы.Список.ТекущиеДанные.О;
Исключение
// Обработка ошибки, если данные недоступны или список пуст
КонецПопытки;
Прервать; // Выходим из цикла по формам, так как нужная найдена
КонецЕсли;
КонецЦикла;
Прервать; // Выходим из цикла по окнам, так как начальная страница найдена
КонецЕсли;
КонецЦикла;
В этом коде мы видим, как происходит пошаговый поиск. Сначала инициализируется переменная текО пустой ссылкой. Затем, в цикле по всем открытым окнам, мы ищем то, которое является начальной страницей (текОкно.НачальнаяСтраница). Внутри этого окна мы перебираем все размещенные на нем формы (масФорм = текОкно.Содержимое). Когда находится форма с заголовком "Уплата", мы пытаемся получить доступ к ее динамическому списку с именем "Список" и извлечь из него текущие данные (масФорм[иф].Элементы.Список.ТекущиеДанные.О). Здесь .О, вероятно, является названием конкретного реквизита, который мы хотим получить из текущей строки динамического списка. Конструкция Попытка...Исключение используется для безопасной обработки ситуации, если список пуст или элемент недоступен.
Важный момент: Весь этот код должен выполняться на клиенте, поскольку ПолучитьОкна является клиентским методом и работает с клиентским интерфейсом.
ПолучитьОкна возвращает только "Конфигурация"?Один из участников форума столкнулся с проблемой: ПолучитьОкна возвращает только одно окно с заголовком "Конфигурация", хотя в приложении открыто несколько форм, в том числе и на начальной странице. Эта ситуация может ввести в заблуждение и не позволить реализовать описанный выше подход. Давайте выясним причину и предложим рекомендации.
Возможные причины, по которым ПолучитьОкна может не "видеть" все ожидаемые окна:
ПолучитьОкна является клиентским. Если код, содержащий этот вызов, выполняется на сервере (например, в модуле объекта или в серверной процедуре формы), он не сможет получить доступ к клиентским окнам. Убедитесь, что ваш код находится в клиентской процедуре или функции (например, в процедуре, отмеченной как &НаКлиенте).ПолучитьОкна. Начальная страница может быть настроена таким образом, что некоторые формы загружаются только при их активации. Убедитесь, что нужные формы действительно отображаются на начальной странице и доступны пользователю.Важно: Для успешной работы с управляемыми формами и их элементами через ПолучитьОкна необходимо, чтобы формы были отрисованы и управлялись клиентским приложением. Для отладки и исследования элементов интерактивного интерфейса пригодится обработка для редактирования свойств открытых форм.
Рекомендации по отладке и проверке:
ПолучитьОкна, помечена атрибутом &НаКлиенте или является частью клиентского модуля формы.Окна = ПолучитьОкна; и посмотрите содержимое коллекции Окна в отладчике. Это поможет понять, какие окна система видит в данный момент — для этой задачи есть инструмент отладки алгоритмов в режиме Предприятие.</li>
<li><strong>Проверьте настройки начальной страницы:</strong> Возможно, формы не были добавлены в рабочую область начальной страницы или не имеют соответствующей видимости. Состав форм на начальной странице можно посмотреть и программно изменить с помощью объекта <code>НастройкиНачальнойСтраницы и его методов ПолучитьСоставФорм() и УстановитьСоставФорм(). Это может быть полезно для отладки, чтобы убедиться, что формы вообще предполагаются к отображению.Хотя прямой доступ через ПолучитьОкна является эффективным для получения текущих данных, существуют и другие подходы к взаимодействию между формами, которые могут быть полезны в различных сценариях. Рассмотрим их подробнее.
Оповестить и ОбработкаОповещения):
Этот механизм предоставляет более структурированный способ обмена информацией между формами — для этого также подойдёт механизм синхронизации данных между окнами 1С. Он позволяет одной форме отправить уведомление (оповещение) с некоторыми данными, а другой форме – обработать это уведомление.
Оповестить(), передавая ему имя события и структуру с данными. Например:
// В форме со списком контрагентов при изменении текущей строки
// или при клике по кнопке "Выбрать"
Если Элементы.СписокКонтрагентов.ТекущиеДанные <> Неопределено Тогда
СтруктураПараметров = Новый Структура("Контрагент", Элементы.СписокКонтрагентов.ТекущиеДанные.Ссылка);
Оповестить("ВыбранКонтрагент", СтруктураПараметров, ЭтаФорма);
КонецЕсли;
Здесь "ВыбранКонтрагент" - это имя события, СтруктураПараметров - данные, которые мы передаем, а ЭтаФорма - ссылка на форму-источник (необязательный параметр).
ОбработкаОповещения, которая будет реагировать на полученные уведомления:
// В форме журнала документов
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ВыбранКонтрагент" Тогда
Если Параметр.Свойство("Контрагент") Тогда
ВыбранныйКонтрагент = Параметр.Контрагент;
// Здесь мы можем использовать полученного контрагента,
// например, для заполнения поля в новой форме документа.
Сообщить("Получен контрагент: " + ВыбранныйКонтрагент);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Преимущества: Более гибкий и менее жестко связанный механизм взаимодействия, который подходит, когда форма-источник не знает, кто будет использовать ее данные, а просто оповещает о событии. Это позволяет избежать прямой зависимости между формами.
Хотя этот метод больше подходит для сценариев, когда одна форма открывает другую, его можно упомянуть как альтернативу для инициализации форм на начальной странице, если они открываются программно. Если вы открываете форму на начальной странице не через стандартные настройки, а программно, вы можете передать ей структуру с параметрами.
Например, если вы программно открываете форму журнала документов и хотите сразу установить фильтр по контрагенту, вы можете передать ему ссылку на контрагента:
ПараметрыОткрытия = Новый Структура("Контрагент", МойКонтрагент);
ОткрытьФорму("Документ.МойДокумент.ФормаСписка", ПараметрыОткрытия);
В открываемой форме эти параметры будут доступны через ЭтаФорма.Параметры.
Недостаток для нашей задачи: Этот метод не подходит для получения *текущих* данных из *уже открытой* соседней формы, а скорее для инициализации формы при ее создании.
Как упоминалось в сообщении 5, можно временно сохранять выбранные данные в регистре сведений (или любой другой временной таблице/объекте в памяти). Например, при активизации строки в списке "Контрагенты" записывать ссылку на текущего контрагента в регистр сведений, а затем из формы журнала документов считывать это значение.
Плюсы: Простота реализации для небольших объемов данных, независимость форм друг от друга (они общаются через общую "таблицу").
Минусы: Это менее оптимальный и не самый "красивый" подход, так как требует работы с базой данных (даже если это регистр сведений) для передачи оперативных клиентских данных. Есть риск коллизий при одновременной работе нескольких пользователей или окон. Он не рекомендуется для частых или объемных обменов данными на клиенте.
Еще одна идея, высказанная на форуме (сообщение 5), заключается в том, чтобы убрать все отдельные формы с начальной страницы и создать одну "внешнюю" общую форму, которая бы содержала в себе весь необходимый функционал, включая оба динамических списка (например, контрагентов и документов). Эту единую форму и разместить на начальной странице.
Плюсы: Внутри одной формы доступ к элементам осуществляется напрямую через Элементы.ИмяЭлемента, что значительно упрощает взаимодействие. Нет необходимости в сложных механизмах поиска окон и форм.
Минусы: Требует значительной переработки пользовательского интерфейса и, возможно, логики, если формы уже существуют как отдельные. Может усложнить поддержку, если форма станет слишком большой и многофункциональной. Однако, для новых разработок или небольших подсистем это может быть вполне жизнеспособным решением.
Поскольку наша основная задача — получение текущих данных из динамического списка, давайте углубимся в особенности работы с ними:
ТекущиеДанные:
Это ключевое свойство элемента управления "Динамический список". Оно возвращает объект, который представляет текущую выделенную строку списка. Если список построен на основе справочника или документа, ТекущиеДанные вернет объект типа СправочникОбъект или ДокументОбъект, либо просто Ссылка на них. Из этого объекта мы можем получить доступ к его реквизитам, как это было показано в примере с .О (предполагая, что "О" — это имя реквизита).
Например, если список построен на справочнике "Контрагенты" и мы хотим получить ИНН текущего контрагента:
ТекущийКонтрагентСсылка = масФорм[иф].Элементы.Список.ТекущиеДанные.Ссылка;
Если ТекущийКонтрагентСсылка.Пустая() Тогда
// Список пуст или строка не выбрана
Иначе
ТекущийКонтрагентОбъект = ТекущийКонтрагентСсылка.ПолучитьОбъект(); // Если нужны реквизиты, которых нет в списке
ИННКонтрагента = ТекущийКонтрагентОбъект.ИНН;
// Или если ИНН есть в списке (через поля динамического списка):
// ИННКонтрагента = масФорм[иф].Элементы.Список.ТекущиеДанные.ИНН;
КонецЕсли;
Используйте ТекущиеДанные.Ссылка, если вам нужна именно ссылка, и ТекущиеДанные.ИмяРеквизита, если реквизит отображается в списке.
ПроизвольныйЗапрос и Параметры:
Динамические списки могут быть построены на произвольных запросах. Если нам нужно влиять на данные в таком списке извне, мы можем программно изменять текст запроса или, что чаще, устанавливать его параметры. Например, если список документов должен отображать документы только для выбранного контрагента.
В принимающей форме можно было бы изменить параметр динамического списка:
// Предположим, что в форме журнала документов есть динамический список с именем "СписокДокументов"
// и у него есть параметр "КонтрагентДляОтбора"
Если Параметр.Свойство("Контрагент") Тогда
Элементы.СписокДокументов.Параметры.УстановитьЗначениеПараметра("КонтрагентДляОтбора", Параметр.Контрагент);
Элементы.СписокДокументов.Обновить(); // Обязательно обновить список, чтобы применился отбор
КонецЕсли;
После изменения параметров динамического списка или его запроса, необходимо вызвать метод Обновить() для элемента управления "Динамический список". Это заставит список повторно выполнить запрос к данным и отобразить актуальную информацию. Без этого вызова изменения не будут видны пользователю.
При активном взаимодействии между формами и динамическими списками, особенно при частых обновлениях, важно учитывать производительность. Избегайте избыточного обращения к серверу. Индексируйте поля в базе данных, которые используются для отбора и сортировки в динамических списках. Старайтесь выполнять только необходимые обновления.
Мы выяснили, что для получения текущих данных из одной формы, размещенной на начальной странице 1С, в другой форме, наиболее прямолинейным и эффективным способом является использование глобального клиентского метода ПолучитьОкна(). Этот метод позволяет нам программно перебрать открытые окна, найти начальную страницу, а затем получить доступ к элементам нужной формы, включая текущие данные динамических списков.
Мы также проанализировали потенциальные проблемы, такие как невидимость окон, и предложили рекомендации по их устранению, подчеркивая важность клиентского контекста выполнения. В качестве альтернативных подходов рассмотрели механизм оповещений, передачу параметров при открытии форм, временное хранение данных и объединение функционала в одной форме. Выбор конкретного подхода зависит от архитектуры решения, требований к связности форм и удобства поддержки.
Помните, что детальное понимание работы с управляемыми формами, динамическими списками и клиент-серверным взаимодействием в 1С:Предприятии 8.3 является ключом к созданию эффективных и удобных пользовательских интерфейсов.