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

Скрипты и API

Обсуждение и решение проблем в работе с Eplan.

Модератор: специалисты по Eplan


Stas
знаток Eplan
знаток Eplan
Сообщения: 26
Зарегистрирован: 14 май 2014, 11:22
Ф.И.О.: Станиславский Станислав Леонидович

Re: Скрипты и API

Сообщение Stas » 01 сен 2015, 17:03

Добрый день!
После нескольких недель штурма вышеупомянутой задачи есть результат.
Но сначала несколько слов о API в целом.
Итак...
1. Для разработки дополнений желательно установить среду разработки IDE (у меня Microsoft Visual Studio), хотя обойтись можно и notepad++ (далее буду описывать ситуацию исходя из наличия IDE).
2. В IDE создаем новый проект (Файл -> Создать -> Проект -> Библиотека классов), Имя проекта (и в конце концов dll файла) должно соответствовать *.EplAddIn.* . В хэлпе было упомянуто что в VS нужно использовать шаблон Eplan Api AddIn, но у меня такого шаблона не оказалось.
3. В проекте нужно указать ссылки на библиотеки Eplan:
[spoiler=]Eplan.EplApi.AFu.dll
Eplan.EplApi.Baseu.dll
Eplan.EplApi.DataModelu.dll
Eplan.EplApi.EServicesu.dll
Eplan.EplApi.Guiu.dll
Eplan.EplApi.HEServicesu.dll
Eplan.EplApi.MasterDatau.dll
Eplan.EplApi.Ppeu.dll
Eplan.EplApi.RecorderToolsu.dll
Eplan.EplApi.RemoteClientu.dll
Eplan.EplApi.Remotingu.dll
Eplan.EplApi.Starteru.dll
Eplan.EplApi.Systemu.dll
Eplan.EplApi.WebServiceu.dll
System.Windows.Forms.dll[/spoiler]
В зависимости от реализуемого решения набор ссылок может отличаться.

4. Реализовать класс EplAddInModule содержащий:

Код: Выделить всё

using Eplan.EplApi.ApplicationFramework;

namespace Eplanwiki.EplAddIn.GetPropertyValue
{
    public class EplAddInModule : IEplAddIn
    {
        public bool OnExit()
        {
            return true;
        }

        public bool OnInit()
        {
            return true;
        }

        public bool OnInitGui()
        {
            return true;
        }

        public bool OnRegister(ref bool bLoadOnStart)
        {
            bLoadOnStart = true;
            return true;
        }

        public bool OnUnregister()
        {
            return true;
        }
    }
}

Этот класс обеспечивает "стыковку" со средой Eplan
5. Реализовать класс Get содержащий непосредственную логику работы дополнения:

Код: Выделить всё

using Eplan.EplApi.ApplicationFramework;
using System;
using System.Windows.Forms;
using Eplan.EplApi.DataModel;
using Eplan.EplApi.HEServices;

namespace Eplanwiki.EplAddIn.GetPropertyValue
{
    class Get : IEplAction
    {
        public bool Execute(ActionCallingContext oActionCallingContext)
        {

            PropertyValue oPropValue1;
            PropertyValue oPropValue2;
            int count = 0;                                      //Инициализация счетчика считающего кол-во обработанных кабелей

            SelectionSet selectionSet = new SelectionSet();     //Выбор выделенных кабелей
            StorableObject [] storableObjects = selectionSet.SelectionRecursive;

           

            foreach (StorableObject so in storableObjects)      //Перебор всех выбранных кабелей
            {
               
                oPropValue1 = so.Properties[20201, 2];          //Вычитывание свойства <20201 2>
                oPropValue2 = so.Properties[20201, 3];          //Вычитывание свойства <20201 3>
                so.Properties[20901, 1] = oPropValue1;          //Запись свойства <20201 2> в Доп. поле <20901 1>
                so.Properties[20901, 2] = oPropValue2;          //Запись свойства <20201 2> в Доп. поле <20901 2>
                count = ++count;                                           //Инкремент счетчика считающего кол-во обработанных кабелей
            }

            MessageBox.Show("Обработано " + count.ToString() + " кабеля(ей)."); //Отчет о том сколько кабелей было обработано
            return true;
        }

        public void GetActionProperties(ref ActionProperties actionProperties)
        {
            throw new NotImplementedException();
        }

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

6. Собрать решение (Сборка -> Собрать решение).
7. Найти готовую dll, скопировать ее в папку c:\Program Files\EPLAN\Platform\2.4.4\Bin\.
8. Запустить Eplan и загрузить Eplan API AddIn (Сервисные программы -> API-AddIns... -> Загрузить).
9. Создать кнопку выполняющую операцию Get.
10. Выделить необходимые кабели.
11. Нажать на кнопку выполняющую операцию Get.
12. Be Happy :)

Данные из свойств блока <20201 2> и <20201 3> будут скопированы в Доп. поля <20901 1> и <20901 2>.
Жду отзывов.

Аватара пользователя

AGorskiy
знаток Eplan
знаток Eplan
Сообщения: 2266
Зарегистрирован: 05 мар 2012, 14:00
Ф.И.О.: Горский Андрей Сергеевич
Откуда: Санкт-Петербург
Благодарил (а): 18 раз
Поблагодарили: 21 раз
Контактная информация:

Re: Скрипты и API

Сообщение AGorskiy » 01 сен 2015, 21:20

Мой отзыв, Стас - http://www.eplan4all.info/2015/09/stanislavskiy/ кроме благодарностей добавить нечего.
Все знания для всех. Поиск знаний священен. Обмен знаниями священен. Копирование священно.

Аватара пользователя

Madwolf
знаток Eplan
знаток Eplan
Сообщения: 884
Зарегистрирован: 17 окт 2012, 10:24
Ф.И.О.: Виталий
Благодарил (а): 4 раза
Поблагодарили: 14 раз

Re: Скрипты и API

Сообщение Madwolf » 02 сен 2015, 17:04

1. В документации Еплан API есть сразу готовые шаблоны для студии, не нужно было изобретать велосипед )
2. При работе с выделенными объектами, лучше сразу отфильтровать кабели, т.к. если юзер выделить что-то другое, возможны ошибки, вплоть до вылета Еплана. В данном случае я бы просто выполнял проверку типа "if so is Cable ..."


Stas
знаток Eplan
знаток Eplan
Сообщения: 26
Зарегистрирован: 14 май 2014, 11:22
Ф.И.О.: Станиславский Станислав Леонидович

Re: Скрипты и API

Сообщение Stas » 02 сен 2015, 17:48

Увы, я не располагаю шаблонами для Visual Studio.
Если Вы поделитесь шаблонами и любыми другими материалами по API - буду признателен.

Аватара пользователя

aranea
знаток Eplan
знаток Eplan
Сообщения: 519
Зарегистрирован: 21 сен 2012, 21:45
Ф.И.О.: Воробьев Александр
Поблагодарили: 12 раз
Контактная информация:

Re: Скрипты и API

Сообщение aranea » 03 сен 2015, 10:00

тоже внесу пару предложений

1. в описании забыли указать, что нужно выделить кабели в навигаторе кабелей, так как SelectionRecursive работает только в навигаторах, и если выделить кабели на листе - не сработает, не будет вложений (насколько помню)
2. копировать dll в папку еплана не обязательно, все равно указывается полный путь при выборе
3. эта конструкция перебирает не только кабели, но и жилы (скорее всего, проверьте записываются ли у них эти свойства)

Код: Выделить всё

SelectionSet selectionSet = new SelectionSet();
StorableObject [] storableObjects = selectionSet.SelectionRecursive;           

foreach (StorableObject so in storableObjects)
    {
    }

лучше перебирать именно определения кабелей, чтобы не зацепить ничего лишнего, например так

Код: Выделить всё

SelectionSet selectionSet = new SelectionSet();
List<Cable> oCables = selectionSet.SelectionRecursive.OfType<Cable>().ToList();

foreach (Cable oCable in oCables)
    {
    }

4. переменные oPropValue1, oPropValue2 лишние, можно присваивать напрямую
5. достаточно count++;
6. лучше проверять не пустое ли свойство перед копированием, чтобы не словить исключение

а так, с почином!
успехов в разработке!
Изображение


Stas
знаток Eplan
знаток Eplan
Сообщения: 26
Зарегистрирован: 14 май 2014, 11:22
Ф.И.О.: Станиславский Станислав Леонидович

Re: Скрипты и API

Сообщение Stas » 03 сен 2015, 15:57

Благодарю за замечания и предложения.
Учту.


ids
знаток Eplan
знаток Eplan
Сообщения: 14
Зарегистрирован: 17 сен 2015, 09:25
Ф.И.О.: Иванюк Дмитрий Сергеевич

Re: Скрипты и API

Сообщение ids » 17 сен 2015, 09:44

Добрый день, господа. Имеется опыт написания довольно серьезных дополнений с окнами редактирования, встроенными в Eplan. Есть ли здесь люди, которые делали подобные вещи? Есть желание поделиться опытом.
Устройства.png
Операции.png
У вас нет необходимых прав для просмотра вложений в этом сообщении.


IOIOOIIOIO
новенький
новенький
Сообщения: 1
Зарегистрирован: 25 сен 2015, 16:56
Ф.И.О.: Андрей

Re: Скрипты и API

Сообщение IOIOOIIOIO » 25 сен 2015, 17:18

Madwolf писал(а):Eplan.EplApi.EServices.Ged.Interaction прерывается при вызове любого другого Action, будь то смена страницы или вызов из командной строки. Выделить несколько объектов на разных страницах не получится (

Понимаю, что своего рода "некропост", но заметил, что данное ошибочное утверждение не подправили. Итак, как же сменить страницу и продолжить Interaction:
1. В ходе выполнения I-n следим за состоянием. В случае прерывания выполнения - сохраняем состояние в промежуточный файл (папка с проектом доступна для записи)
2. Создаем перехватчик событий на момент открытия страницы (насколько показывает GUI, имеем "XPmPageOpenOnePage")
3. В перехватчике создаем проверку на наличие файла и перезапуск I-n'a
4. Так как данный момент будет притормаживать систему, добавляем перехватчик в методе OnStart, отключаем внутри метода OnSuccess.
Как то так :roll:

Аватара пользователя

Madwolf
знаток Eplan
знаток Eplan
Сообщения: 884
Зарегистрирован: 17 окт 2012, 10:24
Ф.И.О.: Виталий
Благодарил (а): 4 раза
Поблагодарили: 14 раз

Re: Скрипты и API

Сообщение Madwolf » 26 сен 2015, 15:24

Я бы сказал что не "ошибочное утверждение", а как побороть данную проблему. Ведь сама суть класса InterAction подразумевает работу на конкретной странице, ведь в экземпляре класса хранятся данные о координатах объектов на странице, тип страницы, из которой вызван Interaction.

По сути да, можно сохранять выделенные объекты (их ID) в буфер и потом выполнить команду для их обработки.


ids
знаток Eplan
знаток Eplan
Сообщения: 14
Зарегистрирован: 17 сен 2015, 09:25
Ф.И.О.: Иванюк Дмитрий Сергеевич

Re: Скрипты и API

Сообщение ids » 08 окт 2015, 10:01

Я реализовывал так:
так как Interaction может прерваться по многим причинам (не только смена страница, но и нажатие Esc например) , в методе OnStop() проверял, надо ли перезапустить Interaction. Далее, если прервал Interaction не я, перезапускал его заново. Для выделенных объектов я сразу выполнял необходимую операцию.

Аватара пользователя

Madwolf
знаток Eplan
знаток Eplan
Сообщения: 884
Зарегистрирован: 17 окт 2012, 10:24
Ф.И.О.: Виталий
Благодарил (а): 4 раза
Поблагодарили: 14 раз

Re: Скрипты и API

Сообщение Madwolf » 22 окт 2015, 10:43

Всем привет. Что за ерунда с locking step. Пытаюсь что-то записать в объект - ничего не дает "объект не был заблокирован перед обращением для записи", пытаюсь блокировать с помощью LockObject() или SmartLock() - работает через раз. Спасает только открытие проекта в режиме "с защитой от записи". Кто как это разруливает?


ids
знаток Eplan
знаток Eplan
Сообщения: 14
Зарегистрирован: 17 сен 2015, 09:25
Ф.И.О.: Иванюк Дмитрий Сергеевич

Re: Скрипты и API

Сообщение ids » 22 окт 2015, 23:58

Попробуй так сделать перед получением активного проекта:

Код: Выделить всё

  //Получение текущего проекта.
  Eplan.EplApi.HEServices.SelectionSet selection = new Eplan.EplApi.HEServices.SelectionSet();
  selection.LockSelectionByDefault = false;
 
  Project currentProject = selection.GetCurrentProject( true );

Аватара пользователя

aranea
знаток Eplan
знаток Eplan
Сообщения: 519
Зарегистрирован: 21 сен 2012, 21:45
Ф.И.О.: Воробьев Александр
Поблагодарили: 12 раз
Контактная информация:

Re: Скрипты и API

Сообщение aranea » 23 окт 2015, 09:41

Код: Выделить всё

            SelectionSet selectionSet = new SelectionSet();
            selectionSet.LockProjectByDefault = true;

в хэлпе что-то было про LockProjectByDefault и LockSelectionByDefault
Изображение

Аватара пользователя

Madwolf
знаток Eplan
знаток Eplan
Сообщения: 884
Зарегистрирован: 17 окт 2012, 10:24
Ф.И.О.: Виталий
Благодарил (а): 4 раза
Поблагодарили: 14 раз

Re: Скрипты и API

Сообщение Madwolf » 23 окт 2015, 10:33

Спасибо, буду иметь ввиду, мне еще посоветовали:

Код: Выделить всё

using (LockingStep ls = new LockingStep())
                {
                    try
                    {
                        Project.LockAllObjects();
                        // all project's objects are locked now
                    }
                    catch (ProjectLockingException ex)
                    {
                        WriteMessage("Не удалось заблокировать проект, причина: " + ex.Message);
                    }
             }


ids
знаток Eplan
знаток Eplan
Сообщения: 14
Зарегистрирован: 17 сен 2015, 09:25
Ф.И.О.: Иванюк Дмитрий Сергеевич

Re: Скрипты и API

Сообщение ids » 23 окт 2015, 16:14

И какой вариант реализовали?

Аватара пользователя

Madwolf
знаток Eplan
знаток Eplan
Сообщения: 884
Зарегистрирован: 17 окт 2012, 10:24
Ф.И.О.: Виталий
Благодарил (а): 4 раза
Поблагодарили: 14 раз

Re: Скрипты и API

Сообщение Madwolf » 23 окт 2015, 21:19

Пока последний, посмотрим что из этого получится.
Дмитрий Сергеевич, расскажите пожалуйста подробнее про окна редактирования, встроенные в Eplan. Как это реализовывается?

Аватара пользователя

AGorskiy
знаток Eplan
знаток Eplan
Сообщения: 2266
Зарегистрирован: 05 мар 2012, 14:00
Ф.И.О.: Горский Андрей Сергеевич
Откуда: Санкт-Петербург
Благодарил (а): 18 раз
Поблагодарили: 21 раз
Контактная информация:

Re: Скрипты и API

Сообщение AGorskiy » 26 ноя 2015, 16:34

Alexander_Pavlov писал(а):На Хабре появилась публикация про API Eplan http://habrahabr.ru/post/271671/

Ссылка есть на наш форум))))
Все знания для всех. Поиск знаний священен. Обмен знаниями священен. Копирование священно.

Аватара пользователя

AGorskiy
знаток Eplan
знаток Eplan
Сообщения: 2266
Зарегистрирован: 05 мар 2012, 14:00
Ф.И.О.: Горский Андрей Сергеевич
Откуда: Санкт-Петербург
Благодарил (а): 18 раз
Поблагодарили: 21 раз
Контактная информация:

Re: Скрипты и API

Сообщение AGorskiy » 30 ноя 2015, 16:38

Предполагаю, что автор статьи на Хабре - скромный молчаливый (здесь нет ни одного сообщения) najdjel.
Спасибо, Александр.
Все знания для всех. Поиск знаний священен. Обмен знаниями священен. Копирование священно.

Аватара пользователя

Madwolf
знаток Eplan
знаток Eplan
Сообщения: 884
Зарегистрирован: 17 окт 2012, 10:24
Ф.И.О.: Виталий
Благодарил (а): 4 раза
Поблагодарили: 14 раз

Re: Скрипты и API

Сообщение Madwolf » 02 дек 2015, 18:16

Возникла следующая проблема: нужно записать в свойства функции данные, причем хочу обращаться к ней по ID и индексу, например: oFunction.Properties[20901, 1].Set(). Еплан постоянно ругается на неправильный индекс, хотя там 100% содержатся данные по данному ID и индексу. При этом oFunction.Properties.FUNC_SUPPLEMENTARYFIELD[1].Set() прекрасно работает.

Для чего нужно? Для того чтобы можно было произвольно копировать некоторые выбранные свойства в другие, т.к. некоторые отчеты не поддерживают сортировку по определенным свойствам. Хотел поручить выбор ID и индекса конечному пользователю.

Может кто уже решал данный вопрос?

Аватара пользователя

Alexander_Pavlov
знаток Eplan
знаток Eplan
Сообщения: 69
Зарегистрирован: 09 апр 2014, 08:55
Ф.И.О.: Александр Павлов
Откуда: Санкт Петербург
Благодарил (а): 3 раза
Поблагодарили: 3 раза

Re: Скрипты и API

Сообщение Alexander_Pavlov » 03 дек 2015, 10:30

Хочу написать программку, которая задавала бы толщину линий в обзоре модели. Подскажите пожалуйста, какому классу принадлежит объект обзор модели?
Eplan 2.1

Аватара пользователя

Madwolf
знаток Eplan
знаток Eplan
Сообщения: 884
Зарегистрирован: 17 окт 2012, 10:24
Ф.И.О.: Виталий
Благодарил (а): 4 раза
Поблагодарили: 14 раз

Re: Скрипты и API

Сообщение Madwolf » 04 дек 2015, 11:10

Eplan.EplApi.DataModel.Graphics: ViewPlacement - обзор модели, ViewPart - деталь на обзоре модели.
А вот уже готовый класс, который присваивает данные по толщине линий и др. параметры у графического элемента на обзоре модели:

Код: Выделить всё

static class SetPenClass
    {
        static public void SetPen(ViewPart oVP)
        {
            using (UndoStep oUndo = new UndoManager().CreateUndoStep())
            {
                Pen oPen = new Pen();
                foreach (Placement item in oVP.SubPlacements)
                {
                    try
                    {
                        if (item is GraphicalPlacement)
                        {
                            GraphicalPlacement oGPl = item as GraphicalPlacement;
                            oPen = oGPl.Layer.Pen;
                            oGPl.Pen = oPen;
                        }
                    }
                    catch (Exception ex)
                    {
                        WriteEplanMessage.Message(ex.Message);
                    }
                }

                oUndo.SetUndoDescription("Изменить графические объекты на обзоре модели");
            }
        }
    }


А данные в него поступают таким вот образом:

Код: Выделить всё

public bool Execute(ActionCallingContext ctx)
        {
            try
            {
                SelectionSet oSS = new SelectionSet();
                StorableObject[] oSOArray = oSS.Selection;
                if (oSS.Selection.Length < 1)
                {
                    CommandLineInterpreter oCLI = new CommandLineInterpreter();
                    String InteractionName = "XGedStartInteractionAction /Name:SetPenInteraction";
                    oCLI.Execute(InteractionName);
                }

                else
                {

                    foreach (StorableObject oSO in oSOArray)
                    {

                        if (oSO is ViewPlacement)
                        {
                            foreach (Placement subPlacement in ((ViewPlacement)oSO).SubPlacements)
                            {
                                if (subPlacement is ViewPart)
                                {
                                    SetPenClass.SetPen(subPlacement as ViewPart);
                                }
                            }
                        }

                        if (oSO is ViewPart)
                        {
                            SetPenClass.SetPen(oSO as ViewPart);
                        }

                    }

                }

            }

            catch (Exception ex)
            {
                WriteEplanMessage.Message(ex.Message);
            }


            return true;
        }


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


ids
знаток Eplan
знаток Eplan
Сообщения: 14
Зарегистрирован: 17 сен 2015, 09:25
Ф.И.О.: Иванюк Дмитрий Сергеевич

Re: Скрипты и API

Сообщение ids » 08 дек 2015, 10:30

С помощью Add-In'a можно реализовать дополнительную функциональность, серьезно облегчающую жизнь инженера по автоматизации. Часто бывает необходимо, чтобы дополнение постоянно отображало какую-то визуальную информации, нужную при разработке проекта. При простом решении данной проблемы - создание пользовательского окна и отображении его либо поверх всех окон, либо перемещением его на передний план - мы получаем некоторые неудобства с организацией пользовательского пространства. С ними можно кое-как мириться, но что делать, если таких окон должно быть несколько? В самой среде все организовано как надо - нужные действия реализованы в виде дополнительных окон, расположение и размер которых пользователь как хочет, так и настраивает для себя. Можно предположить, что Eplan API должен содержать данную функциональность интеграции пользовательских окон в среду, но как ни странно, такого нет. Но, если очень нужно, это можно реализовать.
Предполагается, что уже есть опыт разработки типового дополнения (если нет, то можно ознакомиться с основами здесь, поэтому будут комментироваться только действия, связанные с реализацией визуального окна дополнения. Рассмотрим, для начала, вариант дополнения, отображающего в отдельном окне (на переднем плане) список текущих открытых страниц.
Основной программный файл дополнения, main.cs.

Код: Выделить всё

//@file main.cs
//@brief Классы, реализующие дополнение.

// @author  idimm.

// @par Текущая версия:
// @$Rev: 1 $.\n
// @$Author: idimm $.\n
// @$Date:: 2015-12-03 12:05:13#$.

using System;
using System.Windows.Forms;

using Eplan.EplApi.ApplicationFramework;
using Eplan.EplApi.Gui;
using Eplan.EplApi.DataModel;
using Eplan.EplApi.HEServices;

namespace SimpleAddIn
    {
    public class AddInModule : IEplAddIn
        {
        public bool OnRegister( ref bool bLoadOnStart )
            {
            bLoadOnStart = true;
            return true;
            }

        public bool OnUnregister()
            {
            return true;
            }

        public bool OnInit()
            {
            return true;
            }

        public bool OnInitGui()
            {
            Eplan.EplApi.Gui.Menu oMenu = new Eplan.EplApi.Gui.Menu();
            uint menuID = oMenu.AddMainMenu(
                "eplaner", Eplan.EplApi.Gui.Menu.MainMenuName.eMainMenuHelp,
                "Окно помощи", "showWndAction",
                "Окно помощи по проекту", 0 /*inserts before*/ );

            return true;
            }

        public bool OnExit()
            {
            return true;
            }
        }


    public class Action_Test : IEplAction
        {
        public Action_Test()
            {
            frm = new System.Windows.Forms.Form();
            rtbox = new System.Windows.Forms.RichTextBox();
           
            rtbox.Dock = System.Windows.Forms.DockStyle.Fill;
            rtbox.Location = new System.Drawing.Point( 0, 0 );
            frm.Controls.Add( rtbox );           
            }

       

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

        public bool Execute( ActionCallingContext oActionCallingContext )
            {
            SelectionSet set = new SelectionSet();
            Page[] pages = set.OpenedPages;

            rtbox.Clear();
            foreach ( Page pg in pages )
                {
                rtbox.AppendText( pg.Name + "\n" );
                }           
            frm.ShowDialog();

            return true;
            }

        public void GetActionProperties( ref ActionProperties actionProperties )
            {
            }

        System.Windows.Forms.Form frm;
        System.Windows.Forms.RichTextBox rtbox;
        }
    }

Здесь реализовано простейшее дополнение, в процессе выполнения действия (Action Action_Test) заполняем текстовое поле нужной информацией и отображаем форму в диалоговом режиме. Результаты приведены на рисунках ниже.
Окно дополнения - вызов.png

Окно дополнения - поверх всех окон.png

Как видим, окно отображается поверх среды Eplan, работа в котором возможна только после закрытия окна. Это очень неудобно. Рассмотрим второй вариант дополнения, отображающего информацию в обычном отдельном окне. Для этого заменим строку frm.ShowDialog() на frm.Show() в методе Execute для класса Action_Test. Теперь можно переключаться между окном дополнения и средой. Но для корректной работы после закрытия окна дополнения необходимо модернизировать код класса Action_Test:

Код: Выделить всё

public class Action_Test : IEplAction
        {
        public Action_Test()
            {
            frm = new System.Windows.Forms.Form();
            rtbox = new System.Windows.Forms.RichTextBox();
           
            rtbox.Dock = System.Windows.Forms.DockStyle.Fill;
            rtbox.Location = new System.Drawing.Point( 0, 0 );
            frm.Controls.Add( rtbox );
            frm.FormClosing += FormClosing;
            }
       

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

        private void FormClosing( object sender, FormClosingEventArgs e )
            {
            e.Cancel = true;
            ( sender as System.Windows.Forms.Form ).Hide();
            }

        public bool Execute( ActionCallingContext oActionCallingContext )
            {
            SelectionSet set = new SelectionSet();
            Page[] pages = set.OpenedPages;

            rtbox.Clear();
            foreach ( Page pg in pages )
                {
                rtbox.AppendText( pg.Name + "\n" );
                }           
            frm.Show();           

            return true;
            }

        public void GetActionProperties( ref ActionProperties actionProperties )
            {
            }

        System.Windows.Forms.Form frm;
        System.Windows.Forms.RichTextBox rtbox;
        }

Как видно необходимо было добавить корректную обработку закрытия окна (метод FormClosing). Такое решение может использоваться, но все равно оно не самое удобное для пользователя. Для того, чтобы формы вела себя как встроенная, поместим ее на какое-либо стандартное окно среды, предварительно скрыв ее содержимое. Для реализации данной функциональности окна будем использовать функции WinApi. Код дополнения приведен ниже. Алгоритм работы подробно расписан в комментариях метода ShowDlg() класса EplanWindowWrapper.
Основной программный файл дополнения, main.cs.

Код: Выделить всё

//@file main.cs
//@brief Классы, реализующие дополнение.

// @author  idimm.

// @par Текущая версия:
// @$Rev: 1 $.\n
// @$Author: idimm $.\n
// @$Date:: 2015-12-03 12:05:13#$.

using System;
using System.Windows.Forms;

using Eplan.EplApi.ApplicationFramework;
using Eplan.EplApi.Gui;
using Eplan.EplApi.DataModel;
using Eplan.EplApi.HEServices;

namespace SimpleAddIn
    {
    public class AddInModule : IEplAddIn
        {
        public bool OnRegister( ref bool bLoadOnStart )
            {
            bLoadOnStart = true;
            return true;
            }

        public bool OnUnregister()
            {
            return true;
            }

        public bool OnInit()
            {
            return true;
            }

        public bool OnInitGui()
            {
            Eplan.EplApi.Gui.Menu oMenu = new Eplan.EplApi.Gui.Menu();
            uint menuID = oMenu.AddMainMenu(
                "eplaner", Eplan.EplApi.Gui.Menu.MainMenuName.eMainMenuHelp,
                "Окно помощи", "showWndAction",
                "Окно помощи по проекту", 0 /*inserts before*/ );

            return true;
            }

        public bool OnExit()
            {
            return true;
            }
        }


    public class Action_Test : IEplAction
        {
        public Action_Test()
            {
            rtbox = new System.Windows.Forms.RichTextBox();           
            rtbox.Dock = System.Windows.Forms.DockStyle.Fill;
            rtbox.Location = new System.Drawing.Point( 0, 0 );
            }       

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

        private void FormClosing( object sender, FormClosingEventArgs e )
            {
            e.Cancel = true;
            ( sender as System.Windows.Forms.Form ).Hide();
            }

        public bool Execute( ActionCallingContext oActionCallingContext )
            {
            if ( eww == null )
                {               
                eww = new EplanWindowWrapper( rtbox, new ToolStrip(), "Стр" );
                }

            if ( !wasInit )
                {
                SelectionSet set = new SelectionSet();
                Page[] pages = set.OpenedPages;

                rtbox.Clear();
                foreach ( Page pg in pages )
                    {
                    rtbox.AppendText( pg.Name + "\n" );
                    }
                }
            eww.ShowDlg();

            return true;
            }

        public void GetActionProperties( ref ActionProperties actionProperties )
            {
            }

        System.Windows.Forms.RichTextBox rtbox;
        EplanWindowWrapper eww;

        bool wasInit = false;
        }
    }

Дополнительный программный модуль, EplanWindowWrapper.cs.

Код: Выделить всё

///@file EplanWindowWrapper.cs
///@brief Классы, реализующие минимальную функциональность, необходимую для
///отображения пользовательских окон поверх окон среды Eplan.
///
/// @author idimm.
///
/// @par Текущая версия:
/// @$Rev: 476 $.\n
/// @$Author: id $.\n
/// @$Date:: 2012-04-07 16:45:35#$.
///

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

/// <summary>
/// Окно, отображающееся в Eplan'е и ведущее себя как встроенное в среду.
/// </summary>
public class EplanWindowWrapper
    {
    private IntPtr wndHandle = IntPtr.Zero;     ///Найденное окно.
    private IntPtr dialogHandle = IntPtr.Zero;  ///Найденный диалог.
    private IntPtr panelPtr;                    ///Найденная панель.
                                                 
    IntPtr oldDialogWndProc = IntPtr.Zero;      ///Старая оконная процедура.
    IntPtr oldPanelProc = IntPtr.Zero;          ///Старая оконная процедура.
    pi.Win32WndProc newWndProc;                 ///Новая оконная процедура.                         

    Control mainCntrl;          ///Пользовательское окно.
    byte[] newCaption;          ///Новый заголовок окна.
    string newCaptionStr;

    private string windowName;
    private int panelDlgItemId;
    private int dialogDlgItemId;
    private int panelToHideDlgItemId;
    private int menuClickId;


    /// <summary>   
    /// Новая оконная процедура для обработки перехваченных сообщений
    /// диалогового окна Eplan'а.
    /// </summary>
    private IntPtr DialogWndProc( IntPtr hWnd, int msg, int wPar, IntPtr lPar )
        {
        if ( hWnd == panelPtr )
            {
            switch ( ( pi.WM ) msg )
                {
                case pi.WM.MOVE:
                case pi.WM.SIZE:
                    IntPtr dialogPtr = pi.GetParent( mainCntrl.Handle );

                    pi.RECT rctDialog;
                    pi.RECT rctPanel;
                    pi.GetWindowRect( dialogPtr, out rctDialog );
                    pi.GetWindowRect( panelPtr, out rctPanel );

                    int w = rctDialog.Right - rctDialog.Left;
                    int h = rctDialog.Bottom - rctDialog.Top;

                    int dx = rctPanel.Left - rctDialog.Left;
                    int dy = rctPanel.Top - rctDialog.Top;
                    mainCntrl.Location =
                        new System.Drawing.Point( dx, dy );

                    mainCntrl.Width = w - dx;
                    mainCntrl.Height = h - dy;
                    break;
                }

            return pi.CallWindowProc( oldPanelProc, panelPtr, msg, wPar, lPar );
            }

        if ( hWnd == dialogHandle )
            {
            switch ( ( pi.WM ) msg )
                {
                case pi.WM.GETTEXTLENGTH:
                    return ( IntPtr ) newCaption.Length;

                case pi.WM.SETTEXT:
                    return IntPtr.Zero;

                case pi.WM.DESTROY:
                    dialogHandle = IntPtr.Zero;

                    pi.SetParent( mainCntrl.Handle, IntPtr.Zero );
                    mainCntrl.Hide();

                    System.Threading.Thread.Sleep( 1 );
                    break;

                case pi.WM.GETTEXT:
                    System.Runtime.InteropServices.Marshal.Copy(
                        newCaption, 0, lPar, newCaption.Length );

                    return ( IntPtr ) newCaption.Length;
                }
            }

        return pi.CallWindowProc( oldDialogWndProc, hWnd, msg, wPar, lPar );
        }


    /// <summary>
    /// Конструктор с параметрами окна, содержимое которого будет
    /// изменена на пользовательское.
    /// </summary>
    /// <param name="mainCntrl">
    /// Визуальный пользовательский компонент, отображающийся на форме.
    /// </param>
    /// <param name="caption">
    /// Новый заголовок окна.
    /// </param>
    /// <param name="windowName">
    /// Заголовок окна (окна-основы), содержимое которого будет изменена на
    /// пользовательское.
    /// </param>
    /// <param name="panelDlgItemId">
    /// Идентификатор панели-контейнера окна-основы.
    /// </param>
    /// <param name="dialogDlgItemId">
    ///  Идентификатор диалогового представления окна-основы.
    /// </param>
    /// <param name="panelToHideDlgItemId">
    /// Идентификатор панели с элементами среды Eplan, которую необходимо
    /// скрыть.
    /// </param>
    /// <param name="menuClickId">
    /// Идентификатор пункта меню для вызова окна-основы.
    /// </param>
    public EplanWindowWrapper( Control mainCntrl,
        string caption, string windowName = "Пространство листа",
        int panelDlgItemId = 0xE81F, int dialogDlgItemId = 0x3458,
        int panelToHideDlgItemId = 0xBC2, int menuClickId = 35506 )
        {
        this.mainCntrl = mainCntrl;
        mainCntrl.Hide();

        newCaptionStr = caption;
        newCaption = System.Text.Encoding.GetEncoding( 1251 ).GetBytes(
            caption + '\0' );

        this.windowName = windowName;
        this.panelDlgItemId = panelDlgItemId;
        this.dialogDlgItemId = dialogDlgItemId;
        this.panelToHideDlgItemId = panelToHideDlgItemId;
        this.menuClickId = menuClickId;

        newWndProc = DialogWndProc;
        }


    /// <summary>
    /// Инициализация формы данными для редактирования.
    ///
    /// Так как данная форма отображается как внутреннее окно, то алгоритм
    /// следующий:
    /// 1 Поиск окна (по умолчанию "Пространство листа", меню Пространство
    /// листа -> Навигатор).
    /// 1.1 Поиск плавающего представления: через FindWindowByCaption ,
    /// потом для поиска панели и диалога DlgItemId (0xE81F - базовая панель,
    /// 0x3458 - диалог). Если окно найдено, то переходим к 4, иначе к 1.2.
    /// 1.2 Поиск закрепленного представления: через GetDlgItem для всех
    /// дочерних окон (GetChildWindows) приложения Eplan по DlgItemId
    /// (0x3458 - диалог).
    /// Если окно найдено, то переходим к 4, иначе к 2.
    /// 2 Симулируем нажатие пункта меню (Пространство листа -> Навигатор)
    /// для его отображения.
    /// 3 Повторяем поиск окна (1.1 и 1.2). Если окно не найдено выводим
    /// сообщение об ошибке, завершаем редактирование, иначе к 4.
    /// 4 Скрываем панель с элементами управления Eplan'а
    /// (GetDlgItem, 0xBC2 - родительская панель, ShowWindow).
    /// 5. Переносим на найденное окно свои элементы (SetParent) и подгоняем
    /// их размеры и позицию.
    /// 6. Устанавливаем свою оконную процедуру (для изменения размеров
    /// своих элементов, обработки закрытия окна).
    /// </summary>
    public void ShowDlg()
        {
        if ( mainCntrl.Visible )
            {
            return;
            }

        bool isDocked = false;
        System.Diagnostics.Process oCurrent =
            System.Diagnostics.Process.GetCurrentProcess();

        IntPtr res = pi.FindWindowByCaption( IntPtr.Zero, windowName );//1.1
        if ( res != IntPtr.Zero )
            {
            res = pi.GetDlgItem( res, panelDlgItemId );

            wndHandle = pi.GetParent( res );
            dialogHandle = pi.GetDlgItem( res, dialogDlgItemId );
            }
        else                                                            //1.2
            {
            System.Collections.Generic.List<IntPtr> resW =
                pi.GetChildWindows( oCurrent.MainWindowHandle );
            foreach ( IntPtr panel in resW )
                {
                dialogHandle = pi.GetDlgItem( panel, dialogDlgItemId );
                if ( dialogHandle != IntPtr.Zero )
                    {
                    isDocked = true;
                    res = dialogHandle;
                    break;
                    }
                }

            if ( res == IntPtr.Zero )
                {
                pi.SendMessage( oCurrent.MainWindowHandle,
                    ( uint ) pi.WM.COMMAND, menuClickId, 0 );           //2

                res = pi.FindWindowByCaption( IntPtr.Zero, windowName );//3

                if ( res != IntPtr.Zero )
                    {
                    res = pi.GetDlgItem( res, panelDlgItemId );

                    wndHandle = pi.GetParent( res );
                    dialogHandle = pi.GetDlgItem( res, dialogDlgItemId );
                    }
                else
                    {
                    resW = pi.GetChildWindows( oCurrent.MainWindowHandle );
                    foreach ( IntPtr panel in resW )
                        {
                        dialogHandle = pi.GetDlgItem( panel, dialogDlgItemId );
                        if ( dialogHandle != IntPtr.Zero )
                            {
                            isDocked = true;
                            break;
                            }
                        }

                    if ( dialogHandle == IntPtr.Zero )
                        {
                        System.Windows.Forms.MessageBox.Show(
                            "Не удалось найти окно!" );
                        return;
                        }
                    }
                }
            }

        panelPtr = pi.GetDlgItem( dialogHandle, panelToHideDlgItemId ); //4
        if ( panelPtr == IntPtr.Zero )
            {
            System.Windows.Forms.MessageBox.Show( "Не удалось скрыть окно!" );
            return;
            }

        pi.ShowWindow( panelPtr, 0 );
               
        pi.SetParent( mainCntrl.Handle, dialogHandle );                 //5           
        mainCntrl.Show();

        int dy = 0;
        if ( isDocked )
            {
            dy = 17;           
            }

        pi.RECT dialogRect;
        pi.GetWindowRect( dialogHandle, out dialogRect );
               
        mainCntrl.Location = new System.Drawing.Point( 0, dy );

        int w = dialogRect.Right - dialogRect.Left;
        int h = dialogRect.Bottom - dialogRect.Top - dy;

        mainCntrl.Width = w;
        mainCntrl.Height = h;

        oldDialogWndProc = pi.SetWindowLong( dialogHandle, pi.GWL_WNDPROC,
            newWndProc );
        oldPanelProc = pi.SetWindowLong( panelPtr, pi.GWL_WNDPROC,
            newWndProc );

        pi.SetWindowText( dialogHandle, newCaptionStr );
        pi.SetWindowText( wndHandle, newCaptionStr );
        }
    }

/// <summary>
/// Platform Invoke functions.
/// </summary>
public class pi
    {
    /// <summary>
    /// Window procedure.
    /// </summary>
    public delegate IntPtr Win32WndProc( IntPtr hWnd, int msg, int wParam,
        IntPtr lParam );

    public const int GWL_WNDPROC = -4;

    /// <summary>
    /// Changes an attribute of the specified window. The function also sets
    /// the 32-bit (long) value at the specified offset into the extra window
    /// memory.
    /// </summary>
    /// <param name="hWnd">
    /// A handle to the window and, indirectly, the class to which the window
    /// belongs.
    /// </param>
    /// <param name="nIndex">The zero-based offset to the value to be set.
    /// Valid values are in the range zero through the number of bytes of
    /// extra window memory, minus the size of an integer. To set any other
    /// value, specify one of the following values: GWL_EXSTYLE,
    /// GWL_HINSTANCE, GWL_ID, GWL_STYLE, GWL_USERDATA, GWL_WNDPROC
    /// </param>
    /// <param name="dwNewLong">The replacement value.</param>
    /// <returns>
    /// If the function succeeds, the return value is the previous value of
    /// the specified 32-bit integer. If the function fails, the return value
    /// is zero. To get extended error information, call GetLastError.
    /// </returns>
    [DllImport( "user32" )]
    public static extern IntPtr SetWindowLong( IntPtr hWnd, int nIndex,
        Win32WndProc newProc );

    /// <summary>
    /// Set window text.
    /// </summary>
    [DllImport( "user32.dll", SetLastError = true, CharSet = CharSet.Auto )]
    public static extern bool SetWindowText( IntPtr hwnd, String lpString );

    /// <summary>
    /// Find window by Caption only. Note you must pass IntPtr.
    /// Zero as the first parameter.
    /// </summary>
    [DllImport( "user32.dll", EntryPoint = "FindWindow", SetLastError = true )]
    public static extern System.IntPtr FindWindowByCaption( IntPtr ZeroOnly,
        string lpWindowName );

    /// <summary>
    /// Windows Messages
    /// Defined in winuser.h from Windows SDK v6.1
    /// Documentation pulled from MSDN.
    /// </summary>
    public enum WM : uint
        {
        /// <summary>
        /// The WM_NULL message performs no operation. An application sends
        /// the WM_NULL message if it wants to post a message that the
        /// recipient window will ignore.
        /// </summary>
        NULL = 0x0000,
        /// <summary>
        /// The WM_CREATE message is sent when an application requests that
        /// a window be created by calling the CreateWindowEx or CreateWindow
        /// function. (The message is sent before the function returns.)
        /// The window procedure of the new window receives this message
        /// after the window is created, but before the window becomes visible.
        /// </summary>
        CREATE = 0x0001,
        /// <summary>
        /// The WM_DESTROY message is sent when a window is being destroyed.
        /// It is sent to the window procedure of the window being destroyed
        /// after the window is removed from the screen.
        /// This message is sent first to the window being destroyed and then
        /// to the child windows (if any) as they are destroyed. During the
        /// processing of the message, it can be assumed that all child
        /// windows still exist.
        /// /// </summary>
        DESTROY = 0x0002,
        /// <summary>
        /// The WM_MOVE message is sent after a window has been moved.
        /// </summary>
        MOVE = 0x0003,
        /// <summary>
        /// The WM_SIZE message is sent to a window after its size has changed.
        /// </summary>
        SIZE = 0x0005,
        //...
        /// <summary>
        /// An application sends a WM_SETTEXT message to set the text of a
        /// window.
        /// </summary>
        SETTEXT = 0x000C,
        /// <summary>
        /// An application sends a WM_GETTEXT message to copy the text that
        /// corresponds to a window into a buffer provided by the caller.
        /// </summary>
        GETTEXT = 0x000D,
        /// <summary>
        /// An application sends a WM_GETTEXTLENGTH message to determine the
        /// length, in characters, of the text associated with a window.
        /// </summary>
        GETTEXTLENGTH = 0x000E,
        //...
        /// <summary>
        /// The WM_COMMAND message is sent when the user selects a command
        /// item from a menu, when a control sends a notification message to
        /// its parent window, or when an accelerator keystroke is translated.
        /// </summary>
        COMMAND = 0x0111,
        }
   
    /// <summary>
    /// Get window parent.
    /// </summary>
    [DllImport( "user32.dll", ExactSpelling = true, CharSet = CharSet.Auto )]
    public static extern IntPtr GetParent( IntPtr hWnd );

    /// <summary>
    /// Set window parent.
    /// </summary>
    [DllImport( "user32.dll", SetLastError = true )]
    public static extern IntPtr SetParent( IntPtr hWndChild,
        IntPtr hWndNewParent );

    /// <summary>
    /// Windows rectangle structure.
    /// </summary>
    [StructLayout( LayoutKind.Sequential )]
    public struct RECT
        {
        public int Left;        // x position of upper-left corner
        public int Top;         // y position of upper-left corner
        public int Right;       // x position of lower-right corner
        public int Bottom;      // y position of lower-right corner
        }

    /// <summary>
    /// Get window rectangle.
    /// </summary>
    [DllImport( "user32.dll" )]
    [return: MarshalAs( UnmanagedType.Bool )]
    public static extern bool GetWindowRect( IntPtr hWnd, out RECT lpRect );

    /// <summary>
    /// Calls window procedure.
    /// </summary>
    [DllImport( "user32.dll" )]
    public static extern IntPtr CallWindowProc( IntPtr lpPrevWndFunc,
        IntPtr hWnd, int Msg, int wParam, IntPtr lParam );

    /// <summary>
    /// Gets dialog item by its ID.
    /// </summary>
    [DllImport( "user32.dll" )]
    public static extern IntPtr GetDlgItem( IntPtr hDlg, int nIDDlgItem );

    /// <summary>
    /// Delegate for the EnumChildWindows method
    /// </summary>
    /// <param name="hWnd">Window handle</param>
    /// <param name="parameter">
    /// Caller-defined variable; we use it for a pointer to our list
    /// </param>
    /// <returns>True to continue enumerating, false to bail.</returns>
    public delegate bool EnumWindowProc( IntPtr hWnd, IntPtr parameter );

    /// <summary>
    /// Returns a list of child windows
    /// </summary>
    /// <param name="parent">Parent of the windows to return</param>
    /// <returns>List of child windows</returns>
    public static System.Collections.Generic.List<IntPtr> GetChildWindows(
        IntPtr parent )
        {
        System.Collections.Generic.List<IntPtr> result =
            new System.Collections.Generic.List<IntPtr>();
        GCHandle listHandle = GCHandle.Alloc( result );
        try
            {
            EnumWindowProc childProc = new EnumWindowProc( EnumWindow );
            EnumChildWindows( parent, childProc, GCHandle.ToIntPtr( listHandle ) );
            }
        finally
            {
            if ( listHandle.IsAllocated )
                listHandle.Free();
            }
        return result;
        }

    /// <summary>
    /// Callback method to be used when enumerating windows.
    /// </summary>
    /// <param name="handle">Handle of the next window</param>
    /// <param name="pointer">
    /// Pointer to a GCHandle that holds a reference to the list to fill
    /// </param>
    /// <returns>True to continue the enumeration, false to bail</returns>
    public static bool EnumWindow( IntPtr handle, IntPtr pointer )
        {
        System.Runtime.InteropServices.GCHandle gch =
            System.Runtime.InteropServices.GCHandle.FromIntPtr( pointer );
        System.Collections.Generic.List<IntPtr> list =
            gch.Target as System.Collections.Generic.List<IntPtr>;
        if ( list == null )
            {
            throw new InvalidCastException(
                "GCHandle Target could not be cast as List<IntPtr>" );
            }
        list.Add( handle );
       
        return true;
        }

    [DllImport( "user32" )]
    [return: MarshalAs( UnmanagedType.Bool )]
    public static extern bool EnumChildWindows( IntPtr window,
        EnumWindowProc callback, IntPtr i );

    [DllImport( "user32.dll" )]
    public static extern IntPtr SendMessage( IntPtr hWnd, UInt32 Msg,
        Int32 wParam, Int32 lParam );

    [DllImport( "user32.dll" )]
    [return: MarshalAs( UnmanagedType.Bool )]
    public static extern bool ShowWindow( IntPtr hWnd, Int32 nCmdShow );
    }

Основная функциональность реализована в классе EplanWindowWrapper. При создании экземпляра класса необходимо указать все необходимое для корректной замены содержимого стандартного окна. Для получения необходимых идентификаторов можно использовать утилиту Spy++, которая входит в состав Visual Studio. Для удобства, все необходимые обертки WinApi функций (Platform Invoke) вынесены в отдельный класс pi.
Результат работы такой реализации приведен ниже.
Окно дополнения - встроенное.png

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

Аватара пользователя

Alexander_Pavlov
знаток Eplan
знаток Eplan
Сообщения: 69
Зарегистрирован: 09 апр 2014, 08:55
Ф.И.О.: Александр Павлов
Откуда: Санкт Петербург
Благодарил (а): 3 раза
Поблагодарили: 3 раза

Re: Скрипты и API

Сообщение Alexander_Pavlov » 08 дек 2015, 10:42

Eplan.EplApi.DataModel.Graphics: ViewPlacement - обзор модели, ViewPart - деталь на обзоре модели.


Делаю только первые шаги, поэтому, возможно, глупый вопрос.

Класс ViewPart имеет свойство SubPlacements, в help на API это есть. В References я добавил Eplan.EplApi.DataModel и прописал using Eplan.EplApi.DataModel в свой Add in, но получаю ошибку

'Eplan.EplApi.DataModel.ViewPart' does not contain a definition for 'SubPlacements' and no extension method 'SubPlacements' accepting a first argument of type 'Eplan.EplApi.DataModel.ViewPart' could be found (are you missing a using directive or an assembly reference?)
foreach (Placement item in oVP.SubPlacements)


Может в студии надо ещё где то открыть доступ?
Последний раз редактировалось Alexander_Pavlov 08 дек 2015, 11:22, всего редактировалось 1 раз.
Eplan 2.1


ids
знаток Eplan
знаток Eplan
Сообщения: 14
Зарегистрирован: 17 сен 2015, 09:25
Ф.И.О.: Иванюк Дмитрий Сергеевич

Re: Скрипты и API

Сообщение ids » 08 дек 2015, 10:52

Alexander_Pavlov писал(а):
Eplan.EplApi.DataModel.Graphics: ViewPlacement - обзор модели, ViewPart - деталь на обзоре модели.


Делаю только первые шаги, поэтому, возможно, глупый вопрос.

Класс ViewPart имеет свойство SubPlacements, в help на API это есть. В References я добавил Eplan.EplApi.DataModel и прописал using Eplan.EplApi.DataModel в свой Add in, но получаю ошибку

'Eplan.EplApi.DataModel.ViewPart' does not contain a definition for 'SubPlacements' and no extension method 'SubPlacements' accepting a first argument of type 'Eplan.EplApi.DataModel.ViewPart' could be found (are you missing a using directive or an assembly reference?)

Может в студии надо ещё где то открыть доступ?


Класс Eplan.EplApi.DataModel.ViewPart действительно не содержит свойство SubPlacements. Откройте данный класс в IDE Visual Studio и посмотрите все его свойства и методы. А вот класс Eplan.EplApi.DataModel.Graphics.ViewPlacement - имеет. Может его необходимо использовать?


ids
знаток Eplan
знаток Eplan
Сообщения: 14
Зарегистрирован: 17 сен 2015, 09:25
Ф.И.О.: Иванюк Дмитрий Сергеевич

Re: Скрипты и API

Сообщение ids » 08 дек 2015, 11:18

Madwolf писал(а):Возникла следующая проблема: нужно записать в свойства функции данные, причем хочу обращаться к ней по ID и индексу, например: oFunction.Properties[20901, 1].Set(). Еплан постоянно ругается на неправильный индекс, хотя там 100% содержатся данные по данному ID и индексу. При этом oFunction.Properties.FUNC_SUPPLEMENTARYFIELD[1].Set() прекрасно работает.

Для чего нужно? Для того чтобы можно было произвольно копировать некоторые выбранные свойства в другие, т.к. некоторые отчеты не поддерживают сортировку по определенным свойствам. Хотел поручить выбор ID и индекса конечному пользователю.

Может кто уже решал данный вопрос?


А можно поподробнее о возникающих ошибках - у меня ваш пример отлично работает.


Вернуться в «Eplan Electric P8»



Кто сейчас на конференции

Сейчас этот форум просматривают: Madwolf и 1 гость