Тема: Автоматическое обновление слоёв из базы данных

Здравствуйте.
В Civil 3D используются данные из Oracle через FDO соединение. Система ориентирована на совместную работу нескольких пользователей с одной базой данных. Необходимо автоматизированно обновлять в окне чертежа изменения, произошедшие у других пользователей.
Если использовать следующий код и вызывать его вручную с помощью команды, то, в основном, все работает.
[CommandMethod("MANREFRESH")]
        public void man_refresh()
        {
            AcMapMap currentMap = AcMapMap.GetCurrentMap();
            MgLayerCollection LayerCol = currentMap.GetLayers();
            for (int i = 0; i < LayerCol.Count; i++)
            {
                MgLayerBase currentLayer = LayerCol.GetItem(i);
                currentLayer.ForceRefresh();
            }
            Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.Regen();
        }
Если же тот же самый код запускать из dll по таймеру или с помощью уведомления через socket, то получаем ошибку:

>> System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.

Если убрать Regen(), то получаем пустое окно чертежа. В этом случае объекты вернуть можно, вручную щелкая правой кнопкой мыши по слоям Oracle и выбирая "Обновить слой".

Может кто знает в чем может быть проблема, или есть альтернативные способы обновления данных?

Re: Автоматическое обновление слоёв из базы данных

Павел Кикин пишет:

Может кто знает в чем может быть проблема?

Проблема в том, что AutoCAD API не поддерживает мультизадачность.
Почитай: http://adndevblog.typepad.com/autocad/2 … ssing.html

(изменено: Павел Кикин, 15 апреля 2013г. 13:45:09)

Re: Автоматическое обновление слоёв из базы данных

Дело в том, что код и так написан в thread  и сервер запускается вот так:

        [CommandMethod("SRVR")]
        public void srvr_start()
        {
            th = new Thread(Test);
            th.Start();
        }

Пробовали по другому писать. Нашли такую команду mapupdatemap. Сделали отдельную длльку с этой функцией:
        public void man_refresh()
        {       Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.SendStringToExecute("._MAPUPDATEMAP", true, false, false);
        }

Но при вызове этой функции сервером - вылетает ошибка о том что там ссылка на экземпляр несуществующего объекта. То есть судя по всему, когда мы работаем в отдельном потоке (thread) то связь dll с автокадом теряется. Получается мы вообще не можем никакие команды автокада вызывать с сервера.

Re: Автоматическое обновление слоёв из базы данных

Павел Кикин пишет:

То есть судя по всему, когда мы работаем в отдельном потоке (thread) то связь dll с автокадом теряется.

А я о чем писал?

Павел Кикин пишет:

Получается мы вообще не можем никакие команды автокада вызывать с сервера.

Ты внимательно прочитал всё, что я дал по ссылке?

Re: Автоматическое обновление слоёв из базы данных

Спасибо)) Пропустил начало статьи, сразу к коду пошел - решил что просто потоки предлагают)))

Re: Автоматическое обновление слоёв из базы данных

Помогло?

Re: Автоматическое обновление слоёв из базы данных

Александр Ривилис пишет:

Помогло?

Пока что разбираюсь, есть некоторые сложности, как будет результат отпишусь)

Re: Автоматическое обновление слоёв из базы данных

здравствуйте, у меня похожая проблема.
Имеется форма, созданная посредством VS на C#, грузится в виде dll через реестр. Форма опережает загрузку автокада, не давая ему полностью загрузится. после ввода корректных данных и нажатия соответствущей кнопки, форма закрывается, давая автокаду возможнсть дальнейшей загрузки. На эту же кнопку привязана функция таймера, выполнение которого должно повлечь за собой выполнение нужной команды.
фрагмент кода:

public class Class1 : IExtensionApplication
    {
        System.Timers.Timer timer = new System.Timers.Timer { Interval = 20000, AutoReset = true };
       
        //таймер
        public void MainTimer()
           {
              timer.Elapsed += new ElapsedEventHandler(Opendwg);
              timer.Start();
              MessageBox.Show("старт");
            }

        //открытие файла
        public void Opendwg(object sender, ElapsedEventArgs e)
     {
         timer.Stop();
         Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("стоп");
            //MessageBox.Show("стоп");
         var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
         doc.SendStringToExecute("_OpenDrawing", false, false, true); 
    }
       
     
       //команда открытия чертежа

        [CommandMethod("OpenDrawing", CommandFlags.Session)]
    public static void OpenDrawing()
    {
      string strFileName = "D:\\MyDLL\\template5000\\MAP5000.dwg";
     DocumentCollection acDocMgr = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
     
      if (File.Exists(strFileName))
      {
          acDocMgr.Open(strFileName, false);
      }
      else
      {
          acDocMgr.MdiActiveDocument.Editor.WriteMessage("Файла " + strFileName + " не существует.");
      }
    }

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

Re: Автоматическое обновление слоёв из базы данных

Во первых, А.Н. выше дал ссылку на информацию по теме. Во вторых, вот ещё один тынц, в котором применяется таймер в AutoCAD.

Re: Автоматическое обновление слоёв из базы данных

Вместо таймера используй это

Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
// твой дальнейший код
sw.Stop();
MessageBox.Show("Время выполнения: {0}", sw.Elapsed);

Re: Автоматическое обновление слоёв из базы данных

Спасибо за предложенный пример,он работает, но и мой таймер проблем не вызывал, мне лишь не понятно, почему по истечении работы таймера (сообщения о старте и стопе его работы появляются) автоматически не выполняется команда SendStringToExecute (из командной строки она работает).....

(изменено: Павел Кикин, 29 апреля 2013г. 08:11:19)

Re: Автоматическое обновление слоёв из базы данных

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

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