Как исправить двойное открытие формы выбора в 1С и настроить программный отбор в динамических таблицах?

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

В разработке на платформе 1С:Предприятие 8.3 (особенно в конфигурациях со сложным интерфейсом, таких как «1С:Управление холдингом», где активно используются динамические «МегаТаблицы» или «КроссТаблицы») программисты часто сталкиваются с нестандартным поведением элементов формы. Типичный сценарий: при попытке переопределить стандартный выбор значения в поле ввода и открыть собственную форму с отбором, стандартная форма выбора всё равно продолжает открываться. В результате пользователь видит перед собой два окна выбора подряд, либо кастомная форма выбора игнорируется платформой.

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

Причина №1: Несоответствие сигнатуры обработчика (главный виновник проблемы)

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


Элементы["КроссТаблица_ИзмерениеСтрока_Организация"].УстановитьДействие("НачалоВыбора", "ОУ_КроссТаблицаОрганизацияНачалоВыбора");

На клиенте объявляется сама процедура-обработчик:


&НаКлиенте
Процедура ОУ_КроссТаблицаОрганизацияНачалоВыбора(Элемент, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    // Здесь открывается кастомная форма выбора...
    
КонецПроцедуры 

На первый взгляд всё логично. Мы установили флаг СтандартнаяОбработка = Ложь, чтобы предотвратить штатное открытие формы выбора платформой. Однако при нажатии на кнопку выбора в поле ввода всё равно открывается стандартная форма.

Выясним причину: Платформа 1С строго сопоставляет параметры вызываемых процедур-обработчиков по их позициям (индексам), а не по именам переменных. Для события НачалоВыбора поля ввода управляемой формы предусмотрена следующая жесткая сигнатура:

НачалоВыбора(<Элемент>, <ДанныеВыбора>, <СтандартнаяОбработка>)

Проанализируем, что произошло в ошибочном коде:

  1. Разработчик объявил процедуру всего с двумя параметрами: (Элемент, СтандартнаяОбработка).
  2. Платформа при вызове передала в первый параметр ссылку на элемент управления (все верно), а во второй параметр (в локальную переменную с именем СтандартнаяОбработка) записала значение платформенного параметра ДанныеВыбора.
  3. Истинный третий параметр платформы — реальный флаг СтандартнаяОбработка — в процедуру вообще не попал, так как для него не было объявлено переменной в сигнатуре.
  4. Внутри процедуры строка СтандартнаяОбработка = Ложь лишь перезаписала локальную переменную (которая на самом деле хранила структуру данных выбора), но никак не повлияла на поведение платформы. Истинный флаг стандартной обработки остался в значении Истина, и платформа послушно открыла форму по умолчанию.

Правильное решение: Всегда соблюдайте точную сигнатуру обработчиков событий. Исправим код процедуры, добавив пропущенный параметр:


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

Причина №2: Специфика динамических КроссТаблиц / МегаТаблиц

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

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

Разберем по шагам, почему это происходит:

  1. При изменении данных или перерисовке интерфейса МегаТаблицы на сервере происходит процедура полной или частичной перегенерации элементов формы. Старые колонки и поля ввода программно удаляются из коллекции Элементы формы, и на их месте создаются новые.
  2. Вместе с удалением старых элементов бесследно исчезают и назначенные им в событии ПриСозданииНаСервере действия (обработчики событий НачалоВыбора, ОбработкаВыбора и др.).
  3. Новые элементы формы создаются со свойствами по умолчанию и без привязанных обработчиков событий на клиенте. В итоге стандартный механизм платформы перехватывает управление.

Решения для динамических таблиц

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

Вариант 1. Использование события «Выбор» самой таблицы

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

Посмотрим на пример реализации данного подхода. В модуле формы определяем обработчик события выбора таблицы:


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

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

Вариант 2. Использование декларативной настройки параметров выбора

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

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


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

// Ограничим выбор только неудаленными элементами программно без перехвата НачалаВыбора
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(Новый ПараметрВыбора("Отбор.ПометкаУдаления", Ложь));

// Устанавливаем параметры выбора для элемента
НовыйЭлемент.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);

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

Правила программного открытия формы выбора из кода

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

Частая ошибка разработчиков — передавать в качестве владельца саму форму (параметр ЭтаФорма):

ОткрытьФорму("Справочник.Организации.ФормаВыбора", ПараметрыВыбора, ЭтаФорма);

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

Правильный подход: Передавайте в качестве владельца конкретный элемент формы (поле ввода), из которого был инициирован выбор:

ОткрытьФорму("Справочник.Организации.ФормаВыбора", ПараметрыВыбора, Элемент); // Где Элемент - это ПолеФормы

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

Резюме по шагам решения проблемы

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

  1. Проверяем сигнатуру процедур-обработчиков. Если используется НачалоВыбора, убеждаемся, что объявлены все три параметра: (Элемент, ДанныеВыбора, СтандартнаяОбработка).
  2. Для динамических таблиц отказываемся от индивидуальных действий на ячейках в пользу общего события таблицы Выбор или используем заполнение свойства ПараметрыВыбора на сервере при генерации колонок.
  3. При программном вызове метода ОткрытьФорму всегда передаем активный элемент управления в качестве владельца для автоматического возврата выбранного значения в форму.
← На главную