1с управляемые формы динамическое создание формы
Эта публикация посвящена нюансам программного управления клиентским интерфейсом на управляемых формах.
Первое и главное: Управляемые формы существуют в Управляемом приложении, реализованном в клиент-серверной архитектуре, при которой все данные и программный код разделяются между средой клиента и средой сервера даже в тех случаях, когда это происходит на одном физическом компьютере. Кроме того, выполнение запросов к базе данных выполняется в особой среде на сервере, поэтому в целом существует три среды, каждая из которых имеет собственные существенные отличия:
- На Клиенте
- На Сервере
- В Запросе
Поскольку управляемые формы создавались для работы не только в оболочке 1С:Предприятие, но и в браузере, окно которого нельзя монопольно захватывать, то диалоговые окна и старый стиль разработки интерфейса, рассчитанный на использование диалогов, в управляемыми формами не приветствуется. Так, использование процедуры Сообщить() будет работать только в оболочке 1С:Предприятие, при этом напоминая о некорректности. В управляемых формах вместо процедуры Сообщить() следует использовать новую простую конструкцию:
НСтр ( "ua = 'Привіт, світ!'; ru = 'Привет, мир!'; en = 'Hello, world!'" ) ;Проверка значений реквизитов формы
Проверка отсутствия значения в реквизите в модуле формы
Если ПустаяСтрока ( Объект . < РеквизитСтрока > ) Тогда // пустая строка Если Объект . < РеквизитДата > = Дата ( '00010101' ) Тогда // пустое значение даты Если Объект . < Реквизит > = Неопределено Тогда // отсутствие значение и отсутствие типа Если Объект . < РеквизитСсылка > . Пустая ( ) Тогда // пустая ссылка установленного типаПеречисления
Перечисления полноценно доступны только &НаСервере в коллекции объектов метаданных Перечисления, которое недоступно &НаКлиенте и в запросе непосредственно, а только через
Если Вид = ПредопределенноеЗначение ( "Перечисление.Виды.Основной" ) ТогдаИзменения внесенные в данные формы программно не контролируются формой, поэтому для управления сохранением внесенных изменений необходимо устанавливать свойство Модифицированность формы
В конфигураторе набор отображаемых свойств формы существенно зависит от реквизита с установленным свойством Основной реквизит.
Ограничения при передаче данных в управляемую форму
Подготовка данных необходимых форме при открытии как правило выполняется стандартным средствами сервера и проблем не вызывает. Но во время работы с формой, ей может понадобиться получить дополнительные данные с сервера, что реализуется серверным вызовом функции, которая подготовит данные на Сервере и вернет их на Клиент. Однако часто прикладной объект полученный на Сервере не удается вернуть на Клиент, т.к. это вызывает ошибку XDTO при попытке преобразовать данные неприменимые на Клиенте (например каскадная связь объектов справочника через реквизит .Родитель). Для обхода ошибки не следует возвращать на Клиент прикладные объект, следует создать и возвращать специально подготовленную структуру, в которой источник ошибки преобразования XDTO будет исключен:
// Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа. Возврат Новый Структура ( "Ссылка,Код,Наименование" , Реквизит . Ссылка , Реквизит . Код , Реквизит . Наименование ) ;Оптимизация ресурсоемкости передачи данных между Сервером и Клиентом
Когда форма выполняет серверный вызов процедуры &НаСервере, все данные формы упаковываются и передаются на Сервер, а в сложной форме таких данных может быть много, и это приводит к затратам ресурсов и Клиента, и Сервера. Для снижения затрат ресурсов при серверных вызовах везде, где это возможно, следует использовать процедуры &НаСервереБезКонтекста и параметры передаваемые по значению.
В обычном случае реквизит формы сложного типа обрабатывается на Сервере только после преобразования в значение, а затем значение необходимо преобразовать обратно к реквизиту. Выполняются эти преобразования доступными только &НаСервере процедурами:
При оптимизации серверного вызова для выполнения процедур &НаСервереБезКонтекста используется другая пара процедур:
КомандаЗаполнитьРеквизитДеревоНаСервереБезКонтекста ( Объект . Ссылка , ПараметрДерево , РеквизитДиаграмма ) ; КопироватьДанныеФормы ( ДеревоПараметр , РеквизитДерево ) ; Процедура КомандаЗаполнитьРеквизитДеревоНаСервереБезКонтекста ( Знач ОбъектСсылка , ПараметрДерево , РеквизитДиаграмма )Реквизит типа Динамический список используется в подавляющем числе форм отображающих прикладные объекты данных конфигурации, поскольку этот тип позволяет реквизиту установить свойство Основной реквизит, что существенно влияет на свойства и работу формы.
Режим отображения иерархии в динамическом списке
Пример кода открытия формы с установкой необходимого режима отображения списка:
ФормаВыбора = ПолучитьФорму ( "Справочник.Номенклатура.ФормаВыбора" ) ; ФормаВыбора . Элементы . Список . Отображение = ОтображениеТаблицы . Список ;Это замечание имеет значение не только для управляемых форм. Любая форма с динамическим списком Подчиненного справочника без отбора элементов по владельцу отображает его в режиме Список, независимо от установленного программно или в конфигураторе режима отображения (иерархия групп отображаться корректно не будет)!
Программное управление порядком сортировки динамического списка
Код установки сортировки по ДатаРеализации и Клиент:
элементПорядка = Список . Порядок . Элементы . Добавить ( Тип ( "ЭлементПорядкаКомпоновкиДанных" ) ) ; элементПорядка . Поле = Новый ПолеКомпоновкиДанных ( "ДатаРеализации" ) ; элементПорядка . ТипУпорядочивания = НаправлениеСортировкиКомпоновкиДанных . Возр ; элементПорядка . РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных . Авто ; элементПорядка = Список . Порядок . Элементы . Добавить ( Тип ( "ЭлементПорядкаКомпоновкиДанных" ) ) ; элементПорядка . Поле = Новый ПолеКомпоновкиДанных ( "Клиент" ) ; элементПорядка . ТипУпорядочивания = НаправлениеСортировкиКомпоновкиДанных . Возр ; элементПорядка . РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных . Авто ;Однако если в Настройка списка на закладке Порядок установлено Включать в пользовательские настройки, то программное назначение будет подавляться пользовательскими настройками формы, и в таком случае следует использовать другой код:
элементыПользовательскихНастроек = Список . КомпоновщикНастроек . ПользовательскиеНастройки . Элементы ; Для Каждого элемент Из элементыПользовательскихНастроек Цикл Если ТипЗнч ( элемент ) = ТипЗнч ( Список . КомпоновщикНастроек . Настройки . Порядок ) Тогда элементПорядка = элемент . Элементы . Добавить ( Тип ( "ЭлементПорядкаКомпоновкиДанных" ) ) ; элементПорядка . Поле = Новый ПолеКомпоновкиДанных ( "ДатаРеализации" ) ; элементПорядка . ТипУпорядочивания = НаправлениеСортировкиКомпоновкиДанных . Возр ; элементПорядка = элемент . Элементы . Добавить ( Тип ( "ЭлементПорядкаКомпоновкиДанных" ) ) ; элементПорядка . Поле = Новый ПолеКомпоновкиДанных ( "Клиент" ) ; элементПорядка . ТипУпорядочивания = НаправлениеСортировкиКомпоновкиДанных . Возр ;Отбор данных в динамическом списке
Форма может иметь несколько реквизитов типа Динамический список, которые могут не быть основным реквизитом формы, поэтому необходимый отбор данных в них следует выполнять программно. Поскольку существует два принципиально отличных способа получения данных динамическим списком через свойство Основная таблица или из Произвольный запрос, то для каждого используется свой способ отбора
Отбор в основной таблице
Для отбора следует добавить элемент отбора в коллекцию .Отбор.Элементы, как показано на примере:
ОтборВладелец = МойДинамическийСписок . Отбор . Элементы . Добавить ( Тип ( "ЭлементОтбораКомпоновкиДанных" ) ) ; ОтборВладелец . ЛевоеЗначение = Новый ПолеКомпоновкиДанных ( "Владелец" ) ; ОтборВладелец . ВидСравнения = ВидСравненияКомпоновкиДанных . Равно ;Отбор в произвольном запросе
Отбор в произвольном запросе должен использовать параметр запроса, который передается через коллекцию .Параметры.Элементы, как показано в примере:
МойДинамическийСписок . Параметры . УстановитьЗначениеПараметра ( "Владелец" , Объект . Ссылка ) ;Для отображения в управляемой форме табличных данных, в форме должен быть создан реквизит типа ТаблицаЗначений, который будет доступен и на Клиенте, и на Сервере, при этом функционально будет несколько отличаться.
Элементы.<элемент-таблица>.ОтборСтрок = Новый ФиксированнаяСтруктура(<строка реквизитов>, <значение реквизита>);
Важно! Строковое значение используется для поиска по подстроке
Для отображения в управляемой форме иерархической структуры в форме должен быть создан реквизит типа ДеревоЗначений, который может отображаться на форме элементами типа Таблица. В списке реквизитов формы реквизит отображается типом (ДеревоЗначений) в скобках, потому что он проявляет амбивалентность. Реквизит дерева создается и обладает типом ДеревоЗначений на Сервере, но на Клиенте он имеет тип ДанныеФормыДерево, эти два типа отличаться по составу свойств, методов и типов хранимых данных.
При вызове методов формы &НаСервере xdto-преобразование реквизита от типа к типу выполняется прозрачно, но при передаче в возвращаемых параметра серверных вызовов необходимо применять преобразование функциями ЗначениеВРеквизитФормы(), ЗначениеВДанныеФормы(), РеквизитФормыВЗначение(), ДанныеФормыВЗначение().
Типы, свойства и методы для работы с ДеревоЗначений &НаКлиенте и &НаСервере
&НаСервере
Для работы с Деревом значений на Сервере применяется более функциональная иерархия типов работы со строками и колонками:
. Для отображения в управляемой форме иерархической структуры, в форме должен быть создан реквизит типа ДеревоЗначений, который будет доступен и на Клиенте, и на Сервере, при этом функционально будет несколько отличаться.
Форма нового объекта с заполнением
Новый объект (справочника, документа) может быть создан в форме до того, как он будет записан в ИБ (а возможно, не будет записан вовсе). При этом форме можно передать данные для начального заполнения. Общие свойства создаваемого объекта задаются структурой ПараметрыФормы, с предопределенным набором свойств, среди которых есть свойство ЗначенияЗаполнения типа структура, задающая значения для заполнения реквизитов объекта (ключи свойств должны соответствовать именам реквизитов заполняемого объекта):
Пример открытия формы создания группы в справочнике Модели, следующей за некоторой выбранной:
Перед прочтением данной статьи рекомендуется ознакомиться с первой частью, в которой описаны примеры программного создания элементов, команд, реквизитов управляемой формы, а также описание стандартных возможностей для работы с ними.
В данной же части будет рассмотрено программное создание динамических списков, таблиц значений на форме, их вывод в элементы формы и стандартные возможности для работы.
Модифицировать формы рекомендуется программно для удобного обновления конфигураций и исключения конфликтов, а также для удобной поддержки кода. Со статьями о механизмах модификации можно ознакомиться в разделе полезных ссылок.
Также все описанные в текущем разделе процедуры и функции находятся во внешней обработке УпрФормы.
Примеры программного создания элементов, команд, реквизитов управляемой формы, а также описание стандартных возможностей для работы с ними можно будет посмотреть в части 1.
Создание реквизита типа таблица значений и вывод на форму
Добавление условного оформления таблицы формы
Создаем условное оформление для таблицы:
В процедуру команды добавим вызов серверной процедуры для заполнения таблицы цен в зависимости от выбранной номенклатуры и характеристики:
Добавляем в процедуру ПриСозданииНаСервере процедуры:
Заполняем реквизиты Номенклатура, Характеристика и заполняем цены в таблице значений.
Создание реквизита типа динамический список с заданными настройками и вывод на форму
На странице 3 создадим динамический список с выводом всех цен выбранной номенклатуры и характеристики.
Добавим Условное Оформление дин. списка, отбор и сортировку программно.
Вывести динамический список в элементы управляемой формы 1С
Обновление параметров динамического списка программно
Если в запросе дин. списка используются параметры, то их необходимо обновлять при изменении соответствующих реквизитов.
Добавляем в процедуру ПриСозданииНаСервере процедуры:
Заполняем реквизиты Номенклатура, Характеристика и заполняем цены в таблице значений.
Содержимое регистра сведений ЦеныНоменклатуры:
Динамический список на форме:
Добрый день, Коллеги!
//+++ Обновление публикации от 31.08.2020 г.
//--- Обновление публикации от 31.08.2020 г.
Возникла необходимость в программном создании элементов формы, особенно такого как динамический список. Необходимо программно влиять на него полностью, включая и формирование необходимых мне колонок. Данная процедура может выполняться за сеанс формы N-ное количество раз, поэтому и была написана универсальная процедура формирования динамического списка:
Но если мы что-то создаем программно, то должны уметь и удалять это программно. Поэтому вытекающая процедура это удаление списка:
Но не стоит забывать, что просто создать на форме элемент динамического списка - зачастую мало, пример постобработки программно созданного динамического списка демонстрирую ниже.
Пример использования (простой):
Пример использования (сложный):
Демонстрация работы показана на 1С:Комплексная автоматизация 2 (УТ11, ERP), но так же будет работать и в режиме мистической совместимости 8.2.13 (1С:Комплексная автоматизация 1.1), так как именно для старой доброй 1.1 и делалось и используется. Для простоты восприятия пример использования представлен на видео (без озвучки правда), сама обработка прилагается к публикации.
Как видно, в обработке программно (динамически) формируется динамический список на форме в зависимости от смены имени метаданных документа. Если углубиться, то динамически формируется в обработке также и список будущих колонок по наличию реквизитов у документа, а также сама выборка - текст запроса. Ниже демонстрирую, для чего всё это было, упрощение будущего сопровождения при расширение списка документов:
Пример из практики - история разработки этой процедуры
Есть некая разработка регистрации первичных документов. Управление производится через АРМы. Если в начале жизни разработки, АРМ был рассчитан всего на три документа, то мне было несложно разместить все элементы и описать логику их работы. Но время идёт и хотелки растут, вот уже документов стало пять. А потом попросили ещё пять добавить. И я чувствую, это их (бухгалтерию) не остановит. Тут я и понял, что дальнейшее сопровождение АРМа просто мучительно для меня. Переосмысление привело к разработке с нуля, не помню, кто сказал, но перефразирую: "Когда ты чувствуешь что обрастаешь г. внокодом - остановись и начни с нуля". Так и сделал.
Благодаря новой логике, дальнейшее расширение АРМа количеством документов делается просто - добавляются необходимые значения в перечисление ТипДокумента и без кодинга уже будет работать АРМ.
Визуально для конечного пользователя на форме ничего не изменилось за исключением исчезновения "страниц" и появления переключателя "ТипДокумента". Но с технической стороны, изменения колоссальные:
А теперь о неприятном!
При программном создании динамического списка естественно появляется желание программно влиять на весь элемент формы, а именно речь пойдёт о трудностях с командной панелью и контекстным меню. Программно я не нашел способа добраться до свойства "Автозаполнение":
Казалось бы, почему бы не обратиться просто. Элементы[ИмяЭлемента]КоманднаяПанель.Автозаполнение = ЛОЖЬ , но нет такого свойства. Поэтому пришлось применять хитрости (костыли).
Вопрос с командной панелью решил в процедуре публикации следующим образом:
1. Создается программно элемент группа, вид обычная группа, группировка - горизонтальная, отображать заголовок - ложь.
2. Создается программно в выше созданной группе элемент группа с видом командная панель. Именно она теперь будет основной командной панелью будущего динамического списка.
3. Добавляется создаваемый программно элемент таблица формы (динамический список).
4. У таблицы формы отключается вывод командной панели.
Вопрос по отключению "Автозаполнения" в контекстном меню - решения не нашел. Подозреваю, что это невозможно технически.
Одной из удобных возможностей программирования форм является программное создание элементов формы, не прибегая к конструктору форм. И важной особенностью этого является – программное изменение типовых форм, тем самым облегчая обновление типовых конфигураций.
Для понимания того, о чем идет речь – мы создали пустую конфигурацию (ссылка) и создали пустой справочник «Номенклатура». На форме справочника создали 3 группы – страницы .
Создаем пустую конфигурацию.
Создаем новый Справочник.Номенклатура
На вкладке «Данные» добавляем новую табличную часть «ДополнительныеИзображения», и колонку «ИмяФайлаИзображения», тип данных – строка, неограниченной длины.
На вкладке «Формы» добавляем новую форму «ФормаЭлемента».
Форма элемента:
Имя группы (страницы) оставляем как «Группа1», далее
Добавляем в эту группу(Группа1) две страницы.
Группа2 и Группа3, в поле заголовок для группы 2 – вводим «Изображения», для
группы3 – «Каталог»
Теперь переносим табличную часть «ДополнительныеИзображения» в «Группу2»,
и для видимости второй страницы добавили на страницу2 – «Декорацию – Надпись». Должно получиться так, как на картинке:
В свойствах элемента управления «ДополнительныеИзображенияИмяФайлаИзображения» табличной части установите параметр «КнопкаВыбора» в значение «ДА».
Также в свойствах этого поля задайте Событие «НачалоВыбора» для кнопки выбора
На этом проектирование формы закончим и приступим непосредственно к написанию кода. По кнопке выбора при добавлении новой строки с изображениями будем открывать диалог выбора файла и прописывать в имени файла – путь к выбранному изображению.
Процедура
ДополнительныеИзображенияИмяФайлаИзображенияНачалоВыбора ( Элемент , ДанныеВыбора , СтандартнаяОбработка )
//Вставить содержимое обработчика.
Режим = РежимДиалогаВыбораФайла . Открытие ;
ДиалогОткрытияФайла = Новый ДиалогВыбораФайла ( Режим );
ДиалогОткрытияФайла . Фильтр = Фильтр ;
ДиалогОткрытияФайла . МножественныйВыбор = Ложь;
Если ДиалогОткрытияФайла . Выбрать () Тогда
ИмяФайла = ДиалогОткрытияФайла . ПолноеИмяФайла ;
ТекСтрока = Элементы . ДополнительныеИзображения . ТекущиеДанные ;
ТекСтрока . ИмяФайлаИзображения = ИмяФайла ;
В данном случае мы определяем поведение кнопки выбора – открываем диалог открытия файлов в котором пользователь выберет изображение. Если пользователь изображение выбрал – то в текущую строку табличной части добавляем полный путь и имя файла из диалога.
Напишем следующий код для этой предпределенной процедуры:
//Перезаполнить список изображений
Если текущая страница будет «Группа3», тогда сначала удаляем элементы на вкладке «Группа3» и создаем новые реквизиты, давайте посмотрим состав процедуры
«УдалитьРеквизитыСервер()» и «ДобавитьДополнительныеРеквизитыСервер()».
УдаляемыеРеквизиты = Новый Массив ();
Колво = Реквизиты . Количество ();
Для п = 0 по Колво - 1 Цикл
ТекЭлемент = Реквизиты . Получить ( п );
УдаляемыеРеквизиты . Добавить ( ТекЭлемент . Имя );
ДобавляемыеРеквизиты = Новый Массив ;
Для каждого Стрка из Объект . ДополнительныеИзображения
Цикл СчетчикК = СчетчикК + 1 ;
ДобавляемыеРеквизиты . Добавить ( Реквизит );
//Добавляем нов ые пол я ввода на форму
Для каждого Стрка из Объект . ДополнительныеИзображения Цикл
СчетчикК = СчетчикК + 1 ;
Элемент . Вид = ВидПоляФормы . ПолеКартинки ;
Картинка = Новый ДвоичныеДанные ( Стрка . ИмяФайлаИзображения );
ЭтаФорма [ "Реквизит" + Строка ( Счетчикк )] = ПоместитьВоВременноеХранилище ( Картинка , Новый УникальныйИдентификатор );
Итак,что мы имеем?
Мы получаем все реквизиты формы(хотя мы и можем получить реквизиты страницы «Каталог») и в цикле перебираем их. В случае если имя реквизита будет начинаться с «Рек», тогда мы такой реквизит добавляем в массив и он подлежит удалению.
В процедура ДобавитьДополнительныеРеквизитыСервер () происходит следующее: В зависимости от количества добавленных файлов с изображениями мы формируем массив реквизитов к добавлению, причем стоит отметить, что для вывода изображений – мы будем использовать элемент формы, реквизит которого будет иметь тип значения – строка. Имена получаемых реквизитов будут такими «Реквизит1, Реквизит2», … «Реквизит N ».
Далее процедура ИзменитьРеквизиты) в которой первый параметр – это добавляемые реквизиты, второй удаляемые реквизиты) – добавляет новые реквизиты.
И остается также загрузить из файла и вывести на экран наши картинки. В текущем примере мы не добавляем их в нашу информационную базу – а считываем их каждый раз из файлов. Сначала считываем файл картинки, как двоичные данные, далее помещаем данные во временное хранилище процедурой ПоместитьВоВременноеХранилище , тем самым получаем строку.
В итоге мы получаем динамическое создание элементов формы и реквизитов, и в зависимости от состава табличной части – мы выводим на вкладке «Каталог» изображения.
Читайте также: