Как вернуть выбранное значение в поле ввода после отключения стандартной обработки выбора в 1С?

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

При разработке в 1С:Предприятии 8.3, особенно при работе с управляемыми формами, иногда возникает необходимость полностью переопределить логику выбора значения для реквизита формы. Это часто требуется, когда стандартный механизм выбора не предоставляет нужной гибкости, например, для применения сложных отборов или открытия специализированных форм. Мы подробно рассмотрим ситуацию, когда вы отключаете стандартную обработку выбора (устанавливая СтандартнаяОбработка = Ложь), но сталкиваетесь с проблемой: выбранное значение не возвращается автоматически в поле ввода. Разберем, как самостоятельно реализовать этот механизм.

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

Понимание механизма обработки выбора в 1С

Когда вы устанавливаете СтандартнаяОбработка = Ложь в обработчике события ОбработкаВыбора, вы фактически сообщаете платформе 1С: "Я сам позабочусь о выборе значения для этого поля". Это означает, что:

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

Таким образом, наша задача сводится к двум основным шагам:

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

Способы возврата выбранного значения из формы выбора

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

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

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

Как реализовать в дочерней форме:

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


// В форме выбора, например, в обработчике команды "Выбрать"
&НаСервере
Процедура КомандаВыбратьНаСервере()
    // Получаем выбранный элемент из таблицы формы или другого источника
    // Например, если данные формы представлены таблицей с именем "Список"
    ВыбранныйЭлемент = Элементы.Список.ТекущиеДанные; 

    // Проверяем, что что-то выбрано
    Если ВыбранныйЭлемент <> Неопределено Тогда
        // Устанавливаем ВыбранноеЗначение для текущей формы
        ЭтаФорма.ВыбранноеЗначение = ВыбранныйЭлемент.Ссылка; // Или другое поле, которое нужно вернуть
        ЭтаФорма.Закрыть(); // Закрываем форму после выбора
    Иначе
        ПоказатьПредупреждение(Неопределено, "Выберите элемент!");
    КонецЕсли;
КонецПроцедуры

// Также можно обрабатывать двойной клик, если таблица отображает выбор
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    Если Элемент.ТекущиеДанные <> Неопределено Тогда
        Если Элемент.ТекущиеДанные.Ссылка <> Неопределено Тогда
            ЭтаФорма.ВыбранноеЗначение = Элемент.ТекущиеДанные.Ссылка;
            ЭтаФорма.Закрыть();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Как получить значение в родительской форме:

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


// В обработчике события ОбработкаВыбора реквизита в родительской форме
Процедура МойРеквизитОбработкаВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь; // Отключаем стандартную обработку

    // Создаем параметры для открытия формы выбора (например, отборы)
    ПараметрыОткрытия = Новый Структура("Отбор", Новый Структура("Отдел", МойОтдел)); 

    // Открываем форму выбора модально
    ФормаВыбора = ОткрытьФормуМодально("Справочник.МойСправочник.ФормаВыбора", ПараметрыОткрытия);

    // После закрытия формы, проверяем, было ли что-то выбрано
    Если ФормаВыбора <> Неопределено И ФормаВыбора.ВыбранноеЗначение <> Неопределено Тогда
        // Присваиваем выбранное значение реквизиту нашей формы
        ЭтотОбъект.МойРеквизит = ФормаВыбора.ВыбранноеЗначение;
        // Можно также обновить элемент управления напрямую:
        // Элементы.МойРеквизит.Значение = ФормаВыбора.ВыбранноеЗначение;
    КонецЕсли;
КонецПроцедуры

Важный момент: Если реквизит МойРеквизит имеет составной тип данных, убедитесь, что тип ФормаВыбора.ВыбранноеЗначение совместим с одним из разрешенных типов реквизита.

2. Использование механизма оповещения (предпочтительный для асинхронного открытия форм)

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

Как реализовать в родительской форме:

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


// В обработчике события ОбработкаВыбора реквизита в родительской форме
Процедура МойРеквизитОбработкаВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь; // Отключаем стандартную обработку

    // Создаем параметры для открытия формы выбора (например, отборы)
    ПараметрыОткрытия = Новый Структура("Отбор", Новый Структура("Отдел", МойОтдел)); 

    // Создаем описание оповещения. 
    // "ПослеВыбораЗначения" - имя процедуры, которая будет вызвана
    // "ЭтотОбъект" - контекст, в котором будет вызвана процедура (обычно сама форма)
    ОповещениеОВыборе = Новый ОписаниеОповещения("ПослеВыбораЗначения", ЭтотОбъект);

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

// Процедура-обработчик оповещения, которая будет вызвана после закрытия формы выбора
Процедура ПослеВыбораЗначения(ВыбранноеЗначение, ДополнительныеПараметры) Экспорт
    // ДополнительныеПараметры могут содержать любые данные, переданные в ОписаниеОповещения.
    // В данном примере они не используются.

    Если ВыбранноеЗначение <> Неопределено Тогда
        // Присваиваем выбранное значение реквизиту нашей формы
        ЭтотОбъект.МойРеквизит = ВыбранноеЗначение;
        // Можно также обновить элемент управления напрямую:
        // Элементы.МойРеквизит.Значение = ВыбранноеЗначение;
    КонецЕсли;
КонецПроцедуры

Как реализовать в дочерней форме:

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


// В форме выбора, например, в обработчике команды "Выбрать"
&НаСервере
Процедура КомандаВыбратьНаСервере()
    // Получаем выбранный элемент
    ВыбранныйЭлемент = Элементы.Список.ТекущиеДанные; 

    Если ВыбранныйЭлемент <> Неопределено Тогда
        ЭтаФорма.ОповеститьОВыборе(ВыбранныйЭлемент.Ссылка); // Передаем выбранное значение
        ЭтаФорма.Закрыть();
    Иначе
        ПоказатьПредупреждение(Неопределено, "Выберите элемент!");
    КонецЕсли;
КонецПроцедуры

// Также можно обрабатывать двойной клик
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    Если Элемент.ТекущиеДанные <> Неопределено Тогда
        Если Элемент.ТекущиеДанные.Ссылка <> Неопределено Тогда
            ЭтаФорма.ОповеститьОВыборе(Элемент.ТекущиеДанные.Ссылка);
            ЭтаФорма.Закрыть();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

3. Передача объекта-владельца или ссылки на элемент управления

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

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

Как реализовать в родительской форме:


// В обработчике события ОбработкаВыбора реквизита в родительской форме
Процедура МойРеквизитОбработкаВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;

    ПараметрыОткрытия = Новый Структура();
    ПараметрыОткрытия.Вставить("РодительскаяФорма", ЭтаФорма); // Передаем саму родительскую форму
    ПараметрыОткрытия.Вставить("ИмяРеквизитаДляЗаполнения", "МойРеквизит"); // Или имя элемента

    ОткрытьФорму("Справочник.МойСправочник.ФормаВыбора", ПараметрыОткрытия);
КонецПроцедуры

Как реализовать в дочерней форме:


// В форме выбора, например, в обработчике команды "Выбрать"
&НаСервере
Процедура КомандаВыбратьНаСервере()
    // Получаем выбранный элемент
    ВыбранныйЭлемент = Элементы.Список.ТекущиеДанные; 

    Если ВыбранныйЭлемент <> Неопределено И ЭтаФорма.Параметры.Свойство("РодительскаяФорма") Тогда
        РодительскаяФорма = ЭтаФорма.Параметры.РодительскаяФорма;
        ИмяРеквизита = ЭтаФорма.Параметры.ИмяРеквизитаДляЗаполнения;
        // Присваиваем значение напрямую через ссылку на родительскую форму
        РодительскаяФорма[ИмяРеквизита] = ВыбранныйЭлемент.Ссылка;
        ЭтаФорма.Закрыть();
    КонецЕсли;
КонецПроцедуры

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

Заключительные шаги: присвоение значения реквизиту формы

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

  1. Через свойство реквизита формы: Это наиболее прямой и рекомендуемый способ, если реквизит формы непосредственно связан с элементом управления.

    ЭтотОбъект.МойРеквизит = ВыбранноеЗначение;

    Этот способ автоматически обновит связанный элемент управления на форме.

  2. Через элемент управления формы: Вы можете напрямую обратиться к элементу управления на форме и установить его значение.

    Элементы.МойРеквизит.Значение = ВыбранноеЗначение;

    Здесь МойРеквизит – это имя элемента формы, которое обычно совпадает с именем реквизита.

Особое внимание уделите составным типам данных. Если ваш реквизит МойРеквизит имеет составной тип данных (например, может быть ссылкой на Справочник.Номенклатура или Справочник.Контрагенты), убедитесь, что возвращаемое ВыбранноеЗначение соответствует одному из разрешенных типов. Платформа 1С обычно хорошо справляется с автоматическим преобразованием, если типы совместимы, но если вы попытаетесь присвоить, например, ссылку на документ в поле, которое может содержать только ссылку на справочник, возникнет ошибка или значение не будет установлено.

Полный пример реализации с использованием оповещения

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


// В модуле формы, для реквизита "МойРеквизит"
// Реквизит МойРеквизит, тип: Произвольный (или конкретный составной тип, например, СправочникСсылка.Отделы, СправочникСсылка.Сотрудники)

// --- Родительская форма ---

&НаКлиенте
Процедура МойРеквизитОбработкаВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь; // Отключаем стандартную обработку, чтобы не открывалась стандартная форма выбора

    // Формируем параметры отбора для нашей формы выбора
    // Например, мы хотим показывать только отделы из определенного филиала
    ПараметрыОтбора = Новый Структура("Филиал", МойФилиал); 

    // Дополнительные параметры, которые могут быть полезны в процедуре-обработчике оповещения
    // Например, можно передать имя элемента, который инициировал выбор, если обработчик общий для нескольких полей
    ДополнительныеПараметрыОповещения = Новый Структура("ИмяЭлемента", Элемент.Имя);

    // Создаем описание оповещения. 
    // Процедура "ПослеВыбораЗначенияДляРеквизита" будет вызвана в контексте "ЭтотОбъект" (модуль текущей формы)
    // после закрытия формы выбора.
    ОповещениеОВыборе = Новый ОписаниеОповещения(
        "ПослеВыбораЗначенияДляРеквизита", 
        ЭтотОбъект, 
        ДополнительныеПараметрыОповещения
    );

    // Открываем нашу специализированную форму выбора.
    // Предположим, это форма списка справочника "Отделы", но с нашей кастомизацией.
    ОткрытьФорму(
        "Справочник.Отделы.ФормаВыбора", // Имя формы, которую мы хотим открыть
        ПараметрыОтбора,                // Параметры для инициализации формы (например, отборы)
        Элемент,                        // Владелец формы. Можно Неопределено.
        ,                               // Уникальность. Можно Неопределено.
        ,                               // Окно. Можно Неопределено.
        ,                               // Режим открытия. Можно Неопределено.
        ОповещениеОВыборе               // Наше описание оповещения для получения результата
    );
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораЗначенияДляРеквизита(ВыбранноеЗначение, ДополнительныеПараметры) Экспорт
    // Эта процедура будет вызвана после того, как форма выбора будет закрыта и в ней будет 
    // вызван метод ОповеститьОВыборе().

    // Проверяем, что что-то было выбрано
    Если ВыбранноеЗначение <> Неопределено Тогда
        // Проверяем, из какого элемента пришло оповещение, если обработчик универсален
        Если ДополнительныеПараметры.Свойство("ИмяЭлемента") И ДополнительныеПараметры.ИмяЭлемента = "МойРеквизит" Тогда
            // Присваиваем выбранное значение реквизиту нашей формы.
            // Платформа автоматически обновит связанный элемент управления.
            ЭтотОбъект.МойРеквизит = ВыбранноеЗначение;

            // Если реквизит составной, и нужно выбрать конкретный тип, 
            // например, если ВыбранноеЗначение это СправочникСсылка.Отделы,
            // но реквизит может быть и СправочникСсылка.Сотрудники.
            // Платформа сама определит нужный тип при присвоении.
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

// --- Форма выбора (Справочник.Отделы.ФормаВыбора, которую мы открываем) ---

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

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

&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    // Обработка двойного клика для быстрого выбора
    Если Элементы.Список.ТекущиеДанные <> Неопределено Тогда
        ВыбраннаяСсылка = Элементы.Список.ТекущиеДанные.Ссылка;
        Если ВыбраннаяСсылка <> Неопределено Тогда
            ЭтаФорма.ОповеститьОВыборе(ВыбраннаяСсылка);
            ЭтаФорма.Закрыть();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

Важность правильного выбора типа данных

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

Перед присвоением убедитесь, что:

  1. Выбранное значение является ссылкой, а не просто строкой или числом, если реквизит требует ссылку.
  2. Тип ссылки (например, СправочникСсылка.Отделы) присутствует в списке разрешенных типов для вашего составного реквизита.

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

Заключение

Реализация собственной логики выбора в 1С:Предприятие 8.3 с отключением стандартной обработки требует от нас полной ответственности за весь процесс: от открытия формы выбора до возврата и установки значения в реквизит. Мы рассмотрели различные подходы, такие как модальное открытие с использованием ВыбранноеЗначение и асинхронный механизм оповещения через ОписаниеОповещения. Последний является наиболее гибким и предпочтительным для современных управляемых форм.

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

← На главную