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