Опыт программирования в 1с 8.3 управляемые формы. СтавАналит

Жаропонижающие средства для детей назначаются педиатром. Но бывают ситуации неотложной помощи при лихорадке, когда ребенку нужно дать лекарство немедленно. Тогда родители берут на себя ответственность и применяют жаропонижающие препараты. Что разрешено давать детям грудного возраста? Чем можно сбить температуру у детей постарше? Какие лекарства самые безопасные?

Тоньше некуда. Теперь клиентское приложение не выполняет запросы к базе данных (это дело сервера). Клиентское приложение просто отображает интерфейс и данные.

Стоит отметить, что структура кода стала сложнее из-за таких преобразований. На клиенте нет ссылок, объектов, таблицы значений... доступны только примитивные типы (строка, дата, булево, массив, структура...). А значит программист должен теперь думать, что получить на сервере, и как это сделать с минимальными затратами.

Взаимодействие клиента и сервера

Новый подход к взаимодействию клиента и сервера позволил создать новую модель пользовательского интерфейса. Теперь интерфейс декларируется(!) проектирование интерфейса начинается с данных, с реквизитов и табличных частей. Создавая реквизит, вы обязаны думать, как он будет выглядеть в интерфейсе, будет ли он обязательным, как связан с другими реквизитами...

Отсутствие контекста (состояния) на сервере

Сервер 1С работает по принципу «без состояния» (англ. state-less). Это означает что сервер только отвечает на запросы, и при этом ничего не сохраняет у себя в промежутке между двумя запросами (для этих целей есть временное хранилище).

ДанныеФормыВЗначение, ДанныеФормыКоллекция, ДанныеФормы...

Мы обратились к серверу, он для нас все выполнил, удалил данные и забыл что мы приходили. Все объекты с именами "ДанныеФормы" + "что-то там" помогут нам сохранить свои данные между двумя серверными вызовами.

Временное хранилище

Временное хранилище, это специальное место, в котором (помимо реквизитов формы) можно сохранять состояние на сервере. В хранилище можно хранить данные, которые на клиенте недоступны (т.е. которые нельзя разместить реквизитах формы).

Для работы с временным хранилищем используются методы ПоместитьВоВременноеХранилище() Синтаксис: ПоместитьВоВременноеХранилище(<Данные>, <Адрес>) Описание: Сохраняет сериализуемое значение во временное хранилище. Доступность: Тонкий клиент, веб-клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение(клиент), мобильное приложение(сервер). Вызов метода выполняет обращение к серверу. <Адрес> (необязательный) Тип: УникальныйИдентификатор; Строка. Уникальный идентификатор формы, во временное хранилище которой надо поместить данные и вернуть новый адрес. Или адрес во временном хранилище, по которому надо поместить данные. Адрес должен быть получен ранее с помощью данного метода. В случае, если передается УникальныйИдентификатор формы или адрес в хранилище, то значение будет автоматически удаленопосле закрытия этой формы. Если передан УникальныйИдентификатор, не являющийся уникальным идентификатором формы, то значение будет удалено после завершения сеанса пользователя. Если параметр не указан, помещенное значение будет удалено после очередного запроса сервера из общего модуля, при контекстном и неконтекстном серверном вызове из формы, при серверном вызове из модуля команды или при получении формы. Примечание: Временное хранилище, сформированное в одном сеансе, недоступно из другого сеанса. Исключением является возможность передачи данных из фонового задания в сеанс, инициировавший фоновое задание, с помощью временного хранилища. Для такой передачи следует в родительском сеансе поместить во временное хранилище пустое значение, передав идентификатор формы. Затем полученный адрес передать в фоновое задание через параметры фонового задания. Далее, если этот адрес использовать в параметре <Адрес>, то результат будет скопирован в сеанс, из которого было запущено фоновое задание. Данные, помещенные во временное хранилище в фоновом задании, не будут доступны из родительского сеанса до момента завершения фонового задания. и ПолучитьИзВременногоХранилища() Синтаксис: ПолучитьИзВременногоХранилища(<Адрес>) Описание: Получает значение из временного хранилища. Доступность: Тонкий клиент, веб-клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение(клиент), мобильное приложение(сервер). Вызов метода выполняет обращение к серверу. Примечание: Результат выполнения не кэшируется, вызов сервера осуществляется при каждом вызове метода.

Вызов серверного кода

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

Назначение флагов модулей

  • Флаг показывает, где будет скомпилирован код модуля (на сервере, на клиенте, во внешнем соединении)
  • Если модуль скомпилирован в нескольких местах, то он будет виден только в соответствии с флагами
  • Перенос исполнения кода возможен только если в текущем контексте исполнения нет вызываемого модуля, но он есть в другом месте (если – модуль есть только на сервере, а на клиенте его нет, то будет сделан вызов сервера)

Флаг «Вызов сервера»

Начиная с платформы "1С:Предприятие 8.2" добавился флаг «вызов сервера». Который как раз и помогает "разрулить" условия перехода на другую машину. Если модулю назначить этот флаг, то модуль будет виден с клиента, если нет – то попытка вызова с клиента приведет к ошибке. Код модуля виден не будет, как будто его нет совсем.

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

  • Установлен флажок «Сервер»
  • Установлен флажок «Вызов сервера»
  • Сняты все «клиентские» флажки

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

Введение

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

Немного истории

Исторически сложилось, что клиентское приложение 1С всегда было реализовано в виде так называемого «толстого» клиента – программы, которая сама все делает в плане обработки данных. Это создавало заметную нагрузку на сеть, а кроме того, требовало наличия мощных клиентских машин.

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

Версия 8.0 принесла нам трехзвенную архитектуру, в которой появился «сервер 1С:Предприятия» – отдельный программный компонент, который мог выполнять код бизнес-логики на специально выделенной мощной машине (сервере), тем самым, снизив объем данных, гуляющих по сети и требования к аппаратной части клиентских машин.

И все бы ничего, но до версии 8.2 и появления управляемого приложения реализация серверного кода была совсем необязательной частью. Существовал ряд проблем, объективных и субъективных, которые мешали использовать сервер для обработки бизнес-логики. Код на сервере выполнялся, но в очень редких случаях, когда его специально, не без помощи костылей, заставляли там выполняться.

В основном, все оставалось по-старому, и клиентское приложение так и оставалось «толстым» клиентом, гоняющим сотни мегабайт по сети.

Версия 8.2 кардинально сломала устоявшийся подход к работе приложения и заставила по-новому взглянуть на архитектуру приложения. Об этом новом подходе и пойдет речь в данной статье.

Волшебный зверь Клиент-сервер

С выходом версии 8.0 все учебные курсы, книжки, статьи на ИТС и прочее, и прочее, все в один голос твердили нам – «обработка данных должна идти на сервере», «все нужно выполнять на сервере». Волшебное заклинание «на сервере» плотно забило мозг, так сильно, что на него уже никто внимания не обращал, как на информационный шум.

Опыт показывает, что рядовой программист практически никогда не знал, как нужно перенести код на сервер и что это вообще значит – «на сервер». Удивительно часто встречался код, который переносился «на сервер», но был написан с явным непониманием того, что это в итоге принесет.

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

Однако многие уже опытные разработчики запросто писали такой код:

  • Выбирается локальный файл
  • Его путь передается на сервер
  • Там по этому пути файл пытается открыться и падает с ошибкой «Файл не найден» (еще бы, он же остался на клиенте).
Переход на сервер

До версии 8.2 перенести исполнение кода на сервер можно было только одним способом – а именно, вызовом общего модуля с флагом «Сервер». Причем, только с этим флагом. Если помимо флага «сервер» поставить «клиент», то перехода не произойдет.

Суть всех флагов модуля сводится к простым правилам:

  1. Флаг показывает, где будет скомпилирован код модуля (на клиенте, на сервере, во внешнем соединении)
  2. Если модуль скомпилирован в нескольких местах, то он будет виден только в соответствии с флагами. Клиентский – на клиенте, серверный на сервере. Переноса исполнения с машины на машину не будет.
  3. Перенос исполнения кода возможен только если в текущем контексте исполнения нет вызываемого модуля, но он есть в другом месте (если – модуль есть только на сервере, а на клиенте его нет, то будет сделан вызов сервера)
Флаг «Вызов сервера»

В версии 8.2 добавился флаг «вызов сервера», который помогает разрулить условия перехода на другую машину. Если модулю назначить этот флаг, то модуль будет виден с клиента, если нет – то попытка вызова с клиента приведет к ошибке. Код модуля виден не будет, как будто его нет совсем.

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

  1. Установлен флажок «Сервер»
  2. Установлен флажок «Вызов сервера»
  3. Сняты все «клиентские» флажки
Особенности перехода на сервер

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

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

Это объясняет, почему не все объекты можно передавать на сервер. Это все потому, что не все они поддерживают сериализацию (превращение в строку и обратно). На сервер нельзя передать, например, «ДокументОбъект», т.к. у него в модуле объекта могут быть глобальные переменные, а в них записаны какие-нибудь сложные несериализуемые значения, вроде COM-объектов… Короче, ограничения по обмену с сервером понятны и обоснованны. Нужно следить за тем, что мы передаем на сервер и что возвращаем назад.

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

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

Отсутствие контекста (состояния) на сервере

Существует такая модель серверных приложений, когда сервер только отвечает на запросы, но ничего не сохраняет у себя в промежутке между двумя запросами. Эта модель называется моделью «без состояния» (англ. state-less).

Все HTTP-серверы современного интернета работают именно так. Клиенты посылают запросы, сервер выдает ответ и забывает все, что получал от клиента. Разумеется, есть вариации, но общая модель именно такая: сервер отрабатывает запрос и очищает все данные.

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

Есть специальные объекты, в которых можно хранить очень незначительную часть данных – так называемые «параметры сеанса», но это именно специально выделенное место для хранения состояния. Каждый серверный вызов выполняет некоторую работу, возвращает результат и забывает все свои данные. В управляемом режиме про это всегда необходимо помнить.

Управляемое приложение

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

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

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

Тонкий клиент

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

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

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

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

Тонкий клиент стал поистине «клиентом». Он больше не обрабатывает данные, он их показывает и позволяет редактировать. Всю обработку мы теперь явно переносим на сервер.

Устройство управляемой формы

Давайте рассмотрим, из каких частей состоит управляемая форма.

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

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

Данные формы

Есть старая уже хохма про ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокументИмениНуралиеваБорисаГеоргиевича.

Управляемая форма добавляет очередного претендента на звание длинного и непонятного идентификатора: ДанныеФормыСтруктураСКоллекцией и еще ряд новых классов с именами вида «ДанныеФормы….что-то там». Давайте попробуем выяснить, что это за новые объекты.

Как уже говорилось выше, сервер предприятия не сохраняет свое состояние между двумя вызовами. Когда мы обратимся к серверу, он что-то выполнит для нас и тут же очистит все данные, созданные во время вызова. Объекты с именами «ДанныеФормы…» это как раз то место, в котором мы можем сохранять свои данные между двумя серверными вызовами. На сервере нельзя создать глобальную переменную уровня формы. Такой глобальной переменной должен быть реквизит в данных формы.

Обратите внимание, что классы данных формы любопытно называются «ДанныеФормыСтруктура» или «ДанныеФормыКоллекция». Это вообще, как мне кажется, неспроста. Эти объекты – это просто немного модифицированная стандартная Структура (или ТаблицаЗначений, соответственно).

Здесь стоит немного вспомнить обычные формы. Ведь как мы привыкли – В форме справочника достаточно присвоить переменной «Наименование» какой-то текст и этот текст попадет в СправочникОбъект, а оттуда – в информационную базу.

У управляемой форме все почти так, за исключением того, что все совсем не так (IMG:) .Платформа предпринимает массу усилий, чтобы в повседневной работе программиста ему не приходилось с этим заморачиваться. Как правило, мы, как и раньше, присваиваем свойства реквизитам формы, а они попадают в СправочникОбъект, а оттуда – в ИБ.

Разница заключается в том, что теперь на клиенте не существует «СправочникОбъект». Как я уже говорил, это сложный объект, он не сериализуется, а значит, его нельзя передавать с клиента на сервер. Вместо «Объекта» на клиенте существует его упрощенный аналог – хранилище данных – объект ДанныеФормы.

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

Адресация данных формы

Данные формы доступны непосредственно в коде по тем именам, как они расположены в дереве реквизитов формы (в окне редактора)

Реквизиты верхнего уровня доступны сразу. Вложенные реквизиты доступны через точку. Раньше в обычной форме мы обращались к данным объекта напрямую. Мы писали «Наименование = «АААААА» и данные попадали в объект. Теперь надо писать «Объект.Наименование = «ААААА», потому, что реквизит «Наименование» вложен внутрь реквизита «Объект».

Обмен формы с сервером

Основным «двигателем» всех аспектов управляемой формы является то, что у нас state-less сервер. На нем не сохраняется ничего, никаких промежуточных данных. Всё состояние формы (текст в полях ввода, строки табличных частей и т.п.) хранится на клиенте. Вся совокупность данных формы называется контекстом формы.

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

Жизненный цикл формы объекта

Давайте рассмотрим, что происходит, когда мы открываем форму существующего элемента справочника.

  • На клиенте вызывается метод «ОткрытьФорму» или мы просто открываем форму из какого-либо списка справочника. Начинается серверный вызов
  • В памяти сервера создается новый СправочникОбъект, выполняется код модуля объекта (тот, что написан в самом низу модуля)
  • Данные объекта считываются из базы данных, присваиваются значения реквизитов, наполняются табличные части объекта СправочникОбъект.
  • В памяти сервера создается новая управляемая форма элемента
  • Вызывается событие формы ПриЧтенииНаСервере, куда передается свежесозданный СправочникОбъект в параметре ТекущийОбъект
  • Основной реквизит формы «Объект», тот, что в списке реквизитов выделен жирным шрифтом наполняется данными на основании данных СправочникОбъект. Здесь происходит обычное поэлементное присваивание свойствам объекта ДанныеФормы значений, записанных в одноименных свойствах объекта СправочникОбъект. По сути, происходит «ЗаполнитьЗначенияСвойств(ДанныеФормы, СправочникОбъект)
  • СправочникОбъект уничтожается . Все его данные стираются из памяти сервера.
  • Вызывается событие формы «ПриСозданииНаСервере», в котором мы получаем уже заполненные ДанныеФормы
  • Данные формы сериализуются и отправляются на клиента, где форма отображается пользователю
Обратите внимание, что СправочникОбъект, к которому мы так привыкли в обычном приложении, уничтожился. Если в модуле объекта были какие-либо глобальные переменные, экспортные или не экспортные, все они стали потеряны.

Теперь, давайте рассмотрим процесс записи данных справочника:

  1. Пользователь нажимает кнопку «Записать»
  2. Выполняется обработчик формы «ПередЗаписью» (на клиенте)
  3. Происходит серверный вызов
  4. В памяти сервера создается новый СправочникОбъект, он наполняется данными на основании данных текущей формы (что-то вроде ЗаполнитьЗначенияСвойств, но в обратном направлении – пишется из формы в объект)
  5. Вызывается обработчик события формы «ПередЗаписьюНаСервере», куда передается свежесозданный СправочникОбъект. С этого момента, если мы хотим что-то записать в базу данных, то менять нужно именно СправочникОбъект. Изменения данных формы не отразятся в записываемом объекте.
  6. Вызывается обработчик «ПередЗаписью» самого СправочникОбъект (в модуле объекта)
  7. Вызывается обработчик «ПриЗаписи» самого СправочникОбъект (в модуле объекта)
  8. Вызывается обработчик события формы «ПриЗаписиНаСервере», транзакция записи еще не завершена и можно отменить запись
  9. Вызывается обработчик события формы «ПослеЗаписиНаСервере», транзакция записи уже завершена
  10. СправочникОбъект уничтожается
  11. Выполняется возврат на клиента, где вызывается обработчик события формы «ПослеЗаписи»
Обратите внимание, серверное состояние восстанавливается с нуля, каждый раз создается новый СправочникОбъект. В промежутках между вызовами сервера он не сохраняется.

Конвертация данных формы

Для упрощения жизни существуют простые способы преобразования универсальных объектов «ДанныеФормы….» в привычные прикладные объекты и наоборот.

Так, например, можно получить наполненный данными СправочникОбъект на основании данных формы, если вызвать метод «РеквизитФормыВЗначение(«Объект»). При этом произойдет то, что описано выше – будет создан новый СправочникОбъект и наполнен данными из указанного реквизита данных формы.

Обратное преобразование выполняется методом «ЗначениеВРеквизитФормы». Если мы произвели какие-то действия с данными СправочникОбъект, например, очистили табличную часть, то мы должны поместить наши изменения обратно в форму, иначе будет что?

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

Не все так плохо (IMG:)

Все эти сложности с преобразованием данных полезно знать, однако, они совсем не обязательны. Платформа прекрасно справляется с ними сама. В большинстве случаев достаточно никогда не вспоминать про СправочникОбъект, а работать непосредственно с данными формы. Грязную работу платформа сделает сама.

Команды формы

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

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

Каждая команда может быть размещена в командной панели, подменю, или на самой форме. Создаются команды на закладке «Команды» в редакторе формы.

Параметры формы

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

Управление открытием формы

Отображение форм на экране в управляемом режиме также претерпело некоторые изменения. Прежде всего, формы получили имена, по которым к ним можно обращаться. Например, форма списка справочника «Контрагенты» будет называться «Справочник.Контрагенты1.ФормаСписка».

Методика открытия формы теперь такова: форма должна открываться одной строчкой кода и одним вызовом сервера. Эту задачу на себя берет глобальный метод «ОткрытьФорму». В данный метод мы должны передать имя формы (см. выше), параметры формы, владельца и ключ уникальности. Все параметры, кроме имени являются необязательными.

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

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

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

УсловияОтбора = Новый Структура;
УсловияОтбора.Вставить("ТипКонтрагента", "Поставщик");
УсловияОтбора.Вставить("Лояльность", "Надежный");
ОткрытьФорму("Справочник.Контрагенты.ФормаСписка", УсловияОтбора);

Существуют системные параметры, на которые реагирует сама платформа. Упомянутый параметр «Отбор» как раз является системным, если он передан форме списка, то платформа сама установит отбор на список.

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

Жизненный цикл параметров

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

Исключение составляют параметры, которые в редакторе формы объявлены с признаком «Ключевой параметр». Такой параметр будет существовать до тех пор, пока существует сама форма.

Процедура ПриСозданииНаСервере(Отказ)

Если Параметры.ЗапуститьЯдерныйРеакторПриОткрытии Тогда
УправлениеРеактором.Запустить();
КонецЕсли;

КонецПроцедуры

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

Модуль формы

Справедливости ради стоит отметить, что они доступны не только в модулях форм, но, как правило, используются только там. Директива компиляции это строчка вида &НаКлиенте перед объявлением процедуры.

Для модуля форм возможны следующие директивы:

  • &НаКлиенте
  • &НаСервере
  • &НаСервереБезКонтекста
  • &НаКлиентеНаСервереБезКонтекста
Директива указывает компилятору, где нужно скомпилировать указанную процедуру. С директивами «НаКлиенте» и «НаСервере» все понятно, а вот с добавкой «БезКонтекста» нужно разобраться подробнее.

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

контекст формы, т.е. ее данные. Когда мы вызываем сервер «с контекстом», то контекст должен быть передан на сервер, поскольку его там в данный момент просто не существует (сервер state-less).

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

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

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

Для облегчения клиент-серверного обмена введено понятие серверного вызова «без контекста». Отличается он тем, что при вызове «без контекста» контекст формы не передается и в серверном коде будет недоступен. Процедура «без контекста» не видит данных формы. Фактически, это вообще не модуль формы, а некий отдельный модуль, который ничего про форму не знает.

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

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

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

Переменные уровня модуля формы

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

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

Временное хранилище – секретное оружие

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

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

Для работы со временным хранилищем используются методы ПоместитьВоВременноеХранилище и ПолучитьИзВременногоХранилища.

С методом «Получить» все просто, он по заданному адресу возвращает значение, которое лежит в хранилище.

С методом «Поместить» несколько сложнее. Дело в том, что помещать можно в 2 разных хранилища – простое и хранилище формы. Хранилище формы живет на сервере столько, сколько живет сама форма. Простое хранилище живет ровно 2 серверных вызова. В синтакс-помощнике об этом написано целых несколько умных строк. Я никогда не понимал, что они означают. Опытным путем было установлено, что срок жизни – 2 серверных вызова.

  • Первый – мы помещаем что-то в хранилище и возвращаем адрес на клиента.
  • Клиент делает второй вызов и по этому адресу может получить данные.
  • В третьем вызове по этому адресу уже ничего не будет. Платформа очистит хранилище
С хранилищем формы ситуация более интересная. Если вторым параметром метода «ПоместитьВоВременноеХранилище» передать идентификатор формы (ЭтаФорма.УникальныйИдентификатор), то данные в хранилище будут привязаны к сроку жизни формы и не будут удалятся ни в первых, ни во вторых, ни во всех прочих вызовах сервера.

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

Особенности временного хранилища

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

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

Как примерно работает временное хранилище:

  • Данные помещаются в ВХ
  • Управление возвращается на клиента
  • Клиент делает повторный серверный вызов
  • Менеджер кластера переключает вызов на другую машину из кластера (не ту, что помещала данные в хранилище)
  • И вот тут, если данные в хранилище были сериализуемые, то все отлично, мы получим их даже на другой машине кластера.
  • Если данные не были сериализуемые (СправочникОбъект, COM-объект, что-то еще), то они просто пропадут, ибо нефиг.
Если не вдаваться в дебри документации, то можно сказать примерно следующее: данные во временном хранилище существуют в пределах двух серверных вызовов, либо, если они помещены в хранилище формы, то в течение жизни формы.

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

Если тип данных, помещенных в хранилище не поддерживал сериализацию, то данные просто уничтожаются.

Массив = Новый Массив; Массив.Добавить("Привет");

Адрес = ПоместитьВоВременноеХранилище(Массив);

Массив.Добавить("До свидания");

МассивИзХранилища = ПолучитьИзВременногоХранилища(Адрес);

Сообщить(Массив = МассивИзХранилища); // Истина

Сообщить(МассивИзХранилища.Количество()); // 2 элемента

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

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

С одной стороны, логика довольно путанная, с другой стороны, ничего страшного. Главное помнить о подводных камнях и не закладывать логику на какое-то побочное поведение хранилища.

Краткий итог

  • Взаимодействие с сервером теперь не спрятано от разработчика. Наоборот, оно каждую минуту напоминает о себе. И это хорошо.
  • Сервер 1С не сохраняет данные между обращениями клиента к серверу. Нужно проектировать взаимодействие с учетом этой особенности
  • Временное хранилище – мощное средство, которое нивелирует сложности state-less взаимодействия и позволяет строить сложные схемы серверных вызовов.
  • У формы есть контекст, который передается с клиента на сервер и обратно при каждом контекстном вызове сервера. Для несложных вызовов, где не требуется вся форма целиком, следует использовать внеконтекстные вызовы.
Заключение

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

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

Литература к прочтению

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

Постскриптум

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

[необходимо зарегистрироваться для просмотра ссылки]

Допустим, есть внешняя обработка, написанная для версии 8.1. Можно ли запустить ее в версии 8.2 так, чтобы работать с ее старой, неуправляемой формой? Обработка нужна всего один раз, для переноса данных, и создавать для нее управляемую форму ради одного раза не хочется...

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

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

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

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

При этом нужно помнить, что запуск клиентов в управляемом режиме возможен только в том случае, если у конфигурации отключена совместимость в версией 8.1 (свойство РежимСовместимости ).

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

Возможность использования обычных форм в управляемом режиме регулируется специальным свойством конфигурации - ИспользоватьОбычныеФормыВУправляемомПриложении . Это свойство нужно установить.

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

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

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

Доброго времени суток.

Вот список того, что тут можно будет почерпнуть:

  1. Отображение табличной части документа в виде дерева и обратное преобразование в табличную часть.
  2. Работа с условным оформлением и его программное использование.
  3. Динамическое изменение состава реквизитов формы
  4. Удобный интерфейс по редактированию дерева

А теперь вот исходные данные решаемой задачи:

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

Т.е. у нас вырисовывается следующая структура табличной части документа:

этаж - пока не понятно что это такое

объем работ - число 15.3

количество материалов - число 15.3

Вроде бы просто, но на практике мы получаем много повторяющейся информации. Например у нас две работы, в каждой 10 материалов, и 9 этажей. Это будет 180 строк в документе, в которых колонка "работа" везде почти одинаковая, каждый материал повторяется по 9 раз.

Ниже на рисунке два представления одной и той же информации. 1 - Линейно, 2 - в виде дерева с динамическими колонками количества. Для наглядности разные данные выделил цветами: красный - работа, синий - материал, этаж - сиреневый, зеленый - объем работы, орнажевый - к.расхода, черный - количество материалов.

Второй вариант явно экономит место на экране. В первом у нас 150 ячеек с информацией, во втором - 52. Причем, чем больше этажей, материалов в работе, тем экономия сильнее.

Вот второй вариант мы с Вами в этом уроке и реализуем.

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

  • Справочник "Работы"
  • Справочник "Материалы" (или номенклатура - не важно)
  • Документ "..." (можете назвать его "Смета" или еще как)
  • Регистр сведений, периодический, в котором измерения: работа, материал; ресурс: к.расхода (можете для него сбацать регистратор, можете оставить непосредственное редактирование)

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

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

Тут у нас не хватает третьей аналитики - этаж. В нашем случае это будет целое положительно число. Для удобства, добавим в шапку поле "Количество этажей". Это поле нам сильно упростит жизнь. Случай, когда в таб.части есть этаж №9, а максимум этажей - 8, считаем не допустимым, эти строки будут пропавшими безвести.

Следующим шагом избавимся от поля "ОбъемРабот" и оставим только количество. В строках, где НомерМатериалаВРаботе = 0 будем считать количество - объемом работ.

Со структурой - все, идем в форму. Создадим форму по умолчанию, в которой разместим все, что есть.

Первое - номер и дату сделаем в одну строку, это действие надо делать на автомате всегда, это уже как лесенка в коде.

Далее рисуем реквизит формы "ДеревоРабот" с типом значения "Дерево значений". Добавим в него колонки: Номер, РаботаМатериал, кРасхода, ЭтоРабота. Среди элементов создадим две страницы: служебная, туда отправим реальную таб.часть, и дерево, туда отправим дерево. У дерева отобразим все колонки, кроме флажка "ЭтоРабота".

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

Вот её синтаксис:

&НаСервере
Процедура ОбновитьСоставКолонок()
//1. Правим ревизит формы, добавляем в дерево колонки
дерево = РеквизитФормыВЗначение("ДеревоРабот");
мКУдалению = Новый Массив;
МаксНомерКолонки = 0;
Для каждого Колонка Из Дерево.Колонки Цикл
Если Лев(Колонка.Имя, 3) = "Кол" тогда
НомерКоличества = число(сред(Колонка.Имя,4));
Если НомерКоличества>Объект.КоличествоЭтажей Тогда
мКУдалению.Добавить(Колонка);
КонецЕсли;
Если НомерКоличества>МаксНомерКолонки Тогда
МаксНомерКолонки = НомерКоличества;
КонецЕсли;
КонецЕсли;
КонецЦикла;
//2.
РеквизитыКУдалению = Новый Массив;
Для Каждого элементМКУдалению Из мКУдалению Цикл
РеквизитыКУдалению.Добавить("ДеревоРабот." + элементМКУдалению.Имя);
//элемент формы надо грохнуть раньше, чем реквизит
Элементы.Удалить(Элементы["ДеревоРабот" + элементМКУдалению.Имя])
КонецЦикла;
//3.
РеквизитыКДобавлению = Новый Массив;


НовыйРеквизитФормы = Новый РеквизитФормы("Кол"+НовыйНомер, Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15,3)), "ДеревоРабот", "к "+НовыйНомер);
РеквизитыКДобавлению.Добавить(НовыйРеквизитФормы);
КонецЦикла;
//4.
ИзменитьРеквизиты(РеквизитыКДобавлению,РеквизитыКУдалению);
//5. Рисуем новые элементы формы, добавлять их надо после создания ревизитов
Для ж=1 По объект.КоличествоЭтажей - МаксНомерКолонки Цикл
НовыйНомер = МаксНомерКолонки + ж;
НоваяКолонка = Элементы.Добавить("ДеревоРаботКол"+НовыйНомер, Тип("ПолеФормы"), Элементы.ДеревоРабот);
НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
НоваяКолонка.ПутьКДанным = "ДеревоРабот.Кол"+НовыйНомер;
НоваяКолонка.Ширина = 7;
НоваяКолонка.УстановитьДействие("ПриИзменении", "КоличествоПриИзменении");
НоваяКолонка.Заголовок = "к " + ж;
КонецЦикла;
КонецПроцедуры

Прокомментируем этапы её работы:

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

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

3. Создаем список колонок, которые надо создать.

4. Вызываем встроенную процедуру ИзменитьРеквизиты, после этого у нас уже нет лишних колонок и появились недостающие.

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

-нельзя удалять реквизиты, созданные не программно

-нельзя удалять реквизиты, используемые в элементах формы

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

Теперь напишем процедуру преобразования таблицы в дерево. Для теста заполним в документе табличную часть как на рисунке:

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

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

Комментировать тут особо нечего. С помощью полей "номерРаботы" и "НомерМатериалаВРаботе" определяю, что перед нами, строка с работой или материалом, соответственно добавляем строку в корень или в работу. Если сменился только этаж, то берем только количество. Лишние этажи обрубаются, пропущенные этажи - не испортят структуру дерева.

Вызываем эту процедуру при создании на сервере после "ОбновитьСоставКолонок()".

Теперь можно её протестировать запустив предприятие и открыв созданный ранее документ.

Теперь нам надо перед записью документа сделать наоборот, дерево сохранить в табличную часть. Пишем процедуру:

&НаКлиенте
Процедура ПоместитьДеревоВТабЧасть()
Объект.Материалы.Очистить();
Для Каждого стрРаботы Из ДеревоРабот.ПолучитьЭлементы() Цикл


стр.Этаж = ж;
стр.Количество = стрРаботы["Кол"+ж];
КонецЦикла;
Для Каждого стрМатериала Из стрРаботы.ПолучитьЭлементы() Цикл
Для ж=1 По Объект.КоличествоЭтажей Цикл
стр = Объект.Материалы.Добавить();
стр.НомерРаботы = стрРаботы.Номер;
стр.НомерМатериалаВРаботе = стрМатериала.Номер;
стр.Работа = стрРаботы.РаботаМатериал;
стр.Материал = стрМатериала.РаботаМатериал;
стр.КРасхода = стрМатериала.КРасхода;
стр.Этаж = ж;
стр.Количество = стрМатериала["Кол"+ж];
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецПроцедуры

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

Следует заменить, что условное оформление форм работает только в конфигурациях использующих управляемое приложение (Бухгалтерия 3.0, ЗУП 3.0/3.1, Управление торговлей 11 и т.п.)

Условное оформление 1с. Интерактивная настройка

Еще один плюс условного оформления — его можно настроить не написав ни строчки кода. Для этого в форме необходимо:

  • Открыть свойства формы -> вкладка оформление -> УсловноеОформление Открыть;
  • Откроется таблица ;
  • В первом столбце необходимо выбрать оформление (или сразу несколько);
  • Во втором столбце задать условие, по которому будет срабатывать выбранное оформление;
  • С третьем столбце необходимо выбрать элементы формы на которые будет действовать выбранное оформление.

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

Условное оформление формы. Пример интерактивной настройки

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

Форма обработки выглядит так:

Настроим следующее условное оформление данной формы: при установке реквизита СкрытьКолонку1 в значение Истина , в таблице форме скрывать реквизит Колонка1 .

  • Откроем настройку условного оформления формы;
  • Добавим в таблицу новую строку;
  • В колонке Оформление нажмем на кнопку с тремя точками и выберем параметр Видимость , значение Нет ;

  • В колонке Условие нажмем на кнопку с тремя точками, в открывшемся окне добавим новый отбор. Пропишем туда следующие значения: Левое значение — СкрытьКолонку1, Вид сравнения — Равно, Правое значение — Да ;

  • В колонке Оформляемые поля нажмем на кнопку с тремя точками, в открывшемся окне добавим новый элемент, и выберем значение ТаблицаФормыКолонка1 ;
  • В итоге у нас должна получиться настройка условного оформления, такая же как на следующем рисунке;

  • Нажмем кнопку Ок , сохраним нашу обработку и запустим ее в режиме 1С Предприятие ;
  • При установке флажка Скрыть колонку 1 , будут происходить следующие изменения в оформлении формы.


Условное оформление 8.3. Пример программной настройки

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

В модуле формы создадим серверную процедуру, назовем ее УстановитьУсловноеОформление и сразу же допишем ее вызов в процедуре ПриСозданииНаСервере .

&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) УстановитьУсловноеОформление(); КонецПроцедуры &НаСервере Процедура УстановитьУсловноеОформление() КонецПроцедуры

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

Элемент = УсловноеОформление.Элементы.Добавить();

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

Элемент = УсловноеОформление.Элементы.Добавить(); ПолеЭлемента = Элемент.Поля.Элементы.Добавить(); ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(Элементы.ТаблицаФормыКолонка2.Имя); ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ПоменятьЦветКолонки2"); ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; ОтборЭлемента.ПравоеЗначение = Истина; Элемент.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(255, 0, 0));

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

&НаСервере Процедура УстановитьУсловноеОформление() Элемент = УсловноеОформление.Элементы.Добавить(); ПолеЭлемента = Элемент.Поля.Элементы.Добавить(); ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(Элементы.ТаблицаФормыКолонка2.Имя); ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ПоменятьЦветКолонки2"); ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; ОтборЭлемента.ПравоеЗначение = Истина; Элемент.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(255, 0, 0)); Элемент = УсловноеОформление.Элементы.Добавить(); ПолеЭлемента = Элемент.Поля.Элементы.Добавить(); ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(Элементы.ТаблицаФормыКолонка3.Имя); ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("СделатьНедоступнойКолонку3"); ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; ОтборЭлемента.ПравоеЗначение = Истина; Элемент.Оформление.УстановитьЗначениеПараметра("Доступность", Ложь); КонецПроцедуры

Напомню, что скачать обработку написанную на основе разобранных примеров можно .

Поддержите проект — поделитесь ссылкой, спасибо!
Читайте также
Презентация на тему: Невербальные средства общения Презентация на тему: Невербальные средства общения Турагент: бесплатные путешествия или нервная работа? Турагент: бесплатные путешествия или нервная работа? Современные проблемы науки и образования Факторы, влияющие на процесс принятия решений Современные проблемы науки и образования Факторы, влияющие на процесс принятия решений