Событие - изменение значения параметра в семействе.

Автор Тема: Событие - изменение значения параметра в семействе.  (Прочитано 14408 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн toxanАвтор темы

  • ADN OPEN
  • Сообщений: 8
  • Карма: 0
Добрый день!
Подскажите, можно ли  в фоновом режиме  "увидеть" изменение параметра в определенном семействе? 
Как пример - изменение отметки семейства?


« Последнее редактирование: 31-07-2018, 14:38:10 от Александр Ривилис »

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Можно. Для этого нужно использовать IUpdater.
Там при регистрации есть варианты за чем следить - изменением геометрии, изменением параметра или за всеми изменениями.
А уже в обработчике события вы можете проверять, что это нужное вам семейство изменилось

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Александр, лучше не в IUpdater такое разруливать, а в фильтре, который передается при регистрации апдейтра, что-то вроде такого:
Код - C# [Выбрать]
  1. public ElementFilter CreateCableTrayUnionWithConduitSymbolFilter()
  2. {
  3.         var familyNameRule = ParameterFilterRuleFactory.CreateEqualsRule(new ElementId(BuiltInParameter.ALL_MODEL_FAMILY_NAME), CableTrayUnionWithConduitFamilyName, false);
  4.  
  5.         var symbolNameRule = ParameterFilterRuleFactory.CreateEqualsRule(new ElementId(BuiltInParameter.SYMBOL_NAME_PARAM), CableTrayUnionWithConduitFamilySymbolName, false);
  6.  
  7.         var filters = new ElementFilter[]
  8.                 {
  9.                         new ElementIsElementTypeFilter(),
  10.                         new ElementCategoryFilter(BuiltInCategory.OST_CableTrayFitting),
  11.                         new ElementParameterFilter(new [] {familyNameRule, symbolNameRule})
  12.                 };
  13.  
  14.         return new LogicalAndFilter(filters);
  15. }

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
а в фильтре, который передается при регистрации апдейтра
Ага, точно. Я просто забыл - под рукой не было кода никакого))

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Кстати, для решения задачи еще потребуется где-то хранить прошлое значение, это может быть Extensible storage или параметр проекта/семейства, возможно невидимый.

Т.е., например, 1 апдейтер реагирует на добавление элементов с фильтром по определенным критериям, читаем текущее значение параметра, пишем в extensible storage, второй апдейтер по тому же фильтру реагирует на изменение элемента, в методе Execute сравниваем значение параметра со значением, сохраненным в сторадже и, если они не совпадают, обновляем значение в сторадже и делаем что-то полезное :-)

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Кстати, для решения задачи еще потребуется где-то хранить прошлое значение, это может быть Extensible storage или параметр проекта/семейства, возможно невидимый.

Т.е., например, 1 апдейтер реагирует на добавление элементов с фильтром по определенным критериям, читаем текущее значение параметра, пишем в extensible storage, второй апдейтер по тому же фильтру реагирует на изменение элемента, в методе Execute сравниваем значение параметра со значением, сохраненным в сторадже и, если они не совпадают, обновляем значение в сторадже и делаем что-то полезное :-)
Ну мы не знаем, что хочет автор вопроса, поэтому нет смысла и гадать варианты реализации =)
Например, я делал подобную штуку и мне совершенно не важно было прошлое значение - я обрабатывал только текущее (новое). Все зависит от задачи

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Это всё да, просто раз вопрос об изменении определенных значений, надо дать все направления, в какую сторону копать человеку

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Кстати, как вариант еще, если не нужно менять ничего в модели, запрещать выполнение определенных операций и т.д. можно еще рассмотреть возможность подписки на событие DocumentChanged. Оно read-only, модель изменять нельзя. Из минусов оно, по сравнению с IUpdater выдает полный перечень измененных элементов на каждый чих, лично мне больше как раз нравится IUpdater с гибкими фильтрами

Оффлайн toxanАвтор темы

  • ADN OPEN
  • Сообщений: 8
  • Карма: 0
Коллеги, голову сломал.
Нужно отследить в семействе обобщенной модели  ЗНАЧЕНИЕ параметра отметки  от уровня. 
Не могу понять с какой стороны подкопаться.
Затык именно в том как получить  значение параметра при его изменении.

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
А в чем проблема?

Код - C# [Выбрать]
  1. var value = elem.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM).AsDouble();

При необходимости использовать UnitUtils для преобразования в метры, миллиметры или еще в какие единицы

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
И да, для изучения модели и API крайне рекомендую поставить RevitLookup

Оффлайн toxanАвтор темы

  • ADN OPEN
  • Сообщений: 8
  • Карма: 0
Статика,  то понятна.
Хотелось бы фоном отслеживать изменение параметра.
От начала работы до закрытия файла.
Т.е. если в семействе изменился параметр - то я тут же увидел что он изменился. Т.е. я  должен получить доступ к событию изменения ЗНАЧЕНИЯ параметра  в фоновом режиме, при каждом его изменении.

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Тогда смотрите в теме выше.

Во-первых, есть IUpdater - его метод Execute() выполняется когда "транзакция почти завершена", в нем можно получить все добавленные / измененные элементы согласно фильтра, который передается при его регистрации, здесь можно вносить изменения в модель

Во-вторых, событие DocumentChanged, в него уже прилетают все изменения, получаем элементы, анализируем, что-то делаем (но без возможности вносить изменения в модель)

Оффлайн toxanАвтор темы

  • ADN OPEN
  • Сообщений: 8
  • Карма: 0
Нужен код который реализует:


Я БЫЛ БЫ ОЧЕНЬ ПРИЗНАТЕЛЕН, ЕСЛИ КТО-ТО ПОМОГ МНЕ С ДАННЫМ КОДОМ. 


Отмечено как Решение toxan 31-07-2018, 15:09:18

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Код - C# [Выбрать]
  1. public class App : IExternalApplication
  2. {
  3.         private readonly ElementId elementId = new ElementId(706288);
  4.  
  5.         public Result OnStartup(UIControlledApplication application)
  6.         {
  7.                 application.ControlledApplication.DocumentChanged += OnDocumentChanged;
  8.  
  9.                 return Result.Succeeded;
  10.         }
  11.  
  12.         public Result OnShutdown(UIControlledApplication application)
  13.         {
  14.                 application.ControlledApplication.DocumentChanged -= OnDocumentChanged;
  15.  
  16.                 return Result.Succeeded;
  17.         }
  18.  
  19.         private void OnDocumentChanged(object sender, DocumentChangedEventArgs e)
  20.         {
  21.                 if (!e.GetModifiedElementIds().Contains(elementId))
  22.                         return;
  23.  
  24.                 var document = e.GetDocument();
  25.  
  26.                 var element = document.GetElement(elementId);
  27.  
  28.                 TaskDialog.Show("dev", element.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS).AsString());
  29.         }
  30. }

Оффлайн enot

  • ADN OPEN
  • *****
  • Сообщений: 525
  • Карма: 2
Пробую сделать подобное , но при запуске ревит выдает ошибку (с кодом выше та же ошибка):




Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Пропустили пространство имен, я так, на самом деле даже не знаю, куда .Net положит класс без определения пространства имен, т.е. в классе должно быть что-то вроде:
Код - C# [Выбрать]
  1. namespace MP.RevitReinforcmentLibrary.RevitApp
  2. {
  3.     public class RevitApplication : IExternalApplication
  4.     {
  5.         public Result OnStartup(UIControlledApplication application)...

В манифесте addin:
Код - XML [Выбрать]
  1. ...
  2.     <Assembly>./MP.RevitReinforcmentLibrary/MP.RevitReinforcmentLibrary.RevitApp.dll</Assembly>
  3.     <FullClassName>MP.RevitReinforcmentLibrary.RevitApp.RevitApplication</FullClassName>
  4. ...
  5.  

Оффлайн enot

  • ADN OPEN
  • *****
  • Сообщений: 525
  • Карма: 2
создать новый updaterId можно так:

Код - C# [Выбрать]
  1. static AddInId appId;
  2.     static UpdaterId updaterId;
  3.     public ParameterUpdater(AddInId id)
  4.     {
  5.        appId = id;
  6.        updaterId = new UpdaterId(appId, new Guid("...."));
  7.     }

каким образом можно получить все updaterId в Ревит? Это требуется чтобы если данный updaterId уже есть, то мы  удаляем его и привязываем к нашему событию
« Последнее редактирование: 01-08-2018, 20:53:29 от enot »

Оффлайн toxanАвтор темы

  • ADN OPEN
  • Сообщений: 8
  • Карма: 0
Да меня тоже данный вопрос очень интересует!

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Через API получить все апдейтеры я возможности не вижу, можно попробовать распарсить журнал.

Но для Вашего случая больше подходит статический метод:
Код - C# [Выбрать]
  1. UpdaterRegistry.IsUpdaterRegistered(updaterId)

Или
Код - C# [Выбрать]
  1. UpdaterRegistry.IsUpdaterRegistered(updaterId, doc)

Т.е. проверяете, зарегистрирован ли Ваш конкретный апдейтер

Оффлайн toxanАвтор темы

  • ADN OPEN
  • Сообщений: 8
  • Карма: 0
Спасибо добрый человек.

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Поправочка, можно получить часть информации о всех зарегистрированных апдейтерах, но там довольно немного информации, см. класс UpdaterInfo со свойствами ApplicationName, UpdaterName, IsOptional

Методы:
Код - C# [Выбрать]
  1. UpdaterRegistry.GetRegisteredUpdaterInfos()
и
Код - C# [Выбрать]
  1. UpdaterRegistry.GetRegisteredUpdaterInfos(doc)





Оффлайн enot

  • ADN OPEN
  • *****
  • Сообщений: 525
  • Карма: 2
Тогда смотрите в теме выше.

Во-первых, есть IUpdater - его метод Execute() выполняется когда "транзакция почти завершена", в нем можно получить все добавленные / измененные элементы согласно фильтра, который передается при его регистрации, здесь можно вносить изменения в модель

Во-вторых, событие DocumentChanged, в него уже прилетают все изменения, получаем элементы, анализируем, что-то делаем (но без возможности вносить изменения в модель)

Если нет возможности вносить изменения в модель (изменять например значение параметра элемента), то возможно ли как то в  DocumentChanged использовать метод  Execute() ? или наоборот...



Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Тогда смотрите в теме выше.

Во-первых, есть IUpdater - его метод Execute() выполняется когда "транзакция почти завершена", в нем можно получить все добавленные / измененные элементы согласно фильтра, который передается при его регистрации, здесь можно вносить изменения в модель

Во-вторых, событие DocumentChanged, в него уже прилетают все изменения, получаем элементы, анализируем, что-то делаем (но без возможности вносить изменения в модель)

Если нет возможности вносить изменения в модель (изменять например значение параметра элемента), то возможно ли как то в  DocumentChanged использовать метод  Execute() ? или наоборот...

Зачем вообще нужен DocumentChanged, если можно обойтись IUpdater'ом?
А вообще - конечно возможно. Вы можете нужную логику работы заложить в отдельном статическом классе и вызывать методы из него, когда требуется. Сложности будут только с контекстом Ревита и транзакцией. Но все решаемо

Оффлайн enot

  • ADN OPEN
  • *****
  • Сообщений: 525
  • Карма: 2
Зачем вообще нужен DocumentChanged, если можно обойтись IUpdater'ом?

Я могу ошибаться, но как я заметил когда я отслеживаю изменение значения параметра через IUpdater' то он реагирует только на изменение , которое произвел пользователь - допустим мы отслеживаем координату Х элемента - IUpdater' реагирует только если вручную вбить координату. А если использовать  DocumentChanged , то он отследит изменение - когда мы перенесли элемент --> координата Х изменилась автоматом --> это изменение отследит DocumentChanged (как раз это и нужно --> чтобы записать значение в другой параметр) , а IUpdater'  нет

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Нет, это где-то в Вашем коде проблема, или неверный тип изменения, или с фильтром при регистрации. IUpdater-ы использую очень с давних времен и всегда успешно

Оффлайн toxanАвтор темы

  • ADN OPEN
  • Сообщений: 8
  • Карма: 0
А есть ли  метод позволяющий "просмотреть" какой метод был вызван  при нажатии кнопки мыши.

Суть проблемы в чем:
Ведомости можно разделить средствами ревита, но данный метод отсутствует в API.
Вот и возникло желание вытащить метод непосредственно из ревита.
Не дожидаясь его добавления в API.




Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Что происходит в Revit лучше всего описывает его журнал.

Касательно сути вопроса. Вообще Revit-овские .Net-овые библиотеки (RevitAPI.dll, RevitAPIUI.dll и прочие) содержат, как managed, так и unmanaged код и по сути являются достаточно тонким wrapper-ом для вызова функций ядра из самого Revit.

Чисто теоретически, наверное, можно попробовать применить подобный подход, хотя, как мне кажется, для этого надо как минимум иметь заголовочные .h-файлы, либо использовать механизмы pInvoke.

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

Оффлайн dmitrymaslakov

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Можно ли указать в правилах фильтра имя пользовательского параметра экземпляра, за изменениями которого нужно следить?