Инструменты пользователя

Инструменты сайта


developers:tutorial:createmodel

Различия

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

Ссылка на это сравнение

Следующая версия
Предыдущая версия
developers:tutorial:createmodel [2019/02/16 17:38]
vasya создано
developers:tutorial:createmodel [2022/03/15 19:14] (текущий)
proxor
Строка 1: Строка 1:
 ====== Создание и сохранение модели ====== ====== Создание и сохранение модели ======
  
-Каждая модель данных в комплексе [[http://​www.topomatic.ru|Топоматик Робур]] располагается в рамках отдельного файла, включенного в состав проекта. Для подключения собственной модели к комплексу,​ необходимо выполнить следующие действия:​+Каждая модель данных в комплексе [[http://​www.topomatic.ru|Топоматик Робур]] располагается в рамках отдельного файла, включенного в состав проекта. ​С программной точки зрения модель представляет собой экземпляр класса,​ реализующий интерфейс [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel|IProjectModel]]. 
 +Основные методы этого интерфейса это: 
 +  * [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|LockWrite()]] - блокирует модель для начала редактирования данных 
 +  * [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|UnockWrite()]] - разблокирует модель после окончания редактирования данных 
 +  * [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|LockRead()]] - возвращает экземпляр класса,​ реализующий структуру данных конкретной модели 
 + 
 +Для чтения данных из модели используется метод [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|LockRead()]]. Если данные модели необходимо изменить,​ то перед вызовом [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|LockRead()]] необходимо вызвать [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|LockWrite()]],​ а после [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|UnockWrite()]]. 
 +<​note>​ 
 +После вызова метода [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|LockWrite()]] файл модели становится недоступным для редактирования другими пользователями до того момента,​ пока не будет вызван метод [[developers:​references:​topomatic.applicationplatform.core.iprojectmodel.lockwrite|UnockWrite()]]. 
 +</​note>​ 
 + 
 +Для подключения собственной модели к комплексу,​ необходимо выполнить следующие действия:​ 
 +  * Создать класс модели,​ реализующий интерфейс [[developers:​references:​topomatic.foundationclasses.istatecontroller|IStateController]],​ это необходимо для того чтобы была возможность определять состояние модели и была ли она изменена.
   * Создать класс редактора модели,​ наследник от [[developers:​references:​topomatic.applicationplatform.core.modeleditor|ModelEditor]],​ предназначенный для реализации загрузки,​ сохранения и открытия модели   * Создать класс редактора модели,​ наследник от [[developers:​references:​topomatic.applicationplatform.core.modeleditor|ModelEditor]],​ предназначенный для реализации загрузки,​ сохранения и открытия модели
   * Написать метод, который возвращает экземпляр наследника от [[developers:​references:​topomatic.applicationplatform.core.modeleditor|ModelEditor]] и декорировать его атрибутом "​cmd"​   * Написать метод, который возвращает экземпляр наследника от [[developers:​references:​topomatic.applicationplatform.core.modeleditor|ModelEditor]] и декорировать его атрибутом "​cmd"​
Строка 7: Строка 19:
   * В файле *.plugin в секции [[developers:​references:​core.plugin:​cores|cores]] описать вид модели в структуре проекта,​ а в секции [[developers:​references:​core.plugin:​coreitems|coreitems]] включить модель в состав стандартного проекта. ​   * В файле *.plugin в секции [[developers:​references:​core.plugin:​cores|cores]] описать вид модели в структуре проекта,​ а в секции [[developers:​references:​core.plugin:​coreitems|coreitems]] включить модель в состав стандартного проекта. ​
  
-Обычно поведение модели может быть реализовано одним из следующих способов:​ +<​note>​ 
-  * При открытии модели открывается программа предназначенная для работы с файлами данного типа ​(например ​файлы ведомостей,​ текстовые файлы ​и т.п.) +Большая ​часть методов интерфейса [[developers:​references:​topomatic.foundationclasses.istatecontroller|IStateController]] реализована в классе [[developers:​references:​topomatic.foundationclasses.statecontrollerobject|StateControllerObject]]. 
-  * При открытии модели открывается отдельное окно для редактирования (например файлы чертежа) +Редактор модели на видовом экране окна план и других системных окон нужно наследовать от [[developers:​references:​topomatic.applicationplatform.core.planmodeleditor|PlanModelEditor]]. 
-  * При открытии ​модель отображается в окне плана и других системных окнах ​(например файлы поверхности, подобъектов и т.п.)+Редактор ​модели ​в отдельном окне нужно наследовать от [[developers:​references:​topomatic.applicationplatform.core.documentmodeleditor|DocumentModelEditor]] 
 +</​note>​ 
 + 
 +Для ​реализации сохранения и загрузки ​в программном комплексе [[http://​www.topomatic.ru|Топоматик Робур]] ​используется сборка [[developers:​references:​topomatic.stg|Topomatic.Stg.dll]]. За сохранение отвечает интерфейс [[developers:​references:​topomatic.stg.istgserializable|IStgSerializable]],​ который состоит из двух методов - [[developers:​references:​topomatic.stg.istgserializable.loadfromstg_topomatic.stg.stgnode|LoadFromStg]] для загрузки  
 +и [[developers:​references:​topomatic.stg.istgserializable.savetostg_topomatic.stg.stgnode|SaveToStg]] для сохранения. Оба метода в качестве ​параметра принимают экземпляр класса [[developers:​references:​topomatic.stg.stgnode|StgNode]]. Методы этого класса позволяют сохранить в узел и загрузить из узла все ​базовые типы данных,​ а также дополнительные узлы [[developers:references:​topomatic.stg.stgnode|StgNode]] и массивы элементов,​ используя именованные элементы. 
 +Кроме того у каждого метода есть перекрытое значение, со значением по умолчанию. Значение по умолчанию будет использовано в том случае,​ если в загружаемом файле нет такого именованного элемента. Например: 
 +<code csharp>​ 
 +
 +    .... 
 +    private double m_Value1 = 0.0; 
 +   
 +    private string m_Value2 = 0.0; 
 + 
 +    void LoadFromStg(StgNode node) 
 +    { 
 +         //​Если ​в сохраненном файле нет значения ​с ключом Value1 будет брошено исключение 
 +         ​m_Value1 = node.GetDouble("​Value1"​);​ 
 +         //​Если в сохраненном файле нет значения с ключом Value2,  
 +         //​то ​переменной m_Value2 будет присвоено значение "​defaultValue"​ 
 +         ​m_Value2 = node.GetString("​Value2",​ "​defaultValue"​);​ 
 +    } 
 +    ... 
 +
 +</​code>​ 
 + 
 +Использование именованных элементов позволяет легко расширять и дополнять функции загрузки и сохранения по мере расширения модели данных.  
 + 
 +<​note>​ 
 +Если в сохраненном файле отсутствует вложенный узел [[developers:​references:​topomatic.stg.stgnode|StgNode]] или массив,​ то функции [[developers:​references:​topomatic.stg.stgnode.getnode_system.string|GetNode]] и [[developers:​references:​topomatic.stg.stgnode.getarray_system.string_topomatic.stg.stgtype|GetArray]] вернут пустые элементы.  
 +Проверить ​наличие именованного значения внутри узла позволяет метод [[developers:​references:​topomatic.stg.stgcollection.isexists_system.string|IsExists]] 
 +</​note>​ 
 +  
 +Создайте и настройте новый [[developers:​tutorial:​module|модуль]] ​для ​подключения к программному комплексу [[http://​www.topomatic.ru|Топоматик Робур]].  
 + 
 +С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:​ 
 + 
 +  * [[developers:​references:​topomatic.cad.foundation|Topomatic.Cad.Foundation.dll]] - базовые математические типы и операции 
 +  * [[developers:​references:​topomatic.controls|Topomatic.Controls.dll]] - базовые диалоги и таблицы 
 + 
 +Создайте новый класс Model.cs для реализации нашей ​модели
 +<code csharp>​ 
 +
 +    //​Класс реализующий структуру ​данных нашей модели 
 +    //для поддержки интерфейса IStateController наследуем от StateControllerObject 
 +    class Model : StateControllerObject,​ IStgSerializable 
 +    { 
 +        private bool m_ReadOnly = false; 
 + 
 +        //​Строковое значение 
 +        public string StringValue = "​Строка";​ 
 + 
 +        //​Булево значение 
 +        public bool BooleanValue = false; 
 + 
 +        //​Значение с плавающей точкой 
 +        public double DoubleValue = 10.5; 
 + 
 +        //​Целое значение 
 +        public int IntValue = 10; 
 + 
 +        //Список строковых значений 
 +        public List<​string>​ ArrayValues = new List<​string>​();​ 
 + 
 +        //флаг только для чтения 
 +        public override bool ReadOnly 
 +        { 
 +            get 
 +            { 
 +                return m_ReadOnly;​ 
 +            } 
 + 
 +            set 
 +            { 
 +                m_ReadOnly = value; 
 +            } 
 +        } 
 + 
 +        //​Загрузка из узла 
 +        public void LoadFromStg(StgNode node) 
 +        { 
 +            //Все значения загружаем с указанием значения по умолчанию 
 +            BooleanValue = node.GetBoolean("​BooleanValue",​ false); 
 +            StringValue = node.GetString("​StringValue",​ "Строка"); 
 +            DoubleValue = node.GetDouble("​DoubleValue",​ 10.5); 
 +            IntValue = node.GetInt32("​IntValue",​ 10); 
 +            ArrayValues.Clear();​ 
 +            //При загрузке массива указывается тип составляющих массив значений 
 +            var array = node.GetArray("​ArrayValues",​ StgType.String);​ 
 +            for (int i = 0; i < array.Count;​ i++) 
 +            { 
 +                ArrayValues.Add(array.GetString(i));​ 
 +            } 
 +        } 
 + 
 +        //​Сохранение в узел 
 +        public void SaveToStg(StgNode node) 
 +        { 
 +            //​Сохраняем значения ​в узел 
 +            node.AddBoolean("​BooleanValue",​ BooleanValue);​ 
 +            node.AddString("​StringValue",​ StringValue);​ 
 +            node.AddDouble("​DoubleValue",​ DoubleValue);​ 
 +            node.AddInt32("​IntValue",​ IntValue);​ 
 +            //​Сохраняем массив с указанием типа значений 
 +            var array = node.AddArray("​ArrayValues",​ StgType.String);​ 
 +            for (int i = 0; i < ArrayValues.Count;​ i++) 
 +            { 
 +                array.AddString(ArrayValues[i]);​ 
 +            } 
 +        } 
 +    } 
 +
 +</​code>​ 
 + 
 +И класс Editor.cs реализующий редактор модели 
 + 
 +<code csharp>​ 
 +
 +    //Класс реализующий редактор нашей модели 
 +    class Editor : ModelEditor 
 +    { 
 +        //​Реализация загрузки модели по указанному путидолжна вернуть реализацию ​класса нашей модели 
 +        public override object LoadFromFile(string fullpath) 
 +        { 
 +            //​создаем экземпляр класса модели 
 +            var model = new Model(); 
 +            //если fullpath null - то необходимо просто вернуть экземпляр класса модели,​ без загрузки данных 
 +            if (fullpath != null) 
 +            { 
 +                //​создаем файловый поток 
 +                using (var stream = new FileStream(fullpath,​ FileMode.Open, FileAccess.Read, FileShare.Read)
 +                { 
 +                    //​создаем документ для ​работы с Topomatic.Stg 
 +                    var document = new StgDocument();​ 
 +                    //​загружаем документ ​из потока в бинарном виде 
 +                    document.LoadFromStreamAsBinary(stream);​ 
 +                    //​загружаем данные нашей модели из документа 
 +                    model.LoadFromStg(document.Body);​ 
 +                } 
 +            } 
 +            //​всегда возвращаем экземпляр модели 
 +            return model; 
 +        } 
 + 
 +        //Реализация сохранения ​модели ​по указанному пути 
 +        public override void SaveToFile(object model, string fullpath) 
 +        { 
 +            //в качестве параметра model приходит наша модель ​данных 
 +            var m = model as Model; 
 +            if (m != null) 
 +            { 
 +                //создаем файловый поток 
 +                using (var stream = new FileStream(fullpath,​ FileMode.Create,​ FileAccess.Write,​ FileShare.None)) 
 +                { 
 +                    //создаем документ ​для работы с Topomatic.Stg 
 +                    var document = new StgDocument();​ 
 +                    //​сохраняем данные нашей модели в документ 
 +                    m.SaveToStg(document.Body);​ 
 +                    //сохраняем документ ​в потока в бинарном виде 
 +                    document.SaveToStreamAsBinary(stream);​ 
 +                } 
 +            } 
 +        } 
 + 
 +        //​Реализация открытия модели по команде "​open"​ 
 +        public override IEditorResult Open(IProjectModel model) 
 +        { 
 +            var cursor = Cursor.Current;​ 
 +            Cursor.Current = Cursors.WaitCursor;​ 
 +            try 
 +            { 
 +                //В нашем ​поросто возвращаем реализацию интерфеса IEditorResult 
 +                return new EditorResult();​ 
 +            } 
 +            finally 
 +            { 
 +                Cursor.Current = cursor; 
 +            } 
 +        } 
 + 
 +        //​Реализация интерфейса IEditorResult 
 +        private class EditorResult : IEditorResult 
 +        { 
 +            private bool m_Opened; 
 + 
 +            public EditorResult() 
 +            { 
 +                m_Opened = true; 
 +            } 
 + 
 +            //​Необходимо реализовать флаг, показывающий открыта модель или нет 
 +            public bool Opened 
 +            { 
 +                get 
 +                { 
 +                    return m_Opened; 
 +                } 
 +            } 
 + 
 +            //​Необходимо реализовать метод закрытия модели 
 +            public void Close() 
 +            { 
 +                //В нашем случае мы просто управляем флагом и все 
 +                m_Opened = false; 
 +            } 
 + 
 +            //И метод перезагрузки модели 
 +            public void Reload(
 +            { 
 +                //​Здесь нам ничего не нужно делать 
 +            } 
 +        } 
 +    } 
 +
 +</​code>​ 
 + 
 +В нашем случае ​редактор модели получился достаточно простым,​ поскольку наша модель не реагирует на команду ​открыть и фактически вся работа с ней будет происходить в отдельной команде для редактирования модели. 
 +Дополнительно необходимо ​реализовать [[developers:​tutorial:​dlgandpropertygrid|диалог]] для редактирования данных модели. Его реализацию можно увидеть в исходных кодах ​примера. 
 + 
 +В теле программного модуля необходимо объявить функции для создания и редактирования модели,​ функцию для создания редактора и регистрации модели. 
 +<code csharp>​ 
 +    partial class Module : Topomatic.ApplicationPlatform.Plugins.PluginInitializator 
 +    { 
 +        //​функция ​создает экземпляр редактора модели и возвращает его 
 +        [cmd("​create_testmodel_editor"​)] 
 +        public Editor CreateEditor() 
 +        { 
 +            return new Editor(); 
 +        } 
 + 
 +        //​функция создает новую модель и возвращает её 
 +        [cmd("​create_testmodel"​)] 
 +        private object CreateModel(object[] args) 
 +        { 
 +            //​получаем текущий активный проект 
 +            var project = ApplicationHost.Current.ActiveProject as ModelProject;​ 
 +            Debug.Assert(project != null); 
 +            if (project != null) 
 +            { 
 +                //​запускаем групповое изменение свойств 
 +                project.TransactionManager.BeginUpdate();​ 
 +                try 
 +                { 
 +                    string folder; 
 +                    if ((args != null) && (args.Length > 0) && (args[0] != null)) 
 +                    { 
 +                        //В качестве аргумента приходит либо идентификатор каталога внутри ​проекта 
 +                        folder = args[0].ToString();​ 
 +                    } 
 +                    else 
 +                    { 
 +                        //либо мы создаем  этот идентификатор самостоятельно 
 +                        folder = PluginCoreOps.FindModelPathId(PluginCoreOps.CreateFolder(new string[] { "​Модели",​ "​Тестовые модели"​ })); 
 +                    } 
 +                    //​создаем модель с помощью команды "​mkitem"​ 
 +                    //в неё мы передаем идентификатор каталога ​и тип нашей модели 
 +                    return ApplicationHost.Current.Plugins.Execute("​mkitem"​new object[] { folder, "​testmodel"​ }); 
 +                } 
 +                finally 
 +                { 
 +                    project.TransactionManager.EndUpdate();​ 
 +                } 
 +            } 
 +            else 
 +            { 
 +                throw new OperationCanceledException();​ 
 +            } 
 +        } 
 + 
 +        //​функция ​позволяет редактировать содержимое нашей модели 
 +        [cmd("​edit_testmodel"​)] 
 +        private void OpenModel(string pathid) 
 +        { 
 +            //​получаем IProjectModel используя идентификатор модели 
 +            var project_model = PluginCoreOps.FindModel(pathid);​ 
 +            if (project_model != null) 
 +            { 
 +                //вызываем блокировку модели на редактирование 
 +                project_model.LockWrite();​ 
 +                try 
 +                { 
 +                    //получаем класс нашей модели 
 +                    var model = project_model.LockRead(as Model; 
 +                    if (model != null) 
 +                    { 
 +                        //​вызываем диалог редактирования нашей модели 
 +                        if (EditModelDlg.Execute(model)) 
 +                            project_model.Modified = true; 
 +                    } 
 +                } 
 +                finally 
 +                { 
 +                    //​снимаем блокировку модели на редактирование 
 +                    project_model.UnlockWrite();​ 
 +                } 
 +            } 
 +        }
  
-Первый пункт - это поведение по умолчанию для любого файла включенного в проект,​ для которого не зарегестрирован редактор ​модели. Для реализации ​второго и третьего пункта предназначены два абстрактных классанаследника от [[developers:​references:​topomatic.applicationplatform.core.modeleditor|ModelEditor]] +        public override void Initialize(PluginFactory factory) 
-  * [[developers:​references:​topomatic.applicationplatform.core.documentmodeleditor|DocumentModelEditor]] - предназначен для ​создания видового экрана ​модели в отдельном окне +        { 
-  ​[[developers:​references:​topomatic.applicationplatform.core.documentmodeleditor|PlanModelEditor]] - предназначен для моделейотображающихся непосредственно на видовом экране окна плана+            base.Initialize(factory);​ 
 +            //Регестрируем ​нашу модель в проекте 
 +            factory.RegisterModelEditor("​testmodel"​,  
 +                new ModelEditorInfo("​Тестовая модель|*.testmodelx",​  
 +                ".testmodelx",​  
 +                "​testmodel",​  
 +                "Тестовая модель" 
 +                "​create_testmodel_editor"​));​ 
 +        } 
 +    } 
 +</​code>​
  
 +В файле .plugin нужно разместить нашу модель в секции [[developers:​references:​core.plugin:​cores|cores]] и добавить [[developers:​tutorial:​cmdattribute|команды]] для её редактирования и создания.
 +<code javascript>​
 +{
 +  "​assemblies":​ {
 +    "​tutorial6":​ {
 +      "​assembly":​ "​tutorial6.dll,​ tutorial6.ModulePluginHost"​
 +    }
 +  },
 +  "​actions":​ {
 +    "​id_create_testmodel":​ {
 +      "​cmd":​ "​create_testmodel \"​%0\"",​
 +      "​title":​ "​Тестовая модель"​
 +    },
 +    "​id_edit_testmodel":​ {
 +      "​cmd":​ "​edit_testmodel \"​%0\"",​
 +      "​title":​ "​Редактировать..."​
 +    }
 +  },
 +  "​contexts":​ {
 +    "​ctx_mkitem":​ {
 +      "​items":​ [
 +        "​id_create_testmodel \"​%0\""​
 +      ]
 +    },
 +    "​testmodel.context":​ {
 +      "​priority":​ 1001,
 +      "​items":​ [
 +        { "​default":​ "​$(if,​$(opened,​%0),​core.id_close \"​%0\"​ \"​Скрыть модель\",​core.id_open \"​%0\"​ \"​Показать модель\"​)"​ },
 +        "​id_edit_testmodel \"​%0\"",​
 +        "​-",​
 +        "​core.id_rmitem \"​%0\""​
 +      ]
 +    }
 +  },
 +  "​cores":​ {
 +    "​testmodel":​ {
 +      "​title":​ "​$(referencename,​%0)",​
 +      "​description":​ "​Тестовая модель %0",
 +      "​icon":​ "​ic_file",​
 +      "​statusicon":​ "",​
 +      "​flags":​ "​$(modelflags,​%0)",​
 +      "​menu":​ "​testmodel.context \"​%0\""​
 +    }
 +  }
 +}
 +</​code>​
 +Обратите внимание на секцию [[developers:​references:​core.plugin:​contexts|contexts]]. Для добавления возможности создать нашу тестовую модель из контекстного меню каталога проекта,​ мы добавляем функцию создания нашей модели в системное меню "​ctx_mkitem"​.
  
 +В результате мы получим возможность добавлять в проект наши тестовые модели и редактировать их содержимое по команде "​Редактировать"​ в контекстном меню модели.
 +{{ :​developers:​tutorial:​createmodel:​contexmenu.png?​direct&​600 |}}
  
 +<​note>​[[developers:​tutorial:​tutorialcode|Исходный код]] примера расположен в проекте **"​tutorial6"​**.</​note>​
developers/tutorial/createmodel.1550338706.txt.gz · Последние изменения: 2021/07/22 14:28 (внешнее изменение)