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

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

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

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

Проблема и анализ стандартного решения через перебор открытых окон

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


Окна = ПолучитьОкна();
Для ио = 0 по Окна.Количество()-1 Цикл 
   текОкно = Окна[ио];
   Если текОкно.НачальнаяСтраница Тогда 
      масФорм = текОкно.Содержимое;
      Для иф = 0 по масФорм.Количество()-1 Цикл 
         Если масФорм[иф].Заголовок = "Уплата" Тогда
            Попытка
               т = масФорм[иф].Элементы.Список.ТекущиеДанные.Ч;
            Исключение
            КонецПопытки;
            Прервать;
         КонецЕсли; 
      КонецЦикла
   КонецЕсли;    
КонецЦикла;

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

  1. Поиск по заголовку формы (Заголовок = "Уплата"). Это один из самых ненадежных способов идентификации объектов в программировании. Заголовок формы может динамически изменяться в коде (например, при выводе количества документов или текущего периода), может зависеть от языковых настроек пользователя (локализации) или измениться после очередного обновления конфигурации. Поиск по заголовку гарантированно сломается при малейшем изменении интерфейса.
  2. Использование пустого блока Попытка...Исключение. Подавление системных ошибок без их обработки и логирования считается плохой практикой. Если элемент Список будет удален, переименован или свойство ТекущиеДанные окажется неопределенным (например, когда таблица пуста), программа просто «промолчит», оставив переменную пустой. Это затрудняет отладку и маскирует реальные ошибки в логике.
  3. Жесткая связанность (tight coupling) форм. При таком подходе форма-получатель должна детально знать внутреннюю структуру формы-источника: как называется элемент интерфейса (Список), какое имя носит колонка (Ч) и т.д. Если разработчик решит изменить структуру формы-источника, ему придется переписывать код во всех связанных формах.

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

Способ 1. Исправленный и безопасный перебор окон на клиенте

Если архитектура вашего решения требует получить данные «здесь и сейчас» без предварительной подготовки связей между формами, можно использовать метод ПолучитьОкна(), но его реализация должна быть максимально безопасной. Давайте перепишем исходный алгоритм в соответствии со стандартами разработки «1С».

Для этого мы заменим поиск по заголовку на поиск по системному имени формы ИмяФормы, добавим явные проверки существования элементов и корректно обработаем пустые значения.

Рассмотрим безопасную функцию получения данных:


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

&НаКлиенте
Функция СвойствоОбъекта(Объект, ИмяСвойства)
    Попытка
        Данные = Объект[ИмяСвойства];
        Возврат Истина;
    Исключение
        Возврат Ложь;
    КонецПопытки;
КонецФункции

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

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

Способ 2. Механизм оповещений (Рекомендуемый стандарт 1С)

Наиболее надежным, производительным и архитектурно правильным решением является использование встроенного механизма асинхронных оповещений. Этот метод реализует паттерн проектирования «Издатель-Подписчик» (Observer). Формы становятся полностью независимыми друг от друга (слабая связанность).

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

Разберем реализацию этого механизма по шагам:

Шаг 1. Реализация отправки события в форме-источнике

В форме, где расположена табличная часть (например, список документов «Уплата»), необходимо создать обработчик события таблицы ПриАктивизацииСтроки. При каждом переходе пользователя на новую строку форма будет отправлять оповещение.


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

Шаг 2. Прием и обработка события в форме-приемнике

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


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

Преимущества метода: Полная независимость форм. Если в будущем изменится имя таблицы на форме-источнике или заголовок окна, код формы-приемника останется полностью работоспособным. Оповещения работают мгновенно и не требуют ресурсоемкого перебора окон.

Способ 3. Использование глобального модуля (клиентского кэша)

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

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

Выполним следующие шаги для настройки клиентского кэша:

Шаг 1. Создание общего модуля

  1. В дереве метаданных конфигурации перейдите в раздел Общие -> Общие модули и создайте новый модуль с именем РабочийСтолКлиент.
  2. В свойствах нового общего модуля обязательно установите флаг «Клиент (управляемое приложение)» и снимите все остальные флаги (Сервер, Внешнее соединение и т.д.).

Шаг 2. Объявление экспортной переменной в общем модуле

Откройте модуль и добавьте объявление глобальной переменной, которая будет хранить актуальное состояние выбранных данных:

Перем ТекущийВыборУплаты Экспорт;

Шаг 3. Запись данных из формы-источника

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


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // Сохраняем значение в глобальную переменную общего модуля
        РабочийСтолКлиент.ТекущийВыборУплаты = ТекущиеДанные.Ч;
    Иначе
        РабочийСтолКлиент.ТекущийВыборУплаты = Неопределено;
    КонецЕсли;
    
КонецПроцедуры

Шаг 4. Чтение данных в форме-приемнике

Теперь в форме-приемнике в любой момент времени (например, при нажатии кнопки или при проведении расчета) мы можем напрямую и мгновенно прочитать это значение без перебора окон:


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

Преимущества метода: Исключительная простота реализации, минимальная нагрузка на клиентскую память и процессор. Данные запрашиваются строго «по требованию» получателя.

Сводный анализ и рекомендации по выбору решения

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

  1. Метод оповещений (Способ 2) — идеален для сценариев, когда формы должны реагировать на действия пользователя в реальном времени (например, при клике на строку в левом списке мгновенно фильтруется правый список). Это золотой стандарт разработки на управляемых формах 1С.
  2. Метод клиентского кэша через общий модуль (Способ 3) — незаменим, когда форма-приемник должна использовать данные формы-источника эпизодически (по нажатию кнопки, при сохранении документа, при проверке заполнения) и мгновенный интерактивный отклик интерфейса не требуется.
  3. Перебор окон (Способ 1) — допускается к использованию только в крайних случаях, когда у вас нет технической возможности вносить изменения в форму-источник (например, если она находится в закрытом или типовом модуле, который нельзя редактировать). Во всех остальных ситуациях его использования следует избегать из-за низкой производительности и рисков нарушения стабильности интерфейса при обновлениях.
← На главную