Как программно изменить значения элементов на управляемой форме 1С?

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

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

Понимание работы управляемых форм и элементов

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

  1. Привязка элементов к данным (ПутьКДанным):

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

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

    Для корректного изменения значения элемента на форме, нам всегда нужно изменять значение того реквизита, к которому этот элемент привязан.

  2. Доступ к данным на клиенте и сервере:

    Платформа 1С использует клиент-серверную архитектуру. Код может выполняться либо на клиенте (в браузере или тонком клиенте), либо на сервере 1С:Предприятия. Это накладывает свои ограничения и требует особого подхода при работе с данными:

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

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

  3. Обновление отображения:

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

Анализируем исходную проблему: Почему значения не отображаются?

Рассмотрим код, с которым столкнулся разработчик:


&НаСервере
Процедура НомерГосРегПриИзмененииНаСервере(Код,М,В)
    Ссылка=Справочники.Автомашины.НайтиПоКоду(Код);
    М=Ссылка.Наименование;
    В=Ссылка.Водитель
КонецПроцедуры

&НаКлиенте
Процедура НомерГосРегПриИзменении(Элемент)
    Перем М,В;
    НомерГосРегПриИзмененииНаСервере(Объект.НомерГосРег,М,В);
    Марка=М;
    Водитель=В;
    АдресОтпр="с.Кукуево";
    Сообщить(М);
    Сообщить(В);
КонецПроцедуры

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

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

Таким образом, строки:


Марка=М;
Водитель=В;
АдресОтпр="с.Кукуево";

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

Исправляем проблему с отображением: Присваиваем значения корректно

Для того чтобы значения корректно отобразились на форме, нам необходимо изменить код процедуры НомерГосРегПриИзменении на клиенте. Мы должны использовать префикс Объект. при присвоении значений реквизитам документа:


&НаКлиенте
Процедура НомерГосРегПриИзменении(Элемент)
    Перем М,В;
    // Вызов серверной процедуры для получения данных
    НомерГосРегПриИзмененииНаСервере(Объект.НомерГосРег,М,В);

    // Корректное присвоение значений реквизитам объекта формы
    // Используем "Объект." для доступа к реквизитам документа
    Объект.Марка = М;
    Объект.Водитель = В;
    Объект.АдресОтпр = "с.Кукуево"; // Теперь это значение будет установлено

    // Для отладки
    Сообщить(М);
    Сообщить(В);

    // Дополнительный шаг: Обновление отображения данных на форме
    // Иногда платформа не сразу обновляет UI после присвоения значений.
    // Этот метод принудительно обновляет элементы формы.
    ЭтаФорма.ОбновитьОтображениеДанных(); 
КонецПроцедуры

Как видим, автор в сообщении 12 подтвердил, что с Объект.Водитель и Объект.АдресОтпр получилось нормально. Это подтверждает правильность использования префикса Объект..

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

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

В большинстве случаев, добавление ЭтаФорма.ОбновитьОтображениеДанных(); после всех присвоений на клиенте будет достаточным для решения проблем с отображением.

Разбираемся с проблемой "Марка по-прежнему не работает"

После исправления кода для Водитель и АдресОтпр, автор всё ещё сталкивался с проблемой: "А вот Объект.Марка по-прежнему не работает." Это указывает на другую, более глубокую причину, которая чаще всего связана с несоответствием типов данных.

Давайте проанализируем ситуацию:

Если Объект.Марка в документе "Путевой лист" имеет **ссылочный тип** (например, СправочникСсылка.МаркиАвтомобилей или СправочникСсылка.Автомашины), то мы не можем напрямую присвоить ему строковое значение. 1С не сможет автоматически преобразовать строку (наименование марки) в ссылку на элемент справочника.

Решение 1: Если реквизит "Марка" в документе должен быть строкой.

  1. Проверьте тип реквизита в конфигураторе: Откройте конфигуратор, найдите документ "Путевой лист" и убедитесь, что его реквизит "Марка" имеет тип "Строка".
  2. Убедитесь в правильности ПутиКДанным: Проверьте свойство ПутьКДанным у элемента формы "Марка". Оно должно быть Объект.Марка.
  3. Если тип "Строка" и ПутьКДанным корректен: Тогда строка Объект.Марка = М; должна работать. Если не работает, возможно, есть проблема с видимостью, доступностью элемента, или это составной элемент, требующий особого подхода. Но в подавляющем большинстве случаев это решит проблему.

Решение 2: Если реквизит "Марка" в документе является ссылочным типом.

Это наиболее вероятная причина проблемы. Если реквизит Марка в документе "Путевой лист" предназначен для хранения ссылки на элемент другого справочника (например, справочника "МаркиАвтомобилей"), то нам нужно выполнить дополнительные действия:

  1. На сервере: Получить не наименование, а ссылку на марку.

    Нам потребуется найти соответствующий элемент справочника "МаркиАвтомобилей" по его наименованию (которое мы получили из Ссылка.Наименование) или получить ссылку на марку из справочника "Автомашины", если в нём есть соответствующий реквизит.

    Предположим, что Ссылка.Наименование из справочника "Автомашины" является строковым наименованием марки, а в документе "Путевой лист" реквизит Марка имеет тип СправочникСсылка.МаркиАвтомобилей. Тогда серверная процедура должна выглядеть так:

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

    Мы передали в серверную процедуру дополнительный параметр Марка_Ссылка, который будет заполнен ссылкой на марку автомобиля.

  2. На клиенте: Присвоить полученную ссылку.

    Теперь на клиенте мы должны принять эту ссылку и присвоить её реквизиту Объект.Марка:

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

Общие рекомендации и полезные методы

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

  1. Всегда проверяйте ПутьКДанным элементов формы. Это первое, что нужно сделать, если значение не отображается. Убедитесь, что элемент привязан именно к тому реквизиту, который вы пытаетесь изменить.
  2. Используйте Объект. для реквизитов основного объекта, к которому привязана форма. Это касается реквизитов документов, справочников и других объектов базы данных, которые являются основой вашей формы.
  3. Учитывайте клиент-серверное взаимодействие и передачу параметров. Данные, полученные на сервере, должны быть явно переданы на клиент для использования в клиентском коде и присвоения реквизитам формы. Используйте параметры процедур для передачи значений между клиентскими и серверными вызовами.
  4. Обращайте внимание на соответствие типов данных при присвоении значений. Это одна из самых частых ошибок. Нельзя присвоить строку ссылочному типу без предварительного поиска или создания элемента справочника. Всегда проверяйте типы реквизитов в конфигураторе.
  5. При необходимости используйте ЭтаФорма.ОбновитьОтображениеДанных() или ЭтаФорма.Прочитать(). Эти методы помогут принудительно обновить визуальное представление формы, если изменения не отображаются автоматически. ОбновитьОтображениеДанных() обычно достаточно.
  6. Активно используйте Сообщить() и точки останова для отладки. Если что-то не работает, используйте Сообщить(), чтобы вывести текущие значения переменных на каждом этапе (после серверного вызова, перед присвоением, после присвоения). Также ставьте точки останова в конфигураторе, чтобы пошагово отследить выполнение кода и значения переменных. Это поможет быстро выявить, на каком этапе происходит сбой.

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

← На главную