Что такое модальность в 1с
Клиентские приложения все чаще используются при помощи веб-клиента, что предъявляет определенные требования к коду. В этой статье я постараюсь рассказать о модальности в 1С — когда и почему следует от нее отказаться и как это сделать.
Общая информация
В начале рассмотрим общие вопросы связанные с модальными окнами в 1С.
Что не так с модальными окнами?
С модальными окнами все в порядке. Они широко используются в 1С в тех случаях, когда от пользователя требуется ввод информации без которой невозможно дальнейшее выполнение программы. Остальной интерфейс при этом блокируется, а выполнение кода приостанавливается до тех пор, пока модальное окно не будет закрыто.
Когда следует отказаться от модальности?
Разумеется отказ от модальности необходим далеко не всегда.
Во-первых, режим работы интерфейса без использования модальности появился в версии технологической платформы 8.3.3.721 (от 06.09.2013) — следовательно, при использовании предыдущих версий технологической платформы, не нужно задумываться об отказе от модальности.
Режим использования модальности
Во-вторых, не все прикладные решения обязаны использовать этот режим. Отказ от модальности является критичным для приложений которые будут использоваться:
Нужно отметить, что во всех типовых конфигурациях (речь о новых или не слишком старых версиях) основной режим работы интерфейса — режим без использования модальности. Об этом нужно помнить при внесении изменений в эти конфигурации.
Отказ от модальности в любой серьезной конфигурации (существующей и использующей модальные окна) — дело непростое. В значительном количестве случаев будет недостаточно заменить один метод на другой — может потребоваться изменение значительной части интерфейса прикладного решения.
Каждый раз, перед тем как начать переделывать модальный диалог, стоит очень серьезно подумать — не проще ли будет избавиться от этого диалога совсем.
Помимо изменения самих диалогов (создание вызываемых процедур, изменение кода вызовов и тд.), отказ от модальности — это еще и существенный шаг в сторону асинхронной модели работы клиентского приложения, со всеми вытекающими отсюда последствиями. Подробнее об асинхронной модели клиентского приложения в отдельной статье.
Непосредственно при отказе от модальности очень поможет механизм рефакторинга о котором подробно написано в отдельной статье.
Соответствие синхронных методов асинхронным аналогам (на момент написания статьи) можно посмотреть тут.
Практические примеры
В качестве практических примеров рассмотрим основные приемы работы с блокирующими окнами.
В последних версиях, активно работающих в веб-клиенте и на мобильных приложениях, 1С начала агрессивно продвигать новый подход к модальности, к работе с модальными окнами и диалогами. На эту тему много и убедительно написано в методическом сопровождении, статьях на сайтах и в комментариях специалистов. Но не будем поддаваться, посмотрим критически на предлагаемые нам новшества. Причём рассуждать я хочу как типичный «одинэснег». Обойдусь без пересказа статей, копипаста Синтакс-помощника и раскрытия технических терминов, подразумевая, что читателю оно уже всё известно.
Многое, что можно было «спрятать» в платформе и сделать своими силами, просто перевалено на плечи разработчиков 1С. С больной головы на здоровую. То ли в 1С не захотели это сделать, то ли не успели (последнее заметно по целому ряду прецедентов, когда самоочевидные вещи «подтягивали» по ходу выпуска релизов, не успев сделать сразу).
Предложена идеология, резко увеличивающая объём кода, а значит, затрудняющая работу с ним. Обещанный рефакторинг касается лишь простейших случаев, что уже честно признано.
Во-первых, сила и убедительность многих статей в том, что там очень красиво и аккуратно перемешаны совершенно разные понятия – модальность окна и асинхронность выполнения кода. Под модальностью подразумевается невозможность переключения в другие окна, пока это окно держит фокус. Под асинхронностью – ветвление логики и хода выполнения действий, превращение одной цепочки действий как последовательности команд в две и более, выполняемые параллельно, в т.ч. без взаимных привязок, согласований и вообще без внимания друг к другу (аппаратные тонкости оставим вне рассмотрения).
Во-вторых, нам печально повествуют, что всплывающие окна, как нехорошее рекламное нечто, блокируются браузерами (т.е. требуют разрешения на включение) и вообще не поддерживаются мобильными устройствами, а значит, маст дай. Более того, авторы некоторых методических статей ненавязчиво намекают, что в будущем 1С намерена полностью отказаться от модальности, что это «генеральная линия партии», и хотя нам милостиво разрешено пока жить по-старинке, но будущее уже предрешено и в нём нет места для «Предупреждение(«Hello, World»)». Пугают, стало быть.
Теперь посмотрим, что нам предлагается – свойство, управляющее блокировкой интерфейса/окна. По сути, для нашего юзверя, то же самое. Нам в плюс, что поведение более управляемое, можно задавать в коде; нам в минус, что головной боли об этом чуть больше. Но пользователю, в общем, плевать, почему он не может, открыв окно «1», щёлкнуть по кнопке в окне «2». Внимание, вопрос – где же пресловутый отказ от модальности?
Всплывающие окна. Pop-up. Всякая бяка из интернета. Да-да, конечно, пусть даже браузер совсем их не понимает и не поддерживает, но как тогда 1С реализует эти «блокируемые» окна? И что мешало тихо и незаметно реализовать функцию «Вопрос» так же, как реализуется рисуемая нами форма, блокирующая весь интерфейс, по аналогичной концепции? Ничего ровным счётом. Как-то ведь фирма 1С планирует отрабатывать эту блокировку, так отрабатывали бы и модальные диалоги.
Невинно пострадала процедура «Предупреждение». Полный аналог команды alert, которая отнюдь не является всплывающим окном, она, тем не менее, попала под запрет. Хорошо хоть, описание оповещения необязательное. Мне могут возразить, что в планах 1С есть вывод туда форматированной строки и вообще неизвестно, может, это тоже маленькая отдельная формочка, а не alert. Но тогда см.выше, что мешает ей быть такой формочкой с блокировкой интерфейса, не делая мне головной боли? И что мешает для вывода форматированной строки применить «ПоказатьОповещениеПользователя» (к которой тоже есть претензия именно ввиду её совершеннейшей немодальности – помигало и исчезло, а юзверь мог и не заметить)?
Тем более ни при чём действия с выпадающим списком, в режиме списка и меню. Если 1С оставила такую штуку, как подменю любой вложенности, и в природе существуют поля ввода с выпадающими списками, то причём тут борьба с модальностью? Где в подменю и выпадающем списке модальность? Нигде, чистая произвольная навигация по предоставленным данным в рамках интерфейса. Есть ли разница между «ВыбратьИзМеню» и статичным подменю? Никакой. Тогда почему надо заставлять всех делать «ПоказатьВыборИзМеню» и перелопачивать ради этого и код, и логику?
Ладно, нам объяснили, что «ВыбратьЭлемент» это теперь очень плохо. Но тогда почему остались диалоговые методы различных объектов? Почему никто не посягнул на «ДиалогВыбораФайла.Выбрать»? Модальность же неимоверная! А это далеко не единственный пример. Почему не отказались от мини-диалогов, возникающих при нажатии на «педальку» поля ввода - например, от календаря или калькулятора, от выбора типа значения? Они ведь интерфейсно ровно то же, что выбор из списка или меню. Загадка!
Вернёмся к асинхронности исполнения. «Тупой одинэснег» внимательно читает методические статьи и видит, что теперь после вызова «Показать…» исполнение кода продолжается, а отдельная ветка уходит на обработку действий согласно описанию оповещения. Супер, можно разделить поток исполнения! Можно выполнить действие «а», в то время как «немодальное» окно будет пройдено пользователем и согласно ему выполнится действие «б». Асинхрон!
Не тут-то было. Простейшая проверка показывает, что асинхронность, заявленная идеологически, на практике отсутствует. Достаточно поставить бесконечный цикл после вызова «Показать…» и – здравствуй, перезапуск приложения. Асинхронностью я бы это не назвал ни в коем случае. Нижеприведённое также привело к зависанию:
Процедура НекаяКоманда ( Команда )
опоп =Новый ОписаниеОповещения ( "ЗавершениеНекойКоманды" , ЭтотОбъект ,);
ПоказатьПредупреждение ( опоп , "Hell, world!" );
Пока НекийКлюч Цикл
ОбработкаПрерыванияПользователя ();
КонецЦикла;
КонецПроцедуры
Процедура ЗавершениеНекойКоманды ( Параметр1 )
НекийКлюч =Ложь;
КонецПроцедуры
Более того, авторы статей аккуратно намекают, что после вызова «немодальных» диалогов вообще лучше бы прекратить исполнение кода и вообще выйти из процедуры/функции, т.е. ставить такой вызов последней строкой кода. На красивых картинках нам показывают, как переключается туда-сюда-обратно ход процесса, как передаётся управление, как надо работать со вложенными процедурами и т.д. Но вдумайтесь – где здесь асинхрон? Перед нами просто более запутанное, но всё такое же последовательное, плоское и однопоточное выполнение кода! Пресловутая «асинхронность» не чисто программная, а программно-интерфейсная силами платформы. Здесь нет ожидания успешности или неуспешности, нет их перехвата. Есть приостановка выполнения нашего кода на период «висения» некоего окна. И где разница с тем, что было до сих пор? Почему мы лишены возможности продолжить там же, в той же процедуре? Почему нам, на худой конец, не дали меток наподобие Goto, и обязательно теперь прыгать в другую процедуру? Напомню, второго потока по сути нет и не подразумевается!
Да и зачем нам в интерфейсах асинхронность вместо main flow? Ладно, тяжёлые серверные действия, уходящие фоновыми заданиями в настоящие асинхроны, но на клиенте (а описание оповещения живёт только на клиенте) таких задач пока нет и особо не предвидится. Подчеркну – именно применительно к взаимодействию с интерфейсом, а не к работе с данными, т.к. платформа отрисовывает и показывает всё за нас. Приведите мне пример, позволяющий убедить главбуха, отчего теперь код пишется втрое дольше!
Дочитавшие до этого места могут возразить, что, мол, интернеты-веяния времени, и вообще новомодные геопозиционирования и прочая. Насчёт интернета и веяний времени я комментировать не буду, т.к. версия встроенного в платформу браузера ниже всякой критики, свойство parentWindow не советовали к применению прям даже в СП, а уж какая мешанина вышла из его свойств/методов и свойств/методов Dociment в итоговом «Документ» я вообще молчу. Прогресс беспредельный, ага.
Что касается настоящей «интернетности». Да, хорошо, что объект «ОписаниеОповещения» уже напоминает известную в JavaScript возможность перекинуть процедуру как параметр и выполнить где-то в другом месте. Да, теперь мы можем вызвать процедуру из некоей формы, находясь в совсем другом месте, имея лишь оповещение, а значит, имея саму эту УФ, нужный контекст и тд. Но вот достучаться до команды так пока не получается – известно, что модуль общей команды это «чёрный ящик», и находящийся там код программно вызвать нельзя.
А главное, что нет настоящих Promise, хорошо известных в JS. Следующим логичным шагом было бы сделать нечто вроде:
ОбъектИлиМенеджер . ПроцедураИлиМетод ( Параметры ). ЕслиУспешно Тогда
ДействияПриУспешности ( Параметры );
ЕслиНеуспешно Тогда
ДействияПриНеуспешности ( Параметры );
ЕслиУспешностьНеясна Тогда
ДействияПриНеясности ( Параметры );
Конец
об1 =Новый Обещание ( ОписаниеОповщения1 , ОписаниеОповещения2 );
Но пока "обещаний" нам не обещают.
Логичной представляется также возможность динамического создания подписок на события любого характера (listeners), ну и наконец, господа из 1С, может быть, сделают перехват и обработку нажатия пользовательского прерывания, хотя бы исключительно на клиенте.
Итак, мы пока что имеем однопоточное, не-асинхронное (просто запутанное) выполнение кода, и якобы немодальные диалоги, чьё поведение ничем не отличается от модальных, а в ряде случаев вообще не модально по определению. Просто прибавилось хлопот.
В ряде мест этой замечательной статьи откровенно признано, что 1С и сами ещё не вполне представляют, какое решение будет эффективным, красивым и вообще «правильным» для многих случаев. И случаи эти частые, общеупотребительные, всем нам нужные. Более всего такие места статьи походят на «ну, мы сделали, а вы уж как-нибудь выкрутитесь». При том, что можно было реализовать то же самое, т.е. обойти проблемы работы в браузерах и мобильных устройствах, на уровне платформы, вообще не затрагивая уровень разработки конфигураций. Безо всякой псевдоасинхронности и ненужного умножения и усложнения кода.
Мы реализовали в конфигураторе некоторые функции рефакторинга, а также функции автоматического преобразования модальных методов и участков кода. Необходимость этих инструментов объясняется довольно просто.
Код прикладных решений должен быть понятным. Тогда их легко поддерживать и модифицировать. Но в процессе разработки не всегда можно уследить за этим. Особенно если в модификации прикладного решения участвует большая команда разработчиков. Поэтому "хорошим тоном" считается периодическое "наведение порядка" в имеющемся коде, с целью облегчения его понимания. Этот процесс называют рефакторингом. Он не меняет внешнее поведение прикладного решения.
Рефакторинг, безусловно, полезен сам по себе, но иногда он бывает необходим. Например, перед изменением существующей функциональности или перед реализацией новых функций. То есть сначала нужно сделать имеющийся код понятным, а уже затем его модифицировать.
Задача перевода существующего прикладного решения в режим работы без использования модальности как раз является одной из задач такого класса. Поэтому в конфигураторе мы объединили в одном меню функции рефакторинга и инструменты, позволяющие преобразовывать модальные фрагменты кода:
Функции рефакторинга
Функции рефакторинга позволяют сделать код более понятным и удобным для восприятия. Например, вы можете оформить часть кода в виде отдельной процедуры или функции (команда Выделить фрагмент):
Вы можете сформировать заготовку для описания назначения и параметров процедуры или функции (команда Создать описание процедуры):
А ещё вы можете изменить имя локальной или экспортной переменной, процедуры, функции во всех местах её фактического использования (команда Переименовать):
Кроме этого вы можете просто найти все места, где используется некоторая переменная, функция или процедура. С помощью команды Найти использование:
Отказ от модальности
В общем виде задача отказа от модальности заключается в том, чтобы заменить модальные методы их асинхронными аналогами. Мы уже рассказывали об этом в начале года.
Теперь в простых, и в не очень простых, случаях вы можете сделать это автоматически (команда Модальные вызовы - Преобразовать модальный вызов):
Если вы преобразуете модальную функцию, то платформа добавит инициализацию переменной, в которую возвращается значение функции. Потому что в общем случае эта переменная может использоваться далее в той же процедуре:
Другой случай. Например, фрагмент, который вы преобразуете, содержит две ветки исполнения, одна из которых включает в себя модальный код, а другая нет. Платформа преобразует такой фрагмент в две процедуры:
Однако если вы преобразуете код, который находится, например, в модуле управляемого приложения, то полностью автоматическое преобразование вам выполнить не удастся:
Дело в том, что у глобального контекста нет свойства, позволяющего сослаться на него самого (ЭтотОбъект). А значит процедуру, обрабатывающую оповещение, нельзя разместить тут же, в модуле управляемого приложения. Её можно разместить, например, в каком-нибудь общем модуле. Эти действия вам нужно будет выполнить вручную:
В более сложных случаях автоматическое преобразование также возможно с помощью одного или нескольких инструментов.
Например, модальный вызов располагается внутри вызываемой процедуры:
В этом случае модальным будет не только вызов Предупреждение(), но и вызов Цепочка1(). И если для функции Предупреждение() у вас есть во встроенном языке асинхронный аналог ПоказатьПредупреждение(), то для вызова Цепочка1() асинхронный аналог вам нужно придумать самостоятельно. Для этого можно использовать команду Модальные вызовы - Преобразовать в асинхронную процедуру:
А после этого Предупреждение() преобразовать с помощью Модальные вызовы - Преобразовать модальный вызов:
В данном случае последовательность этих двух операций показана лишь для наглядности. На самом деле в этом примере платформа сразу же преобразовала бы Предупреждение() в конечный вариант, известив вас "в процессе" о том, что процедура так же будет преобразована к асинхронному виду:
Однако в сложных фрагментах кода, при большой вложенности, такое автоматическое преобразование может не работать. Тогда мы рекомендуем вручную выделять в отдельные процедуры те фрагменты, которые содержат модальность. А затем уже преобразовывать модальные процедуры и модальные методы.
Например, если в исходной процедуре ниже вы попытаетесь преобразовать Предупреждение(), у вас ничего не получится. Так как вложенность условий довольно глубока. Поэтому сначала нужно выделить в отдельную процедуру законченный фрагмент, содержащий модальный вызов. В данном случае вы можете взять целиком внутреннее условие.
А после этого можете уже автоматически преобразовать Предупреждение(). И, естественно, платформа известит вас о том, что процедуру она также преобразует к асинхронному виду.
А вот если пример выше будет содержать Возврат после Предупреждение(), то выделить этот фрагмент в обычную процедуру вам не удастся. В этом случае нужно сразу выделять его в асинхронную процедуру с помощью команды Модальные вызовы - Выделить в асинхронную процедуру. А затем уже преобразовывать модальное Предупреждение().
Кроме перечисленных команд, позволяющих выполнять «одиночные» преобразования, мы сделали несколько инструментов для автоматической обработки модулей целиком и даже для обработки всей конфигурации. Эти инструменты по своим возможностям не идентичны тому, что умеют «одиночные» преобразования. Они обеспечивают работу в менее сложных случаях.
Например, с помощью команды Найти модальные вызовы модуля вы можете получить список всех строк и операторов модуля, которые требуют преобразования:
Вы можете даже автоматически Преобразовать модальные вызовы модуля. В этом случае платформа выполнит преобразования, для которых не требуется ваше вмешательство, и выведет итоговую информацию. А в окне результатов поиска вы увидите строки, которые платформа не смогла преобразовать автоматически и причину неудачи.
Проанализировать и преобразовать модальные вызовы во всей конфигурации целиком вы можете с помощью команды Конфигурация - Рефакторинг - Анализ модальных вызовов конфигурации:
В этом случае перед началом вы можете выбрать только анализ или сразу же и преобразование, а также можете задать некоторые параметры этих действий.
По окончании анализа, например, вы увидите сводную информацию, а также более подробную по каждому из модальных вызовов, имеющихся в конфигурации:
Не ответив на запрос, появившийся в подобном окне, невозможно дальше продолжать работать во всей программе. Она полностью блокирует интерфейс, и в результате работа других окон также перекрывается. Более того, исполнение программных кодов аналогичным образом будет остановлено как раз в той точке, где имел место вызов диалога. И такая нештатная ситуация продолжится вплоть до завершения действия с окном, программа будет находиться в режиме ожидания этого.
Устранение ошибки «Использование в данном режиме модальных окон запрещено» в системе 1С
Эта разновидность ошибки стала возникать после того, как 1С была полностью переведена на новый интерфейс, относящийся к платформе 1С 8.3 – «Такси». Связано это с тем, что разработчиками в ней была включена возможность работы с окнами, однако, она была реализована без режима модальности.
После того, как в режиме «Конфигуратор» открывается информационная база системы, нажимаем правую кнопку мышки, а затем выбираем команду «Свойства». Это позволяет увидеть все свойства конфигурации установленной на компьютере системы. После прокрутки линейки вниз, перед пользователем появляется раздел «Совместимость», в пределах поля которого и расположен тот параметр режима, что его в первую очередь интересует. Кроме того, там перечисляются и возможные варианты в плане выбора: их в общей сложности три, и это может быть «Использовать», «Использовать с предупреждением», либо же «Не использовать».
Затем, в обязательном порядке потребуется сохранить произведенные в конфигурации изменения, после чего и обновить их. Та ошибка, о которой шла речь ранее, возникает, если установлена отметка о недопустимости использования режима модальности. Эта возможность возникла, начиная с платформы версии 8.3.3.721, релиз которой состоялся еще в сентябре 2013-го года. Другими словами, те пользователи системы, которые до настоящего момента по каким-либо причинам все еще продолжают работать с более старыми версиями платформы, могут не отказываться от использования модальности. Что же касается других версий, что бы устранить всякую возможность появления окна с ошибкой, допускается простая установка посредством использования вкладки «Использовать».
Модальность и отказ от ее использования
Оказывая поддержку нынешним общемировым тенденциям и четко следуя им, разработчики программы 1С стремятся сделать ее пользовательский интерфейс максимально приближенным к веб-образцам с последующим приведением к единому стандарту. Благодаря этому, пользователи уже в не слишком далеком будущем получат возможность работать с привычным им внешним интерфейсом лишь в одном окне.
Другими словами, данное новшество совершенно освобождает пользователей от неприятной и довольно утомительной необходимости настраивать браузер дополнительно. Кроме этого, оно стабилизирует работу интернет-клиента, одновременно достаточно существенно повышая его производительность. И наконец, поскольку сейчас отсутствует какая-либо необходимость открытия всплывающих окон, возможно использование на любом устройстве соответственно и любой конфигурации, в которую ранее были внесены такого рода изменения.
Читайте также: