Статьи > Тестирование статей
Аналог панели свойств
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; } } } }
Навигация
Перейти к полной версии