public override int Execute(params string[] parameters)
        {
            try
            {
                Document doc = Application.ActiveDocument;

                if (DataStorage == null)
                {
                    string initialPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                    string docFileName = doc.FileName;
                    if (!String.IsNullOrEmpty(docFileName))
                    {
                        initialPath = Path.GetDirectoryName(docFileName);
                    }


                    //выбрать два файла st.xml и cl.xml
                    WinForms.OpenFileDialog ofd1 = new WinForms.OpenFileDialog();
                    ofd1.InitialDirectory = initialPath;
                    ofd1.Filter           = ".st.xml files (*.st.xml)|*.st.xml";
                    ofd1.FilterIndex      = 1;
                    ofd1.RestoreDirectory = true;
                    ofd1.Title            = "Выберите файл структуры модели " + S1NF0_APP_NAME;

                    if (ofd1.ShowDialog() == WinForms.DialogResult.OK)
                    {
                        string stFilename = ofd1.FileName;
                        initialPath = Path.GetDirectoryName(stFilename);

                        WinForms.OpenFileDialog ofd2 = new WinForms.OpenFileDialog();
                        ofd2.InitialDirectory = initialPath;
                        ofd2.Filter           = ".cl.xml files (*.cl.xml)|*.cl.xml";
                        ofd2.FilterIndex      = 1;
                        ofd2.RestoreDirectory = true;
                        ofd2.Title            = "Выберите файл классификатора модели " + S1NF0_APP_NAME;

                        if (ofd2.ShowDialog() == WinForms.DialogResult.OK)
                        {
                            string clFilename = ofd2.FileName;

                            //Десериализовать
                            Structure structure = null;
                            using (StreamReader sr = new StreamReader(stFilename))
                            {
                                string serializedData = Common.Utils.RemoveInvalidXmlSubstrs(sr.ReadToEnd());

                                XmlSerializer xmlSerializer = new XmlSerializer(typeof(Structure));
                                StringReader  stringReader  = new StringReader(serializedData);
                                structure = (Structure)xmlSerializer.Deserialize(stringReader);
                            }

                            Classifier classifier = null;
                            using (StreamReader sr = new StreamReader(clFilename))
                            {
                                string serializedData = Common.Utils.RemoveInvalidXmlSubstrs(sr.ReadToEnd());

                                XmlSerializer xmlSerializer = new XmlSerializer(typeof(Classifier));
                                StringReader  stringReader  = new StringReader(serializedData);
                                classifier                   = (Classifier)xmlSerializer.Deserialize(stringReader);
                                classifier.ClassName         = classifier.Name;
                                classifier.DefaultClasses[0] = classifier.Name + "_DefaultFolder";
                                classifier.DefaultClasses[1] = classifier.Name + "_DefaultGeometry";
                            }

                            DataStorage = new StructureDataStorage(doc, stFilename, clFilename, structure, classifier);

                            startEditXML = true;
                        }
                    }
                }

                if (DataStorage != null)
                {
                    //StructureWindow structureWindow = new StructureWindow(DataStorage);
                    StructureWindow structureWindow = DataStorage.StructureWindow;
                    //Изучается набор выбора на наличие объектов геометрии
                    //Объекты геометрии передаются в свойство StructureWindow.SelectedGeometryModelItems
                    IEnumerable <ModelItem> geometryItems = null;
                    if (startEditXML)
                    {
                        //Для того, чтобы не увеличивать время ожидания при начале редактирования XML
                        //Принудительно настроить выбор объектов на те объекты, которые были не скрыты в начале редактирования
                        //doc.CurrentSelection.CopyFrom(DataStorage.AllItemsLookup.Values);//выглядит не очень красиво
                        doc.CurrentSelection.Clear();//Просто сбросить текущий выбор
                        geometryItems = DataStorage.AllItemsLookup.Values;
                        startEditXML  = false;
                    }
                    else
                    {
                        ModelItemCollection currSelectionColl = doc.CurrentSelection.SelectedItems;
                        int n = 50000;
                        //Проверит, что выбрано не более n конечных геометрических элементов
                        Search searchForAllIDs = new Search();
                        searchForAllIDs.Selection.CopyFrom(currSelectionColl);
                        searchForAllIDs.Locations = SearchLocations.DescendantsAndSelf;

                        StructureDataStorage.ConfigureSearchForAllGeometryItemsWithIds(searchForAllIDs);
                        ModelItemCollection selectedGeometry = searchForAllIDs.FindAll(doc, false);
                        int nSel = selectedGeometry.Count;
                        if (nSel > n)
                        {
                            doc.CurrentSelection.CopyFrom(selectedGeometry);
                            WinForms.DialogResult dialogResult = WinForms.MessageBox.Show("Вы выбрали очень большое количество конечных геометрических элементов - " + nSel
                                                                                          + ". Это приведет к большой задержке в работе программы. Продолжить?", "Предупреждение",
                                                                                          WinForms.MessageBoxButtons.YesNo, WinForms.MessageBoxIcon.Warning);
                            if (dialogResult == WinForms.DialogResult.No)
                            {
                                return(0);
                            }
                        }

                        #region Найти все конечные геометрические элементы с id с помощью Search API. Нельзя настроить на поиск только не скрытых элементов

                        /*
                         * Search searchForAllIDs = new Search();
                         * searchForAllIDs.Selection.CopyFrom(currSelectionColl);
                         * searchForAllIDs.Locations = SearchLocations.DescendantsAndSelf;
                         *
                         * DataStorage.ConfigureSearchForAllNotHiddenGeometryItemsWithIds(searchForAllIDs);
                         * ModelItemCollection selectedGeometry = searchForAllIDs.FindAll(doc, false);
                         *
                         *
                         * if (!DataStorage.AllNotHiddenGeometryModelItems.IsSelected(selectedGeometry))
                         * {
                         *  WinForms.MessageBox.Show("Выбраны объекты, которые были скрыты при начале редактирования XML");
                         *  return 0;
                         * }
                         *
                         *
                         * List<ModelItem> geometryItems = new List<ModelItem>();
                         * selectedGeometry.CopyTo(geometryItems);//ЗДЕСЬ БУДЕТ ЗАДЕРЖКА
                         * //foreach (ModelItem item in selectedGeometry)
                         * //{
                         * //    geometryItems.Add(item);
                         * //}
                         */
                        #endregion


                        //Начать поиск элементов с id
                        currSelectionColl = new ModelItemCollection(currSelectionColl);
                        currSelectionColl.MakeDisjoint();//Убрать все вложенные объекты
                        geometryItems = new List <ModelItem>();
                        RecurseSearchForAllNotHiddenGeometryItemsWithIdsContainedInBaseLookup
                            (currSelectionColl, (List <ModelItem>)geometryItems, DataStorage.AllItemsLookup);
                    }



                    structureWindow.SelectedGeometryModelItems = geometryItems;
                    //Открывается окно StructureWindow
                    structureWindow.BeforeShow();
                    structureWindow.ShowDialog();
                }
            }
            catch (Exception ex)
            {
                CommonException(ex, "Ошибка при задании файла структуры " + S1NF0_APP_NAME);
            }

            return(0);
        }
        public StructureDataStorage(Document doc, string stPath, string clPath, Structure structure,
                                    Classifier classifier, bool newStructureCreationBySelSets = false, List <string> propCategories = null)
        {
            this.doc        = doc;
            this.stPath     = stPath;
            this.clPath     = clPath;
            this.oState     = ComApiBridge.ComApiBridge.State;
            this.Structure  = structure;
            this.Classifier = classifier;

            if (propCategories != null)
            {
                this.propCategories = propCategories;
            }

            //Все новые классы будут создаваться на 2 DetailLevel. 1 - папки, 2 - конечные элементы
            //(это относится только к вновь создаваемым объектам)
            //Значит должно быть 2 класса без свойств. 1 - для папок, второй для конечных элементов!

            //если уровней меньше, чем должно быть, то нужно добавить недостающие
            for (int i = classifier.DetailLevels.Count; i < DefDetailLevels.Length; i++)
            {
                classifier.DetailLevels.Add(DefDetailLevels[i]);
            }

            DefDetailLevels[0] = classifier.DetailLevels[0];
            DefDetailLevels[1] = classifier.DetailLevels[1];
            foreach (string lvlName in DefDetailLevels)
            {
                if (String.IsNullOrWhiteSpace(lvlName))
                {
                    throw new Exception("DetailLevel должен быть не пустой строкой");
                }
            }

            //Построить словари для быстрого поиска классов
            foreach (Class c in classifier.NestedClasses)
            {
                SurveyClass(c);
            }

            //Всегда должны быть заданы все необходимые DefaultClass (сейчас их 2 - для папок и для конечных элементов)
            for (int i = 0; i < DefClassesWithNoProps.Length; i++)
            {
                if (DefClassesWithNoProps[i] == null)
                {
                    DefClassesWithNoProps[i] = CreateNewClass(Classifier.DefaultClasses[i] /*DEFAULT_CLASS_NAME[i]*/,
                                                              Classifier.DefaultClasses[i] /*DEFAULT_CLASS_NAME_IN_PLURAL[i]*/, i);
                }
            }

            #region Поиск всех объектов геометрии с id с помощью Search API. Нельзя настроить на поиск только не скрытых элементов

            /*
             *  //Все объекты модели геометрии с id
             *  Search searchForAllIDs = new Search();
             *  searchForAllIDs.Selection.SelectAll();
             *  //searchForIDs.PruneBelowMatch = false;
             *
             *  ConfigureSearchForAllNotHiddenGeometryItemsWithIds(searchForAllIDs);
             *
             *  //ModelItemCollection allModelItemCollection;
             *  AllNotHiddenGeometryModelItems = searchForAllIDs.FindAll(doc, false);
             *
             *  int n = AllNotHiddenGeometryModelItems.Count;
             *
             *
             *  //Сформировать объект Search для поиска конкретного значения Id. МНОГОКРАТНЫЙ ПОИСК РАБОТАЕТ МЕДЛЕННО
             *  //searchForCertainID = new Search();
             *  //searchForCertainID.Selection.CopyFrom(allModelItemCollection);
             *  //searchForCertainIDCondition = new SearchCondition(tabCN, idCN, SearchConditionOptions.None, SearchConditionComparison.Equal, new VariantData());
             *
             *  //ПОЧЕМУ-ТО ОБХОД ОБЪЕКТОВ ПРОИСХОДИТ ОЧЕНЬ МЕДЛЕННО НА БОЛЬЩИХ МОДЕЛЯХ
             *  //Поэтому у пользователя есть возможность скрыть часть модели, чтобы не загружать ее всю в словарь за один раз
             *  allItemsLookup = new Dictionary<string, ModelItem>();
             *  foreach (ModelItem item in AllNotHiddenGeometryModelItems)
             *  {
             *      DataProperty idProp = item.PropertyCategories
             *                      .FindPropertyByDisplayName(S1NF0_DATA_TAB_DISPLAY_NAME,
             *                      ID_PROP_DISPLAY_NAME);
             *      string key = Utils.GetDisplayValue(idProp.Value);
             *      allItemsLookup[key] = item;
             *  }
             */
            #endregion

            //Обход всей модели через рекурсию НЕ БЫСТРЕЕ. Но можно искать только не скрытые элементы
            if (!newStructureCreationBySelSets)//если структура создается с нуля, то этот шаг не нужен!
            {
                AllItemsLookup = new Dictionary <string, ModelItem>();
                RecurseSearchForAllNotHiddenGeometryItemsWithIds(doc.Models.RootItems, AllItemsLookup);

                //Обход всех объектов
                //Просмотреть все объекты, не имеющие вложенных. Какие из них уже присутствуют в документе?
                //Построить словарь для быстрого поиска объектов, уже добавленных в дерево
                List <XML.St.Object> nestedObjectsValid; List <XML.St.Object> geometryObjectsCurrDoc;
                List <XML.St.Object> geometryObjectsOtherDoc; List <XML.St.Object> displayObjects;
                List <XML.St.Object> resetObjects;
                SurveyNestedObjects(structure.NestedObjects,
                                    out nestedObjectsValid, out geometryObjectsCurrDoc,
                                    out geometryObjectsOtherDoc, out displayObjects, out resetObjects);
                structure.NestedObjects = nestedObjectsValid;

                //Если какие-то объекты уже присутствуют в дереве, то уточнить набор свойств и класс для них согласно модели Navis
                foreach (XML.St.Object o in AddedGeometryItemsLookUp.Values)
                {
                    PropertyCategoryCollection categories = o.NavisItem.PropertyCategories;

                    SetObjectProps(o, categories, 1, 1);
                }

                //Создать окно и заполнить TreeView.
                StructureWindow = new StructureWindow(this);
            }
        }