Введение

Привет, Хабр!

Проектирование конструкторской документации для систем автоматизации в EPLAN ELECTRIC P8 — это интересный и многогранный процесс. Обычно он включает:

  • разработку электрических принципиальных схем шкафов;

  • компоновку оборудования в 3D;

  • оформление чертежей и генерацию отчётов.

На каждом этапе стандартные средства EPLAN Platform предлагают немало инструментов: макросы символов, табличные обработки, объекты-заполнители, экспорт и многое другое. Но со временем, когда база компонентов уже наполнена, схемы и компоновки отлажены, стандартного функционала начинает не хватать — хочется добавить что-то своё. И здесь на помощь приходит EPLAN API.

Главная сложность работы с API — необходимость разбираться не только в базовом функционале EPLAN, но и в языке C#, а также в среде разработки Visual Studio. Таких специалистов немного. Конечно, можно заказать доработки у профессионалов, но бюджет на это есть не всегда, поэтому многим инженерам приходится развивать собственные навыки и осваивать API самостоятельно.

Я сам занимаюсь разработкой РКД на АСУТП и столкнулся с этими трудностями: документация есть, но она скорее справочная, чем обучающая, и примеров для новичков там почти нет. Русскоязычных источников тоже немного: помог Форум АСУТП и одна статья на Хабре про создание простого Add-In.

В этой статье я попробую восполнить пробел: приведу примеры кода с пояснениями, чтобы начинающим разработчикам было проще войти в тему. Я сознательно оставляю примеры максимально простыми — чтобы сосредоточиться на сути, а не на красоте кода.

Scripts и Add-Ins: в чём разница

Итак, EPLAN Platform позволяет использовать API двумя способами: Scripts и Add-In’s.

  • Script - это обычный текстовый файл, содержащий код дополнения. Для его запуска можно просто в программе указать путь до файла *.cs и EPLAN его сам компилирует и запустит. Для запуска скриптов не требуется дополнительных лицензий, но они очень ограничены по функционалу: имеют ограниченный доступ к объектной модели EPLAN, отсутствует возможность получения свойств объектов. Обзор структуры и возможностей скриптов приведен тут.

  • Add-In - это полноценное дополнение, которое компилируется в библиотеку *.dll. Для возможности подключения таких дополнений имеется два вида лицензий: runtime и developer. Runtime лицензия позволяет запускать модули, подписанные самой компанией EPLAN или сертифицированными разработчиками. Developer лицензия позволяет подключать любые библиотеки без подписи.

Для автоматизации взаимодействия с существующими объектами EPLAN возможностей скриптов становится недостаточно, поэтому далее коснемся только разработки Add-In’s.

Создание нового проекта в Visual Studio

В этом разделе частично продублирую статью про создание Add-In'а из-за изменений в интерфейсе MS Visual Studio и API 2025.

При создании нового проекта в MS Visual Studio необходимо выбрать шаблон "Библиотека классов (.NET Framework)".

На следующем шаге выберем платформу .NET Framework 4.8.1.

Настройка проекта под EPLAN API

После создания проекта необходимо добавить ссылки на библиотеки Eplan.EplApi, которые расположены в папке установки EPLAN (в моем случае это C:\Program Files\EPLAN2025\Platform\2025.0.3\Bin).

В свойствах проекта в разделе Сборка выбираем целевую платформу x64.

В разделе "Приложение" указываем имя сборки в формате Eplan.EplAddIn.XXXX, где XXXX - имя нашего приложения.

Видео инструкция по созданию проекта Add-In.

Добавляем класс AddInModule.cs

С настройками покончено, теперь необходимо создать 2 класса: IEplAddIn и  IEplAction. Первый используется для регистрации Add-In и создания кнопок на Ribbon-панели, которые будут запускать будущие действия, прописанные в классах IEplAction.

Переименуем автоматически созданный Class1.cs в AddInModule.cs  и добавим в него следующее содержание:

using Eplan.EplApi.ApplicationFramework;
namespace Test
{
    public class AddInModule : IEplAddIn
    {
        public bool OnExit()
        {
            return true;
        }
        public bool OnInit()
        {
            return true;
        }
        public bool OnInitGui()
        {
            return true;
        }

        public bool OnRegister(ref bool bLoadOnStart)
        {
            var ribbonBar = new Eplan.EplApi.Gui.RibbonBar();
            ribbonBar.AddCommand("Тест", "ActionTest");
            bLoadOnStart = true;
            return true;
        }
        public bool OnUnregister()
        {
            var ribbonBar = new Eplan.EplApi.Gui.RibbonBar();
            ribbonBar.RemoveCommand("ActionTest");
            return true;
        }
    }
}

Начиная с версии EPLAN 2022 классические панели заменены на Ribbon и необходимо создавать и удалять кнопки на этой панели. 

В этом классе можно добавлять для кнопок иконки, комментарии, всплывающие подсказки и сортировать их. Справка по использованию Ribbon.

В текущем примере на вкладке “Расширения” в группе “API” создается новая кнопка с текстом “Тест”, выполняющая действие ActionTest, имя которого должно быть задано в отдельном классе: IEplAction в методе OnRegister.

Так как кнопки добавляются и удаляются в методах OnRegister и OnUnregister, то после внесения изменений в этих методах (например, добавления новой кнопки) чтобы увидеть обновленную информацию в Ribbon-панели, необходимо выгрузить Add-In, перезагрузить EPLAN и заново загрузить Add-In.

В целом, уже на этом этапе можно скомпилировать библиотеку и загрузить её в EPLAN. На Ribbon-панели появится дополнительная вкладка “Расширения”, и на ней появится единственная кнопка “Тест”, которая будет неактивной, так как мы ещё не сделали никаких действий для неё.

Добавляем класс ActionTest.cs

Добавим в проект еще один класс (Shift+Alt+C) и назовем его ActionTest.cs

using Eplan.EplApi.ApplicationFramework;
using System;
using System.Windows.Forms;
namespace Test
{
    public class ActionTest : IEplAction
    {
        public bool Execute(ActionCallingContext oActionCallingContext)
        {
            MessageBox.Show("Hello World");
            return true;
        }

        public void GetActionProperties(ref ActionProperties actionProperties)
        {
           
        }

        public bool OnRegister(ref string Name, ref int Ordinal)
        {
            Name = "ActionTest";
            Ordinal = 20;
            return true;
        }
    }
}

Метод OnRegister вызывается при регистрации Add-In, в нем задается имя и приоритет, которые регистрируются в EPLAN. Метод Execute выполняется при вызове Action, например при нажатии на кнопку, которую создали на предыдущем шаге. Более подробная инструкция по Action.

Взаимодействие с объектами EPLAN

Работа с текущим проектом и страницей

Многие методы API EPLAN требуют в качестве аргументов текущий проект и страницу, так что первым делом запишем в переменные текущий проект и первую выделенную страницу:

Project proj = new SelectionSet().GetCurrentProject(false);
if (proj == null) return false;
Page pg = new SelectionSet().GetSelectedPages().FirstOrDefault();

Выбор и поиск объектов

Для взаимодействия с существующими объектами можно использовать 2 инструмента

  • SelectionSet - выдает набор всех выделенных элементов

  • DMObjectsFinder - позволяет найти необходимые объекты по заданным критериям

SelectionSet

В объектной модели EPLAN множество различных типов объектов, и чтобы понять, с чем конкретно вы имеете дело, можно вывести тип выделенного объекта в сообщении:

SelectionSet Set = new SelectionSet();
if (Set.Selection.Count() == 0)
{
     return false;
}
foreach (StorableObject selObj in Set.Selection)
{
    MessageBox.Show(selObj.ToString());
}

Когда мы уже выяснили, с каким типом объекта имеем дело, то можем преобразовать StorableObject к нужному типу и дальше уже с ним взаимодействовать.

List<Terminal> TerminalsList = new List<Terminal>();
SelectionSet Set = new SelectionSet();
if (Set.Selection.Count() == 0)
{
    return false;
}
foreach (StorableObject selObj in Set.Selection)
{
    if (selObj is Terminal)
    {
        Terminal SelectedTerminal = selObj as Terminal;
        TerminalsList.Add(SelectedTerminal);
    }
}

Справка по инструменту SelectionSet.

DMObjectsFinder

Возможности поиска DMObjectsFinder хорошо иллюстрируются следующим рисунком.

Краткий пример поиска графических элементов на текущей странице:

DMObjectsFinder oDMO = new DMObjectsFinder(proj);
            PlacementsFilter filter = new PlacementsFilter
            {
                Page = pg
            };
            foreach (Placement pcc in oDMO.GetPlacements(filter))
            {
                if (pcc is GraphicalPlacement)
                {
                    GraphicalPlacement gp = pcc as GraphicalPlacement;
                    if (gp.Layer.Name == "Выноски") gp.Remove();                    
                }
            }

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

Справка по DMObjectsFinder

Как добавить поддержку Undo и Rollback

По умолчанию после выполнения любого пользовательского Action в EPLAN полностью сбрасывается список отменяемых действий (Отменить ввод CTRL+Z), что очень неудобно, учитывая отсутствие кнопки "Сохранить". Чтобы такого не произошло, необходимо позаботиться о возможности отмены действий в своем Add-In. Для этого существуют 2 инструмента: UndoManager и SafetyPoint, которые можно использовать совместно.

using (UndoStep undoStep = new UndoManager().CreateUndoStep())
    {
        undoStep.SetUndoDescription("DoStuff");
        using (SafetyPoint safetyPoint = SafetyPoint.Create())
        {
            try
            {
                // Do stuff
                safetyPoint.Commit();
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                safetyPoint.Rollback();
            }
        }
    }

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

Свойства объектов (Properties и PropertyPlacements)

У каждого объекта в API DataModel имеются свойства (Properties), которые мы можем увидеть на первой вкладке свойств.

Но также у большинства объектов имеются свойства (PropertyPlacements), которые отображаются на листе и которые мы можем настроить на вкладке "Отображение".

Для идентификации PropertyPlacements можно получить название и номер используя следующие поля:

...PropertyPlacements[ ].DisplayedProperty.Definition.Name
...PropertyPlacements[ ].DisplayedProperty.AsInt

Пример скрытия свойства <20008> ОУ (идентифицирующее, без структуры проекта) для объектов обзора модели:

SelectionSet Set = new SelectionSet();
if (Set.Selection.Count() == 0)
{
    return false;
}
foreach (StorableObject selObj in Set.Selection)
{
    if (selObj is ViewPart)
    {
        ViewPart SelectedViewPart = selObj as ViewPart;
        foreach (PropertyPlacement prop in SelectedViewPart.PropertyPlacements)
        {
            if (prop.DisplayedProperty.AsInt == 20008) prop.IsVisible = false;
        }                     
    }
}

Помимо PropertyPlacements можно использовать заранее подготовленные порядки свойств (PropertyPlacementsSchemas) и присваивать их выбранному объекту

SelectionSet Set = new SelectionSet();
if (Set.Selection.Count() == 0)
{
     return false;
}
foreach (StorableObject selObj in Set.Selection)
{
    if (selObj is ViewPart)
    {
       ViewPart SelectedViewPart = selObj as ViewPart;
       SelectedViewPart.Properties.INSTANCE_ACTIVE_PROPERTYSET.Set ("Turbo_Output");
    }
}

Справка по Properties и PropertyPlacements. Перечень всех свойств EPLAN с возможностью сортировки и фильтрации можно посмотреть здесь.

Доступ к настройкам EPLAN через API

Eplan позволяет через API получить доступ ко всем настройкам как для чтения, так и для записи. Для чтения или записи конкретной настройки необходимо определить её имя. Это можно сделать путем экспорта настроек в xml и дальнейшего нахождения в файле нужной настройки. Например как это выглядит для выбора стиля оформления:

Соответственно имя настройки для использования в Add-In будет USER.MF.GuiColorScheme, а тип возвращаемого значения - int.

Settings oSettings = new Settings();
int colorScheme = oSettings.GetNumericSetting("USER.MF.GuiColorScheme", 0); // 0=Default 1=Dark 2=Light

Справка по свойствам проекта.

Работа с Interaction

В некоторых случаях во время выполнения Action необходимо получить от пользователя информацию, например, координаты курсора в пространстве листа после клика пользователем. В этом случае EPLAN API предоставляет такую возможность в виде класса Interaction. Ниже приведен пример класса, в котором для перемещения свойств (PropertyPlacement) из подготовленного в Action списка объектов  пользователю предлагается дважды кликнуть мышкой. Первый клик сохраняет координаты, куда необходимо переместить первое свойство в списке, а второй клик расстояние до последующих свойств.

using Eplan.EplApi.Base;
using Eplan.EplApi.DataModel.EObjects;
using Eplan.EplApi.EServices.Ged;
namespace Test
{
    public class TestInteraction : Interaction
    {
        public override RequestCode OnStart(InteractionContext oContext)
        {
            Description = "Отменить перемещение"; //Наименование действия для UndoStep, который генерируется автоматически перед выполнением OnSuccess
            return RequestCode.Point;
        }
        public override RequestCode OnPoint(Position oPosition)
        {
            //Получение координат курсора после клика
            FirstPosition = oPosition.FinalPosition;
            return RequestCode.Length;
        }
        public override RequestCode OnLength(double dLength)
        {
            //Получение расстояния
            length = dLength;
            return RequestCode.Success;
        }
        public override void OnSuccess(InteractionContext oContext)
        {
            foreach (Terminal term in TestAction.SelectedTerminals)
            {
                PointD TempPoint = new PointD (FirstPosition.X - term.Location.X, FirstPosition.Y- term.Location.Y);
                term.PropertyPlacements[3].Location = TempPoint;
                FirstPosition.X += length;
            }
        }
        private double length = 0.0;
        private PointD FirstPosition = new PointD(0, 0);
    }
}

Interaction регистрируется в EPLAN по названию класса. Для вызова Interaction из Action используем ActionManager

string strAction = "XGedStartInteractionAction";
ActionManager oActionManager = new ActionManager();
Eplan.EplApi.ApplicationFramework.Action oAction = oActionManager.FindAction(strAction);
if (oAction != null)
{
    ActionCallingContext oContext = new ActionCallingContext();
    oContext.AddParameter("Name", "TestInteraction");
    bool bRet = oAction.Execute(oContext);
    /*
    if (bRet)
    {
        new Decider().Decide(EnumDecisionType.eOkDecision, "The Action " + oAction.Name + " ended successfully!", "", EnumDecisionReturn.eOK, EnumDecisionReturn.eOK);
    }
    else
    {
        new Decider().Decide(EnumDecisionType.eOkDecision, "The Action " + oAction.Name + " ended with errors!", "", EnumDecisionReturn.eOK, EnumDecisionReturn.eOK);
    }
    */
    return bRet;
}
else
{
    new Decider().Decide(EnumDecisionType.eOkDecision, "Не удалось найти XGedStartInteractionAction", "Ошибка", EnumDecisionReturn.eOK, EnumDecisionReturn.eOK);
    return false;
}

Важно, чтобы значение параметра Name в строке oContext.AddParameter("Name", "TestInteraction"); точно совпадало с названием класса Interaction. Через oContext.AddParameter можно передавать в Interaction любые строковые данные.

Справка по Interactions.

Итоги: зачем инженеру разбираться в API

API EPLAN открывает действительно широкие возможности. Даже простые Add-In’ы позволяют ускорить рутинные операции и сделать разработку проектов удобнее.

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

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

Полезные ссылки

EPLAN API Help System

Форум АСУТП

Suplanus EPLAN API Blog

Suplanus EPLAN API GitHub

Комментарии (2)


  1. DM_ChipCraft
    28.08.2025 21:04

    Отличная статья!!

    Все понятно и по делу, продолжайте дальше!


    1. tolyantez Автор
      28.08.2025 21:04

      Большое спасибо, очень рад таким отзывам!