Сообщество программистов Autodesk в СНГ

ADN Club => Revit API => Тема начата: Кирилл Захаров от 15-02-2018, 19:18:05

Название: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 15-02-2018, 19:18:05
Здравствуйте!
Я столкнулся с очень странной проблемой в работе с API Revit 2018.

Короткое описание проблемы такое:
Если обработчик события Application.DocumentSavingAs выполняет запись данных в ExtensibleStorage сохраняемого документа (строчка кода такого вида - doc.ProjectInformation.SetEntity(entity)),
то после этого все объекты, которые будут созданы в этом документе до его закрытия не сохранятся.

Более подробное описание в коде:
Код - C# [Выбрать]
  1. #region Namespaces
  2. using System;
  3. using System.Collections.Generic;
  4. using Autodesk.Revit.ApplicationServices;
  5. using Autodesk.Revit.Attributes;
  6. using Autodesk.Revit.DB;
  7. using Autodesk.Revit.DB.Events;
  8. using Autodesk.Revit.DB.ExtensibleStorage;
  9. using Autodesk.Revit.UI;
  10. #endregion
  11.  
  12. namespace RevitTestAddin
  13. {
  14.     /// <summary>
  15.     /// 2 тестовых сценария:
  16.     ///
  17.     /// 1. Открыть существующий проект
  18.     /// -> Создать 2-3 любых объекта (я создавал балки)
  19.     /// -> Сохранить проект
  20.     /// -> Закрыть проект
  21.     /// -> Открыть проект
  22.     /// -> Все работает нормально
  23.     /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24.     ///
  25.     /// 2. Создать новый проект или открыть существующий
  26.     /// -> Сохранить проект как с изменением расположения
  27.     /// -> Создать 2-3 любых объекта
  28.     /// -> Сохранить проект
  29.     /// -> Закрыть проект
  30.     /// -> Открыть проект
  31.     /// -> Созданные объекты исчезли!!!
  32.     /// </summary>
  33.     class App : IExternalApplication
  34.     {
  35.         public static Guid Guid { get; private set; }
  36.         public static Schema Schema { get; private set; }
  37.  
  38.         /// <summary>
  39.         /// Создание схемы для сохранения данных о объектах чертежа
  40.         /// </summary>
  41.         static App()
  42.         {
  43.             Guid = new Guid("d05893e6-c01e-44e9-8fbb-0d140a26015b");
  44.             SchemaBuilder schemaBuilder = new SchemaBuilder(Guid);
  45.             schemaBuilder.SetReadAccessLevel(AccessLevel.Public);
  46.             schemaBuilder.SetWriteAccessLevel(AccessLevel.Public);
  47.  
  48.             schemaBuilder.AddArrayField("ObjectArr", typeof(ElementId));
  49.  
  50.             schemaBuilder.SetSchemaName("ObjectsSchema");
  51.  
  52.             Schema = schemaBuilder.Finish();
  53.         }
  54.  
  55.  
  56.  
  57.         public Result OnStartup(UIControlledApplication a)
  58.         {
  59.             a.ControlledApplication.ApplicationInitialized += OnApplicationInitialized;
  60.             return Result.Succeeded;
  61.         }
  62.  
  63.  
  64.         void OnApplicationInitialized(object sender, ApplicationInitializedEventArgs e)
  65.         {
  66.             Application app = sender as Application;
  67.  
  68.             //Подпись на события сохранения чертежа и сохранения с новым именем
  69.             //Оба обработчика событий запускают метод, который создает Entity по схеме, описанной выше
  70.             app.DocumentSaving += DocumentSaving_EventHandler;
  71.             app.DocumentSavingAs += DocumentSavingAs_EventHandler;
  72.         }
  73.  
  74.  
  75.         public static void DocumentSaving_EventHandler(object sender, DocumentSavingEventArgs e)
  76.         {
  77.             Document doc = e.Document;
  78.             SaveDocumentObjectIds(doc);
  79.         }
  80.  
  81.         public static void DocumentSavingAs_EventHandler(object sender, DocumentSavingAsEventArgs e)
  82.         {
  83.             Document doc = e.Document;
  84.             SaveDocumentObjectIds(doc);
  85.         }
  86.  
  87.         /// <summary>
  88.         /// Создание Entity
  89.         /// Запись всех id объектов документа в Entity
  90.         /// Запись Entity в ProjectInfo
  91.         /// </summary>
  92.         /// <param name="doc"></param>
  93.         private static void SaveDocumentObjectIds(Document doc)
  94.         {
  95.             if (!doc.IsFamilyDocument)
  96.             {
  97.                 Entity entity = new Entity(Schema);
  98.                 IList<ElementId> objectArr = new List<ElementId>();
  99.                 FilteredElementCollector familyInstanceCollector = new FilteredElementCollector(doc);
  100.                 familyInstanceCollector.OfClass(typeof(FamilyInstance));
  101.                 foreach (Element elem in familyInstanceCollector)
  102.                 {
  103.                     objectArr.Add(elem.Id);
  104.                 }
  105.                 entity.Set("ObjectArr", objectArr);
  106.  
  107.                 if (entity.IsValid())
  108.                 {
  109.                     using (Transaction trans = new Transaction(doc))
  110.                     {
  111.                         trans.Start("SaveDataIntoDocument");
  112.                         doc.ProjectInformation.SetEntity(entity);
  113.                         trans.Commit();
  114.                     }
  115.                 }
  116.             }
  117.  
  118.         }
  119.  
  120.  
  121.         public Result OnShutdown(UIControlledApplication a)
  122.         {
  123.             return Result.Succeeded;
  124.         }
  125.     }
  126. }
  127.  
Тестовый проект прилагаю.

Это проблема самого API или я что-то не так делаю?
Как решить эту проблему?
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Алексей Кузин от 16-02-2018, 16:02:54
Не смог повторить, но хотелось бы разобраться. Пробовал на версии Revit 2018.2 (Попробуйте обновление поставить). Тестировал на на DuctFitting.

Цитировать
/// -> Созданные объекты исчезли!!!
Что именно вы имеете ввиду? исчезли из чертежа совсем?
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Алексей Кузин от 16-02-2018, 16:34:46
Вроде повторил. Притом именно на балках (но странно).
Обработчик события

Код - C# [Выбрать]
  1.         public static void DocumentSavingAs_EventHandler(object sender, DocumentSavingAsEventArgs e)
  2.         {
  3.             Document doc = e.Document;
  4.             SaveDocumentObjectIds(doc);
  5.         }


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

Код - C# [Выбрать]
  1.             var app = sender as Autodesk.Revit.ApplicationServices.Application;
  2.             if (app == null)
  3.                 return;
  4.  
  5.             var uiApp = new UIApplication(app);
  6.  
  7.             if (uiApp?.ActiveUIDocument?.Document == null)
  8.                 return;
  9.             if (uiApp.ActiveUIDocument.Document.IsFamilyDocument)
  10.                 return;
  11.  
  12.             var doc = uiApp.ActiveUIDocument.Document;

Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 16-02-2018, 17:09:56
Спасибо, Алексей.
У меня это не работает.
Сейчас еще попробую обновить Revit до версии 2018.2
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 16-02-2018, 17:14:29
if (uiApp?.ActiveUIDocument?.Document == null)
                return;
Никогда не видел такой записи проверки на null. Очень удобно)
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 16-02-2018, 18:15:05
Нет, это не работает, независимо от наличия обновления Revit.

Я еще раз прикладываю тестовый проект к этому сообщению. Я добавил в него две команды - по одной на каждый из тестовых сценариев. В классе Command2 команда, которая приводит к исчезновению объектов. Везде есть комментарии.
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Алексей Кузин от 16-02-2018, 22:47:53
Посмотрю обязательно в понедельник. У меня были проблемы что не всегда удавалось повторить пропадания но ошибку я видел. Мне сейчас очень близка эта тема сохранения информации, занимаюсь этим активно и хочу разобраться. Кстати я привязывался к событиям немного по другому:

там где ваш код
Код - C# [Выбрать]
  1. a.ControlledApplication.ApplicationInitialized += OnApplicationInitialized;


я делал привязку к событиям сохранения. (Но не думаю что в этом дело.)

Код - C# [Выбрать]
  1.                 a.ControlledApplication.DocumentSaving += new EventHandler<Autodesk.Revit.DB.Events.DocumentSavingEventArgs>(documentSaving);
  2.                 a.ControlledApplication.DocumentSavingAs += new EventHandler<Autodesk.Revit.DB.Events.DocumentSavingAsEventArgs>(documentSavingAs);
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Алексей Кузин от 16-02-2018, 23:02:45
Цитировать
Никогда не видел такой записи проверки на null. Очень удобно)
Очень упрощает код. так же проверку можно свести к такому виду:

Код - C# [Выбрать]
  1.             if (uiApp?.ActiveUIDocument?.Document?.IsFamilyDocument != false)
  2.                 return;
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 18-02-2018, 00:22:20
Я заметил еще одну особенность: проблема возникает только в том случае, когда при сохранении с новым именем, мы перезаписываем уже существующий файл.
Если до этого в данном расположении еще не было файла, то проблема не возникает.
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 18-02-2018, 00:49:26
Сразу добавлю, что удалить существующий файл в обработчике DocumentSavingAs не получается. Этот файл уже заблокирован.
Ревит меняет имя старого файла, дописывая суффикс с номером и записывает новый файл с именем старого
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 18-02-2018, 01:12:25
Мне пока что пришло в голову только одно решение: запретить сохранение с перезаписью старого файла
Код - C# [Выбрать]
  1.         public static void DocumentSavingAs_EventHandler(object sender, DocumentSavingAsEventArgs e)
  2.         {
  3.             if (!File.Exists(e.PathName))
  4.             {
  5.                 Document doc = e.Document;
  6.                 SaveDocumentObjectIds(doc);
  7.             }
  8.             else if(e.Cancellable)
  9.             {
  10.                 TaskDialog.Show("ПРОЕКТ НЕ СОХРАНЕН!", "Для сохранения проекта с именем "
  11.                     + e.PathName + " необходимо вручную удалить или переименовать существующий"+
  12.                     " файл с данным именем.");
  13.                 e.Cancel();
  14.             }
  15.         }
  16.  

Но в документации написано, что это событие может быть неотменяемым в том случае, если оно вызывается в момент закрытия проекта.
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 18-02-2018, 01:18:09
Autodesk уже зафиксировал эту проблему - https://forums.autodesk.com/t5/revit-api-forum/using-ext-storage-inside-documentsavingas-event-handler-causes/m-p/7783698/highlight/true#M28704. Но когда она будет решена неизвестно.
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Алексей Кузин от 19-02-2018, 12:20:50
У меня так же повторяется как и у вас. Будет ждать ответа.
Кстати если привязаться к обработчику DocumentSavedAs всё сохраняется нормально. Но после команды SaveAs документ получится что изменен. Это не решение, но возможно вам это поможет... Хотя думаю вы сами это пробовали.
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Кирилл Захаров от 19-02-2018, 15:33:44
Кстати если привязаться к обработчику DocumentSavedAs всё сохраняется нормально.
Ну мне необходимо записывать данные в ProjectInfo именно перед сохранением проекта, а не после. Это основа всей логики моего разрабатываемого плагина.
Название: Re: Проблема. Запись в ExtensibleStorage при обработке события DocumentSavingAs
Отправлено: Алексей Кузин от 20-02-2018, 12:36:39
Цитировать
Ну мне необходимо записывать данные в ProjectInfo именно перед сохранением проекта, а не после. Это основа всей логики моего разрабатываемого плагина.
Я так и понял. Просто думал на тему - записать данные после команды SaveAs а потом вызвать еще раз метод сохранения. Но из этого обработчика события точно не получится, просто для размышления...