Обычный пульт получает список по имени, основной список, формы выбора товара/группы и формы нового товара/группы. Все окна принадлежат пульту; просмотр, новый UUID, повтор своего списка и закрытие только собственных окон проверяются явно.
Где и как запускать
Полный модуль ОБЫЧНОЙ формы Пульт собственной обработки. Только толстый клиент, обычное приложение; отдельные модули ниже. Не выполнялся.
Подготовка
Создайте НОВУЮ пустую файловую базу 8.5.1.1343 с именем конфигурации УчебныеВыборкиКаталога85, совместимость НеИспользовать. Основной режим запуска ОбычноеПриложение. Запускайте толстым клиентом в обычном приложении; тонкий/веб-клиент и управляемые формы для этих шести методов не подходят. Здесь UI не запускался: runtimeVerifiedScenarios=0.
Единственный справочник УчебныеТовары: иерархия групп и элементов, владельцев и предопределенных данных нет, Код Строка(10), автонумерация выключена, контроль уникальности включён, Наименование(100), единственный Артикул Строка(20), для групп и элементов, Индексировать. Остальные объекты хранения, подписки, задания, разделители и расширения отсутствуют; справочник пуст.
УчебныеТовары → Формы: создайте пять ОБЫЧНЫХ форм мастером соответствующего назначения: ФормаСписка, ФормаВыбора, ФормаВыбораГруппы, ФормаЭлемента, ФормаГруппы. Назначьте их основными для списка, выбора элемента, выбора группы, элемента и группы соответственно. Не оставляйте выбор основной формы на автоопределении.
В ФормаЭлемента и ФормаГруппы проверьте основной реквизит СправочникОбъект типа СправочникОбъект.УчебныеТовары, созданный мастером. На форме только поля Код, Наименование, Артикул и Родитель. В обеих формах вставьте полный отдельный модуль проверки собственного нового объекта ниже. Модули объекта и менеджера справочника пусты.
Формы списка/выбора содержат только табличное поле своего справочника с колонками Код и Наименование. Во всех пяти учебных формах не добавляйте команды создания, редактирования, записи, удаления или выбора, пользовательские обработчики и автоматические действия. Это пульт просмотра назначения форм, не пример ввода/сохранения товара или возврата выбора.
Создайте неглобальный общий модуль УчебныйКаталог85: Сервер=Да, Вызов сервера=Да, клиентские флаги=Нет, привилегированный режим=Нет. Вставьте полный отдельный модуль защиты стенда ниже; в этом уроке он не содержит подготовки/записи товаров.
Создайте обработку УчебныеОкнаКаталога85 с обычной основной формой Пульт и восемью кнопками: СписокПоИмени, ОсновнойСписок, ВыборТовара, ВыборГруппы, НовыйТовар, НоваяГруппа, ПовторитьПоИмени, ЗакрытьСвоиОкна. Назначьте одноимённые действия, события ПриОткрытии и ПередЗакрытием. Вставьте полный основной модуль. Обновите конфигурацию базы, выполните F7 и вручную сверяйте назначения основных форм.
Не используйте рабочую конфигурацию или её копию: ТолькоПросмотр — свойство UI, не права доступа и не защита от неизвестных обработчиков записи. Код не вызывает Записать и не заполняет объект; формы новых объектов остаются новыми и незаписанными. Здесь не было запуска в 1С.
Перем СвоиОкна;
Перем СвойСписокПоИмени;
Процедура ПриОткрытии()
УчебныйКаталог85.ПроверитьСвойСтенд();
СвоиОкна = Новый Массив;
СвойСписокПоИмени = Неопределено;
КонецПроцедуры
Процедура СписокПоИмени(Кнопка)
УчебныйКаталог85.ПроверитьСвойСтенд();
Ключ = Новый УникальныйИдентификатор;
Окно = Справочники.УчебныеТовары.ПолучитьФорму("ФормаСписка", ЭтаФорма, Ключ);
ПоказатьСвоеОкно(Окно, Ключ, "Список по явному имени", Неопределено);
СвойСписокПоИмени = Окно;
КонецПроцедуры
Процедура ОсновнойСписок(Кнопка)
УчебныйКаталог85.ПроверитьСвойСтенд();
Ключ = Новый УникальныйИдентификатор;
Окно = Справочники.УчебныеТовары.ПолучитьФормуСписка(, ЭтаФорма, Ключ);
ПоказатьСвоеОкно(Окно, Ключ, "Основная форма списка", Неопределено);
КонецПроцедуры
Процедура ВыборТовара(Кнопка)
УчебныйКаталог85.ПроверитьСвойСтенд();
Ключ = Новый УникальныйИдентификатор;
Окно = Справочники.УчебныеТовары.ПолучитьФормуВыбора(, ЭтаФорма, Ключ);
ПоказатьСвоеОкно(Окно, Ключ, "Форма выбора товара: просмотр", Неопределено);
КонецПроцедуры
Процедура ВыборГруппы(Кнопка)
УчебныйКаталог85.ПроверитьСвойСтенд();
Ключ = Новый УникальныйИдентификатор;
Окно = Справочники.УчебныеТовары.ПолучитьФормуВыбораГруппы(, ЭтаФорма, Ключ);
ПоказатьСвоеОкно(Окно, Ключ, "Форма выбора группы: просмотр", Неопределено);
КонецПроцедуры
Процедура НовыйТовар(Кнопка)
УчебныйКаталог85.ПроверитьСвойСтенд();
Ключ = Новый УникальныйИдентификатор;
Окно = Справочники.УчебныеТовары.ПолучитьФормуНовогоЭлемента(, ЭтаФорма, Ключ);
ПоказатьСвоеОкно(Окно, Ключ, "Новый товар в памяти: без записи", Ложь);
КонецПроцедуры
Процедура НоваяГруппа(Кнопка)
УчебныйКаталог85.ПроверитьСвойСтенд();
Ключ = Новый УникальныйИдентификатор;
Окно = Справочники.УчебныеТовары.ПолучитьФормуНовойГруппы(, ЭтаФорма, Ключ);
ПоказатьСвоеОкно(Окно, Ключ, "Новая группа в памяти: без записи", Истина);
КонецПроцедуры
Процедура ПоказатьСвоеОкно(Окно, Ключ, Заголовок, ОжидаемаяГруппа)
Если Окно = Неопределено Тогда
ВызватьИсключение "Собственная форма не создана; сверяйте подготовку и отказ создания";
КонецЕсли;
Если ТипЗнч(Окно) <> Тип("Форма") Тогда
ВызватьИсключение "Нужна обычная форма толстого клиента";
КонецЕсли;
Если Окно.Открыта() Или Окно.КлючУникальности <> Ключ Или Окно.ВладелецФормы <> ЭтаФорма.ЭтаФорма Тогда
ВызватьИсключение "Не изменяем чужое или уже открытое окно";
КонецЕсли;
Окно.ТолькоПросмотр = Истина;
Окно.АвтоЗаголовок = Ложь;
Окно.Заголовок = Заголовок;
Окно.ЗакрыватьПриЗакрытииВладельца = Истина;
Если ОжидаемаяГруппа <> Неопределено Тогда
Если Не Окно.ПроверитьСвоеСоздание(ОжидаемаяГруппа) Тогда
ВызватьИсключение "Своя форма не подтвердила новый незаписанный объект";
КонецЕсли;
КонецЕсли;
СвоиОкна.Добавить(Окно);
Попытка
Окно.Открыть();
Если Не Окно.Открыта() Или Не Окно.ТолькоПросмотр Тогда
ВызватьИсключение "Своя форма не открылась в режиме просмотра";
КонецЕсли;
Исключение
Если Окно.Открыта() Тогда
Окно.Закрыть();
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Процедура ПовторитьПоИмени(Кнопка)
Если СвойСписокПоИмени = Неопределено Тогда
Сообщить("Сначала откройте свой список кнопкой СписокПоИмени");
Возврат;
КонецЕсли;
Если Не СвойСписокПоИмени.Открыта() Тогда
Сообщить("Свое окно уже закрыто; создайте новый опыт кнопкой СписокПоИмени");
Возврат;
КонецЕсли;
УчебныйКаталог85.ПроверитьСвойСтенд();
Повторное = Справочники.УчебныеТовары.ПолучитьФорму("ФормаСписка", ЭтаФорма, СвойСписокПоИмени.КлючУникальности);
Если Повторное <> СвойСписокПоИмени Тогда
ВызватьИсключение "Совпадающие имя, владелец и ключ должны вернуть свое открытое окно";
КонецЕсли;
Сообщить("Повторный вызов вернул именно свой уже открытый список");
КонецПроцедуры
Процедура ЗакрытьСвоиОкна(Кнопка)
ЗакрытьСозданныеОкна();
КонецПроцедуры
Процедура ЗакрытьСозданныеОкна()
Если СвоиОкна = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого Окно Из СвоиОкна Цикл
Если Окно.Открыта() Тогда
Окно.Закрыть();
Если Окно.Открыта() Тогда
ВызватьИсключение "Собственное окно отказалось закрываться";
КонецЕсли;
КонецЕсли;
КонецЦикла;
СвоиОкна.Очистить();
СвойСписокПоИмени = Неопределено;
КонецПроцедуры
Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
ЗакрытьСозданныеОкна();
КонецПроцедурыУчебныеТовары.ФормаЭлемента/ФормаГруппы
УчебныеВыборкиКаталога85 → Справочники → УчебныеТовары → Формы → ФормаЭлемента и ФормаГруппы → Модуль каждой формы
Один и тот же полный модуль вставьте отдельно в обе подготовленные обычные объектные формы. Не выполнялся.
Функция ПроверитьСвоеСоздание(ОжидаемаяГруппа) Экспорт
Если Не ЭтаФорма.ТолькоПросмотр Тогда
ВызватьИсключение "Своя учебная форма должна открываться только для просмотра";
КонецЕсли;
Если Не СправочникОбъект.ЭтоНовый() Или Не СправочникОбъект.Ссылка.Пустая()
Или СправочникОбъект.ЭтоГруппа <> ОжидаемаяГруппа Тогда
ВызватьИсключение "Нужен свой новый незаписанный элемент или группа ожидаемого вида";
КонецЕсли;
Возврат Истина;
КонецФункцииУчебныйКаталог85.ПроверкаСтенда
УчебныеВыборкиКаталога85 → Общие → Общие модули → УчебныйКаталог85
Полный серверный общий модуль, вызов сервера разрешён; ни одной записи в базу. Не выполнялся.
Процедура ПроверитьСвойСтенд() Экспорт
Если Метаданные.Справочники.Количество() <> 1 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Каталог = Метаданные.Справочники[0];
Если Каталог.Имя <> "УчебныеТовары" Или Не Каталог.Иерархический
Или Каталог.Реквизиты.Количество() <> 1 Или Каталог.Реквизиты.Найти("Артикул") = Неопределено Тогда
ВызватьИсключение "Нужен собственный иерархический справочник с единственным реквизитом Артикул";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедурыРазбор по шагам
ПолучитьФорму("ФормаСписка") использует явное подготовленное имя. ПолучитьФормуСписка с пропущенным первым аргументом использует назначенную основную форму списка; второй и третий аргументы всё равно владелец и ключ.
ПолучитьФормуВыбора и ПолучитьФормуВыбораГруппы используют разные основные назначения. Сейчас показываем их только для просмотра; справочник пуст, значения пользователю не возвращаются.
ПолучитьФормуНовогоЭлемента и ПолучитьФормуНовойГруппы получают новые объекты, не формы существующей ссылки. Собственный экспортный метод дочерней формы проверяет ЭтоНовый, пустую ссылку и ЭтоГруппа=Ложь/Истина до открытия.
Каждый новый опыт имеет UUID. Перед любым изменением свойств проверяем тип Форма, отсутствие отказа создания, закрытое состояние, переданный ключ и владельца — именно этот Пульт. Чужие и открытые окна не перенастраиваются.
ТолькоПросмотр устанавливается перед Открыть; АвтоЗаголовок выключен, поэтому проверяемое название задаётся явно. Это делает назначение окна читаемым, не подменяет основной реквизит и не записывает его.
ПовторитьПоИмени работает только со своим запомненным открытым списком. Те же имя, владелец и ключ должны вернуть тот же экземпляр; новый UUID у кнопки СписокПоИмени создаёт отдельный опыт.
СвоиОкна содержит только полученные самим пультом экземпляры. ЗакрытьСозданныеОкна закрывает только их и проверяет отказ закрытия, после чего очищает собственный массив. ПередЗакрытием повторяет эту уборку; глобального закрытия окон нет.
Как проверить результат
При будущем ручном тесте откройте шесть видов окон по одной кнопке. Списки пусты; у двух новых объектных форм поля недоступны для изменения, экспортная проверка подтверждает новый элемент и новую группу без записи.
СписокПоИмени → ПовторитьПоИмени: появляется сообщение о том же экземпляре, без второго окна. Ещё раз СписокПоИмени: новый UUID создаёт другое собственное окно.
Закройте одно дочернее окно крестиком, затем ЗакрытьСвоиОкна. Закрытое пропускается, остальные собственные закрываются. Окна другого пульта не должны закрыться.
Закройте Пульт с оставшимися дочерними окнами: событие ПередЗакрытием убирает свои экземпляры. Затем проверьте учебный справочник — записанных товаров/групп нет.
Проверка отказа: в копии основной формы нового товара уберите основной реквизит или экспортную функцию. F7 либо вызов проверки должны сообщить ошибку; не заменяйте проверку константой Истина ради открытия.
Ожидаемый результат
Подготовлены собственный пульт, пять обычных форм и проверки нового объекта, владельца, ключа, повторного получения и уборки собственных окон. runtimeVerifiedScenarios=0.
На что обратить внимание
Обычная Форма и УправляемаяФорма — разные типы. Не заменяйте толстоклиентские методы универсальным ОткрытьФорму без пересмотра параметров и контекста.
ТолькоПросмотр не является системой прав и не запрещает произвольному коду выполнить Записать. Поэтому модули и команды собственного стенда заданы явно.
Названия форм и основного реквизита здесь реальные, но только после указанного создания. В типовой конфигурации они могут быть другими.
Просмотр форм выбора не означает успешный подбор элемента. Передача выбранного значения и уведомления владельца разобраны в отдельном уроке.
Платформа может сохранять параметры окон в пользовательском профиле. Уникальные собственные UUID не являются очисткой этого профиля; чужие настройки не удаляются.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.