Динамически изменяющееся контекстное меню в 1С 8.3

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

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

Метаданные для учебной конфигурации

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

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

Событие ПриАктивизацииЯчейки

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

Получится следующий код:

&НаКлиенте
Перем ТекущаяСтрока;

&НаКлиенте
Процедура СписокПриАктивизацииЯчейки(Элемент)

    Если ТекущаяСтрока = Элементы.Список.ТекущаяСтрока Тогда
        Возврат;
    КонецЕсли;

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

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

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

&НаКлиенте
Перем ТекущаяСтрока;

&НаКлиенте
Процедура СписокПриАктивизацииЯчейки(Элемент)

    Если ТекущаяСтрока = Элементы.Список.ТекущаяСтрока Тогда
        Возврат;
    КонецЕсли;
    ТекущаяСтрока = Элементы.Список.ТекущаяСтрока;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    ДобавитьСкладыВМенюСписка(ТекущаяСтрока)

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

&НаСервере
Процедура ДобавитьСкладыВМенюСписка(ДокументПриход)

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

В этой процедуре создадим запрос, в котором получим сгруппированный список складов  с наименованиями из документа прихода.

&НаСервере
Процедура ДобавитьСкладыВМенюСписка(ДокументПриход)
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
                   |    ПриходСписокТоваров.Склад КАК Склад,
                   |    Склады.Наименование КАК НаименованиеСклада,
                   |    Склады.Код КАК КодСклада
                   |ИЗ
                   |    Документ.Приход.СписокТоваров КАК ПриходСписокТоваров
                   |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Приход КАК Приход
                   |        ПО ПриходСписокТоваров.Ссылка = Приход.Ссылка
                   |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Склады КАК Склады
                   |        ПО ПриходСписокТоваров.Склад = Склады.Ссылка
                   |ГДЕ
                   |    Приход.Ссылка = &Ссылка
                   |
                   |СГРУППИРОВАТЬ ПО
                   |    ПриходСписокТоваров.Склад,
                   |    Склады.Наименование,
                   |    Склады.Код";

    Запрос.УстановитьПараметр("Ссылка",ДокументПриход);
    Результат = Запрос.Выполнить();
    Если Результат.Пустой() Тогда
        Возврат;
    КонецЕсли;
    Выборка = Результат.Выбрать();
    Пока Выборка.Следующий() Цикл

    КонецЦикла;
КонецПроцедуры

Внутри цикла выборки создаем имена для команд, которые связаны со складами, команды, а также элементы формы с типом КнопкаФормы, которые разместим в группе Элементы.Список.КонтекстноеМеню.

Пока Выборка.Следующий() Цикл
    ИмяКоманды = "ОткрытиеСклада_" + Выборка.КодСклада;

    Команда = Команды.Добавить(ИмяКоманды);
    Команда.Заголовок = "Открыть склад: " + Выборка.НаименованиеСклада;
    Команда.Действие  = "ОткрытиеФормыСкладаИзКонтекстногоМеню";

    КнопкаКоманды = Элементы.Добавить("КнопкаКоманды" + ИмяКоманды, Тип("КнопкаФормы"),Элементы.Список.КонтекстноеМеню);
    КнопкаКоманды.ИмяКоманды = ИмяКоманды;
КонецЦикла;

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

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

Таблица значений на форме

Будем заполнять эту таблицу в конце цикла.

НовСтрока = СвязьКомандыИСклада.Добавить();
НовСтрока.ИмяКоманды = ИмяКоманды;
НовСтрока.Склад = Выборка.Склад;

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

&НаКлиенте
Процедура ОткрытиеФормыСкладаИзКонтекстногоМеню(Элемент)
    ИмяКоманды = Элемент.Имя;
    Отбор = Новый Структура("ИмяКоманды",ИмяКоманды);
    МассивСкладов = СвязьКомандыИСклада.НайтиСтроки(Отбор);

    Если МассивСкладов.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

    СсылкаНаСклад = МассивСкладов[0].Склад;

    ПараметрыОткрытия = Новый Структура("Ключ",СсылкаНаСклад);

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

Нам осталось в начале процедуры ДобавитьСкладыВМенюСписка очищать команды и элементы формы, которые мы создали ранее.

Для Каждого стрКоманда из СвязьКомандыИСклада Цикл
    ИмяКоманды = стрКоманда.ИмяКоманды;
    ИмяКнопки  = "КнопкаКоманды" + ИмяКоманды;
    Команды.Удалить(Команды[ИмяКоманды]);
    Элементы.Удалить(Элементы[ИмяКнопки]);
КонецЦикла;
СвязьКомандыИСклада.Очистить();

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

Изменяющееся контекстное меню формы

Изменяющееся контекстное меню формы

А при выполнении команды, будет открываться форма того склада, который указан в названии этой команды.

Мой опыт преподавания показывает, что многие начинающие и не очень разработчики всё еще слабо программируют в управляемом приложении, теряются во многих вопросах.
Книга «Основы разработки в 1С: Такси» научила программировать под управляемым приложением 300+ начинающих программистов 1С.
И Вы обязательно освоите все тонкости разработки под управляемым приложением 1С 8.3.

Книга «Основы разработки в 1С: Такси»

  1. Очень доступный и понятный язык изложения
  2. Книга посылается на электронную почту в формате PDF. Можно открыть на любом устройстве!
  3. Поймете идеологию управляемого приложения 1С
  4. Узнаете, как разрабатывать управляемое приложение;
  5. Научитесь разрабатывать управляемые формы 1С;
  6. Сможете работать с основными и нужными элементами управляемых форм
  7. Программирование под управляемым приложением станет понятным

Только для читателей моего блога,
промо-код на скидку в 150 рублей — blog

Для тех же, кто только начинает:
общие вопросы по разработке в 1С подробно и основательно даются в книге «Программировать в 1С за 11 шагов»

Книга «Программировать в 1С за 11 шагов»

Стартуйте в изучении 1С программирования в месте с моей книги «Программировать в 1С за 11 шагов»

  1. Книга написана понятным и простым языком — для новичка.
  2. Книга посылается на электронную почту в формате PDF. Можно открыть на любом устройстве!
  3. Научитесь понимать архитектуру 1С;
  4. Станете писать код на языке 1С;
  5. Освоите основные приемы программирования;
  6. Закрепите полученные знания при помощи задачника;

Только для читателей моего блога, промо-код на скидку в 150 рублей — blog

Эти книги плюс книга по программированию оперативного учета имеются в едином комплекте: комплект книг по разработке в 1С.
Только для читателей моего блога,
промо-код на скидку в 300 рублей на весь комплект: blog


Если Вам помог этот урок решить какую-нибудь проблему, понравился или оказался полезен, то Вы можете поддержать мой проект, перечислив любую сумму:

можно оплатить вручную:

Яндекс.Деньги — 410012882996301
Web Money — R955262494655

Вступайте в мои группы:

Вконтакте: https://vk.com/1c_prosto
Фейсбуке: https://www.facebook.com/groups/922972144448119/
ОК: http://ok.ru/group/52970839015518
Твиттер: https://twitter.com/signum2009

3 Replies to “Динамически изменяющееся контекстное меню в 1С 8.3”

  1. Что за бред и корявый код?
    И разве не смущает, что:
    В обработчике СписокПриАктивизацииЯчейки используется вызов контекстного серверного метода формы
    т.е. по факту получаем бесконечный цикл, благо платформа об этой лаже знает и не зациклит, но будет постоянно спамить…

    1. Читаем внимательно статью, прежде чем оставлять неграмотные комментарии.
      Чтобы не было бесконечного цикла в самом начале осуществляется проверка.

  2. В данном случае лучше использовать событие «ПриАктивизацииСтроки» вместо события «ПриАктивизацииЯчейки».

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *