Статьи > Тестирование статей

Аналог панели свойств

(1/2) > >>

alz:
В связи с тем, что через .net нет возможности добавлять свои данные в стандартную панель свойств, та и делать было особо нечего, решил написать свой аналог, ну и заодно хоть немного разобраться в wpf.

Визуально постарался сделать панель аналогично стандартной, и вроде как получилось даже похоже


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

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

alz:
При создании панели вылез вопрос, а в какие цвета ее красить, советы с пипеткой из фотошопа или чего-то подобного не очень вдохновили, та и в группе телеграмма подсказали что в автокаде есть папка Themes, поэтому решил пойти через нее, в ней оказалось несколько файлов .xbel, которые оказались обычными xml, после чего просто решил их расшифровать и вытащить цвета уже из них, в принципе получилось, поэтому в зависимости от цветовой темы автокада панель раскрашивается соответствующими цветами из файлов тем, ну и для определения того, какой же цвет чему соответствует написал небольшое окошко, которое выводит попарно цвета с их названиями из соответствующих файлов, так как определить по названиям, какому элементу соответствует данный цвет лично мне было невозможно, а в таком наглядном виде стало гораздо проще

alz:
В принципе все стандартные возможности - реализованы, в панель можно вывести какие-либо параметры, в ней их можно отредактировать и соответственно изменить объекты в чертеже. В графу значения параметра можно поместить:
1) простое текстовое или числовое значение

2) сложный элемент, состоящий из каких-то графических примитивов вместе со значением параметра (пока что реализовано добавление объектов Border и Path)

3) группу значений для возможного выбора

4) запуск дополнительных методов по выбору каких либо параметров

alz:
Как добавить в нее дополнительные свойства
1) создаем проект, в ссылках добавляем библиотеку панели, так как в автокад она будет подгружаться отдельно, что бы не грузить с каждым проектом, ставим значение Копировать локально - false
Основой для нашего проекта служит класс SelectedDataClass

--- Код - C# [Выбрать] ---using Autodesk.AutoCAD.DatabaseServices;using System.Collections.Generic;using System.Linq; namespace PaletteProperties{    /// <summary>    /// Класс хранящий в себе метод получения нужных параметров и методы их изменения    /// для использования требуется создать наследник данного класса, и переопределить методы получения и редактирования параметров    /// </summary>    public abstract class SelectedDataClass : object    {        /// <summary>        /// название, используется для идентификации класса в панели настроек        /// </summary>        public string Name { get; set; }        /// <summary>        /// Маркер изменения, определяет надо ли изменять что-то в данной группе параметров        /// </summary>        public bool ChangeNeed { get; set; } = false;        /// <summary>        /// точность округления double значений        /// </summary>        public int Preсision { get; set; } = 3;          /// <summary>        /// Выпрлняет действия перед получением параметров        /// </summary>        public virtual void PreAcadUpdateAction()        {        }         /// <summary>        /// Выполняет действия после получения объединения параметров, изменяет полученные объединенные параметры        /// </summary>        /// <param name="property">Параметр, через который вызывается метод</param>        public virtual void AfterUnitedAction(UnitedProperty property, List<UnitedProperty> properties)        {        }        /// <summary>        /// получение параметров        /// </summary>        /// <param name="e"></param>        /// <param name="o"></param>        /// <returns></returns>        public virtual List<Property> GetProperties(Entity e, Object o)        {            return new List<Property>();        }        /// <summary>        /// изменение параметров        /// </summary>        /// <param name="e"></param>        /// <param name="properties"></param>        public virtual void SetProperties(Entity e, List<Property> properties)        {        }        /// <summary>        /// Действие, вызываемое одним из вариантов при выборе свойства из комбобокса        /// </summary>          /// <param name="property">Вызывающий параметр</param>        public virtual bool Action(Property property)        {            return false;        }        /// <summary>        /// Действие, вызываемое одним из вариантов при выборе свойства из комбобокса, возвращает какой либо объект        /// </summary>          /// <param name="property">Вызывающий параметр</param>        public virtual object ResultAction(Property property)        {            return null;        }        /// <summary>        /// список параметров, с флагом отображения в панели        /// </summary>        public Dictionary<string, bool> AllProperties { get; set; } = new Dictionary<string, bool>();        /// <summary>        /// проверяет, нужно ли считывать хоть один из параметров        /// </summary>        /// <returns></returns>        public bool CheckPropertyes()        {            if (AllProperties.Values.ToList().Contains(true)) return true;            return false;                }    } } 
2) создаем класс, наследник класса SelectedDataClass, через него мы и будем добавлять свои параметры, даем название своей группе параметров и добавляем эти параметры в словарь AllProperties, в значениях словарей булевый параметр отвечает за то, будет ли отображаться данный параметр в панели, изменяется он через панель параметров, и сохраняет значения пользователя в xml файле рядом с библиотекой палитры.


--- Код - C# [Выбрать] ---    public class CurvePropertiesDataClass : SelectedDataClass    {         public CurvePropertiesDataClass()        {            Name = "Данные кривых";            AllProperties = new Dictionary<string, bool>            {                { "Замкнуто", true },                { "Угол", true },                { "Вертикальный угол", true },                { "Толщина", true },                { "Уровень", true },                { "Длина", true },                { "Длина (сумма)", true },                { "Площадь", true },                { "Площадь (сумма)", true },            };        }    }3) переопределяем нужные методы:
а) метод, вызывается перед получением данных из автокада, в нем я обычно определяю требуемую точность округления параметров, например
определение точности в автокаде

--- Код - C# [Выбрать] ---        public override void PreAcadUpdateAction()        {            object luprec = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("LUPREC");             if (luprec != null && int.TryParse(luprec.ToString(), out int result))            {                Preсision = result;            }           }определение точности высот в цивиле

--- Код - C# [Выбрать] ---        public override void PreAcadUpdateAction()        {                     Preсision = Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument.Settings.DrawingSettings.AmbientSettings.Elevation.Precision.Value;        }б) собственно само считывание нужных параметров, возвратить мы должны список классов Property, в которые мы и запишем нужные параметры, в этот метод передается класс объекта, для возможности переименования нужного объекта, по умолчанию в названии пишется название класса

--- Код - C# [Выбрать] ---    public class Object    {        public Object(ObjectId id)        {            ObjectId = id;            Name = id.ObjectClass.Name;            ClassName = id.ObjectClass.Name;        }        public string Name { get; set; }        public string ClassName { get; set; }        public ObjectId ObjectId { get; }        public List<Property> Properties { get; set; } = new List<Property>();    }и собтсвенно сам объект автокада как сущность Entity, с которой мы и должны считать нужные параметры, как на примере ниже, в полях параметра можно установить различные флаги, что параметр только для чтения, что аналогичные параметры должны суммироваться, что при выборе этого параметра надо сделать какой-либо действие и тд, из основного, параметру надо дать название, соответствующее добавленному в AllProperties, считанное значение, и наш класс в поле Parent.
       
--- Код - C# [Выбрать] ---public override List<Property> GetProperties(ADB.Entity e, PaletteProperties.Object o)       {           List<Property> properties = new List<Property>();                      if (e is Curve curve && curve.IsAcadCurve())           {               if (o != null && o.Name == o.ClassName)               {                   if (e is Line) o.Name = "Отрезок";                   else if (e is Polyline) o.Name = "Полилиния";                   else if (e is Circle) o.Name = "Круг";                   else if (e is Ellipse) o.Name = "Эллипс";                   else if (e is Arc) o.Name = "Дуга";                   else if (e is Spline) o.Name = "Сплайн";                   else if (e is Polyline3d) o.Name = "3dПолилиния";               }                if (e is Line l && (AllProperties["Угол"] || AllProperties["Вертикальный угол"]))               {                   double angle = 0;                   double vAngle = 0;                   Vector3d direction = (l.EndPoint - l.StartPoint).GetNormal();                   Vector3d proj = new Vector3d(direction.X, direction.Y, 0);                   if (proj.IsZeroLength()) proj = Vector3d.XAxis;                   if (!direction.IsZeroLength())                   {                       angle = Vector3d.XAxis.GetAngleTo(proj, Vector3d.ZAxis) * 180 / Math.PI;                       if (direction.Z != 0)                       {                                                  Vector3d rotDir = proj.TransformBy(Matrix3d.Rotation(-Math.PI / 2, Vector3d.ZAxis, Point3d.Origin));                           vAngle = proj.GetAngleTo(direction, rotDir) * 180 / Math.PI;                       }                     }                   if (AllProperties["Угол"]) properties.Add(new Property("Угол", angle, false, this) { Group = "Параметры" });                   if (AllProperties["Вертикальный угол"]) properties.Add(new Property("Вертикальный угол", vAngle, false, this) { Group = "Параметры" });               }                if (AllProperties["Длина"] || AllProperties["Длина (сумма)"])               {                   double length = curve.GetLength();                   if (AllProperties["Длина"])                   {                       if (e is Line || e is Circle) properties.Add(new Property("Длина", length, false, this) { Group = "Геометрия" });                       else properties.Add(new Property("Длина", length, true, this) { Group = "Геометрия" });                   }                                              if (AllProperties["Длина (сумма)"]) properties.Add(new Property("Длина (сумма)", length, true, this) { Group = "Геометрия", IsSum = true });               }                if (AllProperties["Площадь"] || AllProperties["Площадь (сумма)"])               {                   double area = 0;                   bool error = false;                   try                   {                       area = curve.Area;                   }                   catch                   {                       error = true;                   }                   if (AllProperties["Площадь"]) properties.Add(new Property("Площадь", area, true, this) { Group = "Геометрия", Error = error });                   if (AllProperties["Площадь (сумма)"]) properties.Add(new Property("Площадь (сумма)", area, true, this) { Group = "Геометрия", IsSum = true, Error = error });               }                  }           return properties;       }В принципе это все, что требуется, для вывода каких либо данных в панель.
3) Для того, что бы данные из нашего нового класса пошли в панель нам требуется подгрузить наш класс, для этого делаем небольшой класс, который автоматически загрузит данные


--- Код - C# [Выбрать] ---using Autodesk.AutoCAD.Runtime;using PaletteProperties;using System; namespace CurveProperties{    public class AddPalette : IExtensionApplication    {        public void Initialize()        {            //подписываемся на момент полной загрузки автокада,            //что бы подгружать наш класс точно после того, как загрузится основная библиотека            Autodesk.AutoCAD.ApplicationServices.Core.Application.Idle += Wait;        }        public void Terminate() { }        private static void Wait(object sender, EventArgs e)        {            if (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager != null)            {                //отписываемся                Autodesk.AutoCAD.ApplicationServices.Core.Application.Idle -= Wait;                //подгружаем в панель наш класс                CreatePaletteClass.Create(new CurvePropertiesDataClass());            }        }    }}

alz:
Что бы изменить данные после изменения в панели требуется переопределить метод SetProperties, который вернет список наших параметров, в переданных параметрах нас интересует 2 значения, первое это флаг property.Change, который показывает был ли изменен параметр в панели и property.NewValue, в котором записано новое значение параметра, соответственно сначала проверяем требуется ли изменять, и если да то присваиваем новое значение переданному объекту

       
--- Код - C# [Выбрать] --- public override void SetProperties(ADB.Entity e, List<Property> properties)        {                        foreach (Property property in properties)            {                if (!property.Change) continue;                 property.Change = false;                 switch (property.Name)                {                                      case "Длина":                        {                            if (property.NewValue is double d)                            {                                if (e is Line l)                                {                                                                       Vector3d direction = (l.EndPoint - l.StartPoint).GetNormal();                                    if (direction.IsZeroLength()) direction = Vector3d.XAxis;                                     l.EndPoint = l.StartPoint + direction * d;                                }                                else if (e is Circle c)                                {                                    c.Radius = d / (2 * Math.PI);                                }                            }                            break;                        }                    case "Угол":                        {                            if (property.NewValue is double d && e is Line l)                            {                                while (d > 360) d -= 360;                                while (d < 0) d += 360;                                 d = d * Math.PI / 180;                                 double angle = 0;                                 Vector3d direction = l.EndPoint - l.StartPoint;                                if (!direction.IsZeroLength())                                {                                    angle = Vector3d.XAxis.GetAngleTo(new Vector3d(direction.X, direction.Y, 0), Vector3d.ZAxis);                                }                                 d -= angle;                                 l.TransformBy(Matrix3d.Rotation(d, Vector3d.ZAxis, l.StartPoint));                            }                            break;                        }                    case "Вертикальный угол":                        {                            if (property.NewValue is double d && e is Line l)                            {                                while (d > 360) d -= 360;                                while (d < 0) d += 360;                                 d = d * Math.PI / 180;                                 double vAngle = 0;                                 Vector3d direction = l.EndPoint - l.StartPoint;                                Vector3d proj;                                Vector3d rotDir = -Vector3d.YAxis;                                if (!direction.IsZeroLength())                                {                                    proj = new Vector3d(direction.X, direction.Y, 0);                                    if (proj.IsZeroLength()) proj = Vector3d.XAxis;                                    rotDir = proj.TransformBy(Matrix3d.Rotation(-Math.PI / 2, Vector3d.ZAxis, Point3d.Origin));                                    vAngle = proj.GetAngleTo(direction, rotDir);                                                                   }                                 d -= vAngle;                                 l.TransformBy(Matrix3d.Rotation(d, rotDir, l.StartPoint));                            }                            break;                        }                                          }            }                    }

Навигация

[0] Главная страница сообщений

[#] Следующая страница

Перейти к полной версии