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

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

При работе с платформой 1С:Предприятие 8.3, особенно в режиме обычных форм, часто возникает необходимость обмениваться данными между различными формами. Одной из таких задач является передача или получение значения реквизита формы документа в форму списка документов. Эта задача имеет свои особенности, поскольку мы должны четко различать реквизит самого документа, который хранится в базе данных, и реквизит формы документа, который существует только в контексте открытой формы и не сохраняется автоматически.

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

Понимание различий: Реквизит документа против Реквизита формы

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

  1. Реквизит документа:

    Это данные, которые являются частью структуры самого объекта базы данных – документа. Они хранятся непосредственно в таблицах базы данных и сохраняются при записи документа. Доступ к таким реквизитам осуществляется через ссылку на документ или его объект.

    Пример: Если у документа "РеализацияТоваровУслуг" есть реквизит "СуммаДокумента", то это реквизит документа. Мы можем получить его значение, имея ссылку на документ:

    
    СсылкаНаДокумент = ДанныеСтроки.Ссылка; // Например, из формы списка
    ОбъектДокумента = СсылкаНаДокумент.ПолучитьОбъект();
    Сумма = ОбъектДокумента.СуммаДокумента;
    

    Эти реквизиты доступны всегда, когда у нас есть объект или ссылка на документ, независимо от того, открыта ли его форма.

  2. Реквизит формы документа:

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

    Пример: Если на форме документа "РеализацияТоваровУслуг" мы добавили реквизит формы "ОтображатьПодробности" с типом Булево, то его значение существует только пока форма открыта. Доступ к нему осуществляется через ЭтаФорма.ОтображатьПодробности или просто ОтображатьПодробности внутри модуля формы.

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

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

Сценарий 1: Отображение реквизита самого документа в форме списка (для справки)

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

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

  1. Добавление реквизита в документ:

    Прежде всего, убедитесь, что реквизит добавлен в структуру самого документа (в конфигураторе, на вкладке "Реквизиты" объекта "Документ").

  2. Добавление поля в форму списка:

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

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

  3. Обработка события ПриВыводеСтроки:

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

    Рассмотрим код, предложенный на форуме, и объясним его:

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

    В этом коде:

    • ДанныеСтроки.Ссылка предоставляет ссылку на текущий документ в списке.
    • .ПолучитьОбъект() загружает сам объект документа из базы данных, что позволяет нам получить доступ к его реквизитам, таким как ОригиналДаНет.
    • ОформлениеСтроки.Ячейки.СтатусДокумента обращается к объекту оформления конкретной ячейки в нашей колонке "СтатусДокумента".
    • Мы устанавливаем свойства Текст, ОтображатьТекст и ЦветФона в зависимости от значения реквизита.

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

    Сценарий 2: Передача реквизита формы документа в форму списка (основная задача автора)

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

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

    Подход 2.1: Передача параметров при открытии формы списка из формы документа

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

    1. В форме документа (источник данных):

      Предположим, у нас есть реквизит формы на документе под названием МойРеквизитФормы. Когда мы открываем форму списка (например, по кнопке "Открыть список", "Показать связанные" и т.д.), мы можем сформировать структуру с этим реквизитом и передать ее в качестве параметра метода ОткрытьФорму().

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

      Пояснения:

      • Новый Структура("ИмяРеквизитаИзДокумента", ЭтаФорма.МойРеквизитФормы): Мы создаем структуру, где ключ ИмяРеквизитаИзДокумента будет именем параметра, а значением — значение нашего реквизита формы документа.
      • ОткрытьФорму(...): Вызывает метод открытия формы. Важно правильно указать имя формы списка.
      • Третий параметр ЭтаФорма: Указывает, что текущая форма документа является владельцем открываемой формы списка. Это может быть полезно для дальнейшего взаимодействия или для закрытия дочерних форм при закрытии владельца.
    2. В форме списка (получатель данных):

      Когда форма списка открывается с переданными параметрами, мы можем получить их в событии ПередОткрытием или ПриОткрытии (для обычных форм). Переданные параметры будут доступны через свойство формы Параметры.

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

      Пояснения:

      • ЭтотОбъект.Параметры.Свойство("ИмяРеквизитаИзДокумента"): Проверяем наличие нашего параметра в переданной структуре.
      • ЗначениеПереданногоРеквизита = ЭтотОбъект.Параметры.ИмяРеквизитаИзДокумента: Присваиваем значение локальной переменной.
      • Мы можем сохранить это значение в новый реквизит формы списка (ЭтаФорма.ПолученныйРеквизитДокумента), чтобы оно было доступно в других процедурах формы списка.

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

    Подход 2.2: Получение реквизита из уже открытой формы документа в форме списка

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

    Метод 2.2.1: Поиск формы по типу в коллекции ВсеФормы()

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

    1. В форме списка (инициатор получения данных):

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

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

      Пояснения и важные моменты:

      • ВсеФормы: Глобальная коллекция всех открытых форм в текущем сеансе.
      • ТипЗнч(ФормаИзКоллекции) = Тип("ФормаДокумента.ИмяДокумента"): Мы сравниваем тип каждой формы в коллекции с ожидаемым типом формы документа. Имя типа должно быть полным (например, ФормаДокумента.РеализацияТоваровУслуг).
      • Доступ к реквизитам формы: В обычных формах реквизиты формы, как правило, доступны напрямую через объект формы, если они не являются приватными. Если же для обычных форм реквизиты формы объявлены как `НеВыгружаемый` или `Приватный` (что редкость), или если бы это были управляемые формы, то для доступа к реквизиту понадобился бы экспортный метод в модуле формы документа, который возвращает это значение.
      • Ограничения: Этот метод может быть ненадежным, если у пользователя открыто несколько форм документа одного типа. Тогда Прервать найдет только первую попавшуюся форму, что не всегда то, что нужно. Для более точного выбора потребовалась бы дополнительная логика (например, сравнение ссылок, идентификаторов или поиск по владельцу).
    Метод 2.2.2: Использование механизма оповещений

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

    1. В форме документа (источник данных):

      Когда значение реквизита формы изменяется или наступает событие, которое требует уведомления, форма документа вызывает метод Оповестить(). Этот метод отправляет оповещение всем открытым формам, которые могут его обработать.

      
      // В модуле формы документа
      // Например, в обработчике ПриИзменении реквизита формы
      Процедура МойРеквизитФормыПриИзменении(Элемент)
          // Здесь ЭтаФорма.МойРеквизитФормы содержит новое значение
          // Отправляем оповещение
          // ИмяСобытия: строка, которая идентифицирует событие
          // Параметр: данные, которые мы хотим передать (например, значение реквизита)
          // Источник: ссылка на саму форму, которая отправила оповещение (может быть полезно)
          Оповестить("РеквизитФормыДокументаОбновлен", ЭтаФорма.МойРеквизитФормы, ЭтаФорма);
      КонецПроцедуры
      
      // Или при закрытии формы документа, чтобы сообщить о последнем значении
      Процедура ПриЗакрытии()
          Оповестить("ФормаДокументаЗакрывается", ЭтаФорма.МойРеквизитФормы, ЭтаФорма);
      КонецПроцедуры
      

      Пояснения:

      • Оповестить(ИмяСобытия, Параметр, Источник): Метод для отправки оповещения.
      • "РеквизитФормыДокументаОбновлен": Это произвольное строковое имя события, по которому формы-получатели будут идентифицировать, что произошло.
      • ЭтаФорма.МойРеквизитФормы: Значение реквизита формы, которое мы хотим передать.
      • ЭтаФорма: Ссылка на текущую форму документа, что позволяет получателю, если нужно, обратиться обратно к источнику.
    2. В форме списка (получатель данных):

      Форма списка должна реализовать процедуру ОбработкаОповещения(), которая будет автоматически вызываться при получении оповещения.

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

      Пояснения:

      • ОбработкаОповещения(ИмяСобытия, Параметр, Источник): Это стандартная процедура, которая должна быть реализована в модуле формы, чтобы она могла принимать оповещения.
      • Мы используем условный оператор Если ИмяСобытия = ... Тогда для фильтрации оповещений по их именам.
      • Параметр и Источник содержат данные, переданные вызывающей формой.

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

    Метод 2.2.3: Временное хранение в общем модуле (менее предпочтительно)

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

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

      Создайте новый общий модуль (например, ПередачаДанныхМеждуФормами) и установите его свойства так, чтобы он был доступен на клиенте (для обычных форм, это обычно означает, что флажок "Клиент (обычное приложение)" должен быть установлен).

      
      // В модуле "ПередачаДанныхМеждуФормами"
      Перем ЗначениеРеквизитаФормыДокумента Экспорт; // Объявляем экспортную переменную
      
    2. В форме документа (источник данных):

      При необходимости передать значение, запишите его в эту переменную:

      
      // В модуле формы документа
      Процедура ПередатьРеквизитЧерезОбщийМодуль()
          ПередачаДанныхМеждуФормами.ЗначениеРеквизитаФормыДокумента = ЭтаФорма.МойРеквизитФормы;
          Сообщить("Значение реквизита формы документа записано в общий модуль.");
      КонецПроцедуры
      
    3. В форме списка (получатель данных):

      Считайте значение из общего модуля:

      
      // В модуле формы списка
      Процедура ПолучитьРеквизитИзОбщегоМодуля()
          ЗначениеРеквизита = ПередачаДанныхМеждуФормами.ЗначениеРеквизитаФормыДокумента;
          Сообщить("Форма списка получила значение из общего модуля: " + ЗначениеРеквизита);
          // Важно: очистить переменную после использования, чтобы избежать влияния на другие сценарии
          ПередачаДанныхМеждуФормами.ЗначениеРеквизитаФормыДокумента = Неопределено;
      КонецПроцедуры
      

      Пояснения и предостережения:

      • Этот метод менее предпочтителен, так как создает глобальное состояние, которое может быть непредсказуемым. Если несколько форм одновременно используют один и тот же общий модуль для передачи разных данных, могут возникнуть конфликты или некорректная работа.
      • Крайне важно очищать переменную после использования (например, устанавливать ее в Неопределено или ПустаяСтрока), чтобы избежать "загрязнения" данных и предотвратить получение устаревших значений другими формами.

    Подход 2.3: Использование реквизита формы списка для хранения полученного значения

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

    1. Создайте реквизит формы списка:

      В конфигураторе, в модуле формы списка, на вкладке "Реквизиты" создайте новый реквизит. Дайте ему осмысленное имя (например, ПолученныйРеквизитДокумента) и выберите подходящий тип (например, Строка, Булево, Число – такой же, как у реквизита формы документа).

    2. Присвойте значение:

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

      
      // Пример после получения значения
      ЭтаФорма.ПолученныйРеквизитДокумента = ЗначениеРеквизитаИзФормыДокумента;
      

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

    Дополнительные рекомендации и практические советы

    1. Четко определяйте сценарий: Прежде чем выбирать метод, ответьте на вопросы:
      • Какая форма инициирует взаимодействие?
      • Форма-источник и форма-получатель открываются одновременно или независимо?
      • Нужно ли одноразово передать данные при открытии или поддерживать их актуальность в течение всего времени работы?

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

    2. Используйте экспортные методы, если необходимо: Для более контролируемого доступа к реквизитам формы документа (особенно если бы это были управляемые формы или вы хотели бы защитить реквизиты от прямого доступа), можно создать экспортную функцию в модуле формы документа, которая будет возвращать значение нужного реквизита.
      
      // В модуле формы документа
      Функция ПолучитьМойРеквизитФормы() Экспорт
          Возврат ЭтаФорма.МойРеквизитФормы;
      КонецФункции
      

      Тогда из другой формы вы бы вызывали: ФормаДокумента.ПолучитьМойРеквизитФормы().

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

    Таким образом, мы видим, что передача реквизита формы документа в форму списка в обычных формах 1С 8.3 — это не тривиальная задача, но она вполне решаема с помощью правильного выбора механизмов платформы. Главное – четко понимать, с каким типом реквизита вы работаете и какой сценарий взаимодействия между формами вы хотите реализовать.

← На главную