Как вывести информацию из модуля объекта на форму в 1С:Предприятие 8.3 (Управляемые формы)?

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

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

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

Понимание контекста выполнения: клиент и сервер

Ключ к решению проблемы лежит в понимании архитектуры 1С:Предприятия 8.3, которая основана на клиент-серверном взаимодействии. Рассмотрим основные моменты:

  1. Модуль формы: Код, написанный в модуле формы, выполняется на стороне клиента (то есть на компьютере пользователя). Он отвечает за отображение интерфейса, обработку пользовательских действий, клиентские проверки и т.д. Реквизиты формы — это данные, которые хранятся непосредственно в форме и доступны только на клиенте.

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

  3. Разделение контекстов: Клиент и сервер — это две разные "среды выполнения". Они не имеют прямого доступа к переменным и данным друг друга. Для обмена информацией между ними используются специальные механизмы, такие как вызов серверных функций с клиента и возврат значений.

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

Способы вывода информации из модуля объекта на форму

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

1. Использование экспортных функций модуля объекта для реквизитов формы

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

  1. Создание экспортной функции в модуле объекта:

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

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

    Обратите внимание, что эта функция будет выполняться на сервере.

  2. Вызов экспортной функции из модуля формы и присвоение реквизиту формы:

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

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

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

    Важные моменты:

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

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

    • Убедитесь, что тип реквизита формы Реквизит1 соответствует типу возвращаемого значения (или может быть неявно преобразован, например, число в строку).

2. Изменение реквизита объекта и последующее обновление формы

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

  1. Изменение реквизита объекта в серверной процедуре:

    В модуле объекта создаем экспортную процедуру, которая принимает в качестве параметра ссылку на текущий объект (или работает с ЭтотОбъект, если процедура вызывается для конкретного экземпляра объекта). В этой процедуре выполняем расчет, присваиваем результат реквизиту объекта и вызываем метод Записать() для сохранения изменений в базе данных.

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

    В некоторых случаях, если вы вызываете эту процедуру из другого серверного контекста, вам может потребоваться получить объект по ссылке: Объект = ОбъектСсылка.ПолучитьОбъект();, а затем работать с Объект.РеквизитОбъекта1 и Объект.Записать();.

  2. Вызов серверной процедуры из модуля формы и обновление формы:

    Из модуля формы вызываем созданную серверную процедуру. После того как серверная процедура отработает и сохранит изменения в базе данных, нам нужно обновить данные формы, чтобы она "подтянула" свежие значения реквизитов из базы. Для этого используются методы Прочитать() или ОбновитьДанные().

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

    Важные моменты:

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

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

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

Принятие решения о том, где разместить код — в модуле формы или в модуле объекта — является важным аспектом эффективной разработки в 1С. Рассмотрим основные критерии выбора:

  1. Модуль формы:

    • Используется для реализации логики, связанной исключительно с пользовательским интерфейсом.

    • Обработка событий элементов формы (кнопки, поля ввода).

    • Управление видимостью, доступностью, цветом элементов формы.

    • Выполнение клиентских проверок, которые не требуют обращения к базе данных.

    • Простые вычисления, не требующие серверных данных.

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

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

  2. Модуль объекта:

    • Предназначен для реализации основной бизнес-логики, которая оперирует данными объекта информационной базы.

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

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

    • Операции, связанные с записью, проведением или отменой проведения объектов.

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

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

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

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

  1. Именование: Присваивайте своим реквизитам формы и методам осмысленные имена. Например, вместо Реквизит1 используйте РезультатРасчетаСкидки или СуммаИтогоСНДС. Это значительно улучшает читаемость и поддерживаемость кода.

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

  3. Производительность: Старайтесь минимизировать количество серверных вызовов с клиента, особенно в циклах или при частых пользовательских действиях. Каждый такой вызов — это сетевой обмен и переключение контекста, что может замедлить работу приложения.

  4. Контекст объекта: Если вы работаете с реквизитами основного объекта формы (который обычно называется Объект), всегда имейте в виду, что ЭтотОбъект в модуле формы — это объект самой формы, а Объект — это основной реквизит формы, представляющий объект базы данных.

Таким образом, для вывода информации из модуля объекта на форму в 1С:Предприятии 8.3 (управляемые формы) мы используем механизмы клиент-серверного взаимодействия. Если значение временное и нужно только для формы, мы применяем экспортные функции модуля объекта, возвращающие результат на клиент. Если значение должно быть сохранено в базе данных как реквизит объекта, мы изменяем его в модуле объекта и сохраняем, а затем обновляем форму с помощью методов Прочитать() или ОбновитьДанные(). Понимание контекста выполнения и правильный выбор места для кода значительно упрощают разработку и делают систему более надежной и производительной.

← На главную