К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как программно добавить команду в контекстное меню 1С

Пошаговое руководство: как программно добавить команду в контекстное меню формы и таблицы 1С 8.3, настроить видимость по условию, обработчик и типовые ошибки.

Контекстное меню в 1С — это выпадающий список команд, который появляется по правому клику мыши на элементе формы: таблице, поле, динамическом списке. Стандартные пункты вроде «Копировать», «Изменить», «Установить пометку удаления» платформа формирует сама, но разработчик может добавить туда собственные команды — например, «Печать акта», «Создать на основании» или «Показать связанные документы».

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

Ниже разобран полный цикл: создание команды формы, добавление кнопки в контекстное меню таблицы, назначение обработчика, управление видимостью и проверка результата. Примеры приведены для управляемых форм платформы 1С:Предприятие 8.3 — в обычных формах механика другая и рассматривается отдельно.

Когда нужен программный способ, а когда достаточно конфигуратора

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

Программное добавление оправдано в трёх ситуациях. Первая — состав меню зависит от прав: например, пункт «Провести без контроля» должен видеть только администратор. Вторая — команда появляется по условию на данные: пункт «Открыть договор» имеет смысл, только если в строке заполнено поле «Договор». Третья — форма создаётся динамически (обработки с произвольным интерфейсом), и заранее описать меню невозможно.

Маршрут решения

Как выбрать способ

Команда нужна всем пользователям и не зависит от данныхДобавьте её в конфигураторе через дерево команд формы — это проще и надёжнее
Видимость зависит от роли, функциональной опции или данных объектаСоздавайте команду и кнопку программно в ПриСозданииНаСервере
Меню нужно менять уже после открытия формыСоздавайте элементы заранее, а в процессе работы управляйте свойствами Видимость и Доступность

Шаг 1. Создание команды формы программно

Любая кнопка контекстного меню ссылается на команду формы, поэтому сначала команда создаётся в коллекции Команды. Код размещается в обработчике ПриСозданииНаСервере — на этом этапе форма уже существует на сервере, но ещё не показана пользователю, и состав элементов можно менять свободно.

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

НоваяКоманда = Команды.Добавить("ПоказатьСвязанныеДокументы");

НоваяКоманда.Действие = "Подключаемый_ПоказатьСвязанныеДокументы";

НоваяКоманда.Заголовок = НСтр("ru = 'Связанные документы'");

НоваяКоманда.Подсказка = НСтр("ru = 'Показать документы, связанные с текущей строкой'");

НоваяКоманда.Отображение = ОтображениеКнопки.Надпись;

НоваяКоманда.Картинка = БиблиотекаКартинок.НайтиВСодержании;

КонецПроцедуры

Обратите внимание на свойство Действие: в него записывается строка — имя процедуры-обработчика в модуле формы. Сама процедура должна существовать и иметь директиву компиляции &НаКлиенте, если она обращается к клиентскому контексту (открытие форм, оповещения). Если действие указано, а процедуры нет, при нажатии на пункт меню пользователь получит ошибку «Процедура или функция с указанным именем не определена».

Шаг 2. Добавление кнопки в контекстное меню элемента

Команда сама по себе не отображается — нужен элемент формы типа «Кнопка», помещённый в контекстное меню. У каждого элемента формы, поддерживающего меню (таблица, поле), есть коллекция КонтекстноеМеню, в которую кнопка и добавляется.

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

// ... создание команды (см. шаг 1) ...

МенюТаблицы = Элементы.СписокТоваров.КонтекстноеМеню;

КнопкаМеню = Элементы.Добавить("КнопкаСвязанныеДокументы",

Тип("КнопкаФормы"), МенюТаблицы);

КнопкаМеню.ИмяКоманды = "ПоказатьСвязанныеДокументы";

КонецПроцедуры

Третий параметр метода Элементы.Добавить() — родительский элемент. Именно он определяет, что кнопка попадёт в контекстное меню, а не в командную панель или на форму. Если передать Неопределено, кнопка окажется в корне формы и, скорее всего, не будет видна.

Чтобы разместить пункт в конкретном месте меню, а не в конце, используйте группы: добавьте в контекстное меню элемент типа ГруппаФормы с видом ВидГруппыФормы.ГруппаКнопок и помещайте кнопки в неё. Порядок следования пунктов соответствует порядку добавления элементов в коллекцию.

Шаг 3. Обработчик нажатия и получение текущей строки

Команды контекстного меню таблиц почти всегда работают с текущей строкой. В обработчике на клиенте текущие данные получают через свойство ТекущиеДанные элемента-таблицы, а не через объект данных напрямую — это важно для динамических списков, где объект строки недоступен целиком.

&НаКлиенте

Процедура Подключаемый_ПоказатьСвязанныеДокументы(Команда)

ТекущиеДанные = Элементы.СписокТоваров.ТекущиеДанные;

Если ТекущиеДанные = Неопределено Тогда

ПоказатьПредупреждение(, НСтр("ru = 'Строка не выбрана'"));

Возврат;

КонецЕсли;

ПараметрыФормы = Новый Структура("Отбор",

Новый Структура("Номенклатура", ТекущиеДанные.Ссылка));

ОткрытьФорму("Документ.РеализацияТоваров.ФормаСписка",

ПараметрыФормы, ЭтотОбъект);

КонецПроцедуры

Проверка ТекущиеДанные = Неопределено обязательна: пользователь может вызвать меню на пустой таблице, и без проверки обращение к полю строки вызовет ошибку. Если команда работает с выделенными строками, а не с одной текущей, используйте Элементы.СписокТоваров.ВыделенныеСтроки — это массив идентификаторов, по которым на сервере можно получить данные.

Порядок действий целиком
  1. 1
    Откройте модуль формы и найдите или создайте обработчик ПриСозданииНаСервере
  2. 2
    Создайте команду методом Команды.Добавить(), задайте Действие, Заголовок и Картинку
  3. 3
    Добавьте кнопку: Элементы.Добавить() с родителем — КонтекстноеМеню нужного элемента
  4. 4
    Свяжите кнопку с командой через свойство ИмяКоманды
  5. 5
    Напишите клиентский обработчик с проверкой ТекущиеДанные на Неопределено
  6. 6
    Обновите конфигурацию базы данных при необходимости и проверьте меню правым кликом

Управление видимостью и доступностью по условию

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

Логичное место для проверки условия — обработчик ПриАктивизацииСтроки таблицы. Но он вызывается при каждом перемещении курсора, поэтому код в нём должен быть максимально лёгким: никаких серверных вызовов и запросов. Оптимально — проверка уже загруженных данных текущей строки.

&НаКлиенте

Процедура СписокТоваровПриАктивизацииСтроки(Элемент)

ТекущиеДанные = Элементы.СписокТоваров.ТекущиеДанные;

ЕстьСтрока = (ТекущиеДанные <> Неопределено)

И ЗначениеЗаполнено(ТекущиеДанные.Договор);

Элементы.КнопкаСвязанныеДокументы.Доступность = ЕстьСтрока;

КонецПроцедуры

Если видимость зависит от роли пользователя, проверку делайте один раз на сервере при создании формы через ПользователиИнформационнойБазы.ТекущийПользователь() или функции проверки прав (ПравоДоступа, роли из БСП), и сразу устанавливайте Видимость = Ложь. Не полагайтесь только на скрытие кнопки как на защиту: саму бизнес-логику всё равно нужно защищать проверками прав на сервере.

Особенности для динамических списков и обычных форм

Для таблиц, связанных с динамическим списком (списки документов, справочников), механика та же, но есть нюанс: значение ТекущиеДанные.Ссылка доступно всегда, а вот остальные поля — только если они выведены в список или добавлены в обязательные. Если обработчику нужно поле, которого нет в запросе списка, добавьте его в запрос динамического списка, иначе получите пустое значение без всякой ошибки.

В обычных формах (режим обычного приложения) подход принципиально другой: там контекстное меню строится через объект КонтекстноеМеню элемента управления и методы Добавить с указанием действия-обработчика напрямую, без промежуточной команды формы. Если вы сопровождаете старую конфигурацию на обычных формах, код из этой статьи потребует адаптации.

Типичные ошибки
01
Кнопка добавлена в Элементы без указания родителя — пункт не появляется в контекстном меню, а кнопка теряется в корне формы
02
В свойстве Действие указано имя процедуры, которой нет в модуле, — ошибка при нажатии на пункт меню
03
Нет проверки ТекущиеДанные на Неопределено — падение при вызове меню на пустой таблице
04
Серверный вызов в ПриАктивизацииСтроки ради проверки условия — форма подтормаживает при каждом перемещении по списку
05
Попытка добавить команду в обработчике ПриОткрытии — состав элементов на клиенте уже не изменяется, нужен ПриСозданииНаСервере
06
Использовано имя команды, совпадающее с существующей, — исключение при создании формы

Проверка результата и отладка

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

Если пункта нет, проверьте три вещи по порядку: выполняется ли вообще ваш код в ПриСозданииНаСервере (поставьте точку останова), тот ли элемент формы указан как владелец меню (имена элементов чувствительны к регистру написания в конфигураторе, хотя в коде платформа имена сравнивает без учёта регистра), не переопределяется ли меню стандартными командами объекта. Отлаживать серверный код создания формы удобно в конфигураторе с включённой отладкой по протоколу HTTP или TCP в зависимости от режима запуска.

Контрольные точки

Как проверить результат

Пункт в контекстном меню
Норма

Отображается с заданным заголовком и картинкой при правом клике по таблице

Тревожный признак

Пункт отсутствует или появился в командной панели вместо меню

Нажатие на пункт
Норма

Выполняется обработчик, ошибок в журнале регистрации нет

Тревожный признак

Ошибка «процедура не определена» или ничего не происходит

Поведение на пустой таблице
Норма

Пункт недоступен или показывает понятное предупреждение

Тревожный признак

Ошибка обращения к полю Неопределено

Видимость по ролям
Норма

У пользователя без нужной роли пункт скрыт или недоступен

Тревожный признак

Пункт виден всем, а защита отсутствует и на сервере

Частые вопросы

Можно ли добавить пункт в контекстное меню динамического списка без изменения конфигурации?

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

Как добавить пункт в меню «Ещё» вместо контекстного?

Меню «Ещё» — это подменю командной панели формы. Добавьте кнопку с родителем Элементы.ФормаКоманднаяПанель.ПодменюЕщё (точное имя зависит от формы) и свяжите с командой так же, через ИмяКоманды.

Почему картинка команды не отображается в меню?

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

Можно ли добавить один пункт сразу в меню нескольких таблиц?

Да. Одна команда формы может быть связана с несколькими кнопками: добавьте по кнопке в КонтекстноеМеню каждой таблицы и укажите всем одинаковое ИмяКоманды. В обработчике различать источник вызова придётся по активному элементу формы.

Как удалить или переименовать стандартный пункт контекстного меню?

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

Работает ли этот способ в мобильном клиенте и веб-клиенте?

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

Итог

Что важно запомнить

Команда в контекстное меню добавляется в два действия: Команды.Добавить() создаёт команду с обработчиком, Элементы.Добавить() с родителем КонтекстноеМеню размещает кнопку. Весь код — в ПриСозданииНаСервере, проверка ТекущиеДанные на Неопределено обязательна, а скрытие кнопки никогда не заменяет проверку прав на сервере.