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

Автор Тема: Аналог панели свойств  (Прочитано 837 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн alzАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 108
  • Карма: 12
Аналог панели свойств
« : 02-01-2025, 19:47:04 »
В связи с тем, что через .net нет возможности добавлять свои данные в стандартную панель свойств, та и делать было особо нечего, решил написать свой аналог, ну и заодно хоть немного разобраться в wpf.

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


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

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

Оффлайн alzАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 108
  • Карма: 12
Re: Аналог панели свойств
« Ответ #1 : 02-01-2025, 19:57:59 »
При создании панели вылез вопрос, а в какие цвета ее красить, советы с пипеткой из фотошопа или чего-то подобного не очень вдохновили, та и в группе телеграмма подсказали что в автокаде есть папка Themes, поэтому решил пойти через нее, в ней оказалось несколько файлов .xbel, которые оказались обычными xml, после чего просто решил их расшифровать и вытащить цвета уже из них, в принципе получилось, поэтому в зависимости от цветовой темы автокада панель раскрашивается соответствующими цветами из файлов тем, ну и для определения того, какой же цвет чему соответствует написал небольшое окошко, которое выводит попарно цвета с их названиями из соответствующих файлов, так как определить по названиям, какому элементу соответствует данный цвет лично мне было невозможно, а в таком наглядном виде стало гораздо проще


Оффлайн alzАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 108
  • Карма: 12
Re: Аналог панели свойств
« Ответ #2 : 02-01-2025, 20:09:45 »
В принципе все стандартные возможности - реализованы, в панель можно вывести какие-либо параметры, в ней их можно отредактировать и соответственно изменить объекты в чертеже. В графу значения параметра можно поместить:
1) простое текстовое или числовое значение

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

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

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


Оффлайн alzАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 108
  • Карма: 12
Re: Аналог панели свойств
« Ответ #3 : 02-01-2025, 20:46:28 »
Как добавить в нее дополнительные свойства
1) создаем проект, в ссылках добавляем библиотеку панели, так как в автокад она будет подгружаться отдельно, что бы не грузить с каждым проектом, ставим значение Копировать локально - false
Основой для нашего проекта служит класс SelectedDataClass
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5. namespace PaletteProperties
  6. {
  7.     /// <summary>
  8.     /// Класс хранящий в себе метод получения нужных параметров и методы их изменения
  9.     /// для использования требуется создать наследник данного класса, и переопределить методы получения и редактирования параметров
  10.     /// </summary>
  11.     public abstract class SelectedDataClass : object
  12.     {
  13.         /// <summary>
  14.         /// название, используется для идентификации класса в панели настроек
  15.         /// </summary>
  16.         public string Name { get; set; }
  17.         /// <summary>
  18.         /// Маркер изменения, определяет надо ли изменять что-то в данной группе параметров
  19.         /// </summary>
  20.         public bool ChangeNeed { get; set; } = false;
  21.         /// <summary>
  22.         /// точность округления double значений
  23.         /// </summary>
  24.         public int Preсision { get; set; } = 3;
  25.  
  26.         /// <summary>
  27.         /// Выпрлняет действия перед получением параметров
  28.         /// </summary>
  29.         public virtual void PreAcadUpdateAction()
  30.         {
  31.         }
  32.  
  33.         /// <summary>
  34.         /// Выполняет действия после получения объединения параметров, изменяет полученные объединенные параметры
  35.         /// </summary>
  36.         /// <param name="property">Параметр, через который вызывается метод</param>
  37.         public virtual void AfterUnitedAction(UnitedProperty property, List<UnitedProperty> properties)
  38.         {
  39.         }
  40.         /// <summary>
  41.         /// получение параметров
  42.         /// </summary>
  43.         /// <param name="e"></param>
  44.         /// <param name="o"></param>
  45.         /// <returns></returns>
  46.         public virtual List<Property> GetProperties(Entity e, Object o)
  47.         {
  48.             return new List<Property>();
  49.         }
  50.         /// <summary>
  51.         /// изменение параметров
  52.         /// </summary>
  53.         /// <param name="e"></param>
  54.         /// <param name="properties"></param>
  55.         public virtual void SetProperties(Entity e, List<Property> properties)
  56.         {
  57.         }
  58.         /// <summary>
  59.         /// Действие, вызываемое одним из вариантов при выборе свойства из комбобокса
  60.         /// </summary>  
  61.         /// <param name="property">Вызывающий параметр</param>
  62.         public virtual bool Action(Property property)
  63.         {
  64.             return false;
  65.         }
  66.         /// <summary>
  67.         /// Действие, вызываемое одним из вариантов при выборе свойства из комбобокса, возвращает какой либо объект
  68.         /// </summary>  
  69.         /// <param name="property">Вызывающий параметр</param>
  70.         public virtual object ResultAction(Property property)
  71.         {
  72.             return null;
  73.         }
  74.         /// <summary>
  75.         /// список параметров, с флагом отображения в панели
  76.         /// </summary>
  77.         public Dictionary<string, bool> AllProperties { get; set; } = new Dictionary<string, bool>();
  78.         /// <summary>
  79.         /// проверяет, нужно ли считывать хоть один из параметров
  80.         /// </summary>
  81.         /// <returns></returns>
  82.         public bool CheckPropertyes()
  83.         {
  84.             if (AllProperties.Values.ToList().Contains(true)) return true;
  85.             return false;        
  86.         }
  87.     }
  88.  
  89. }
  90.  

2) создаем класс, наследник класса SelectedDataClass, через него мы и будем добавлять свои параметры, даем название своей группе параметров и добавляем эти параметры в словарь AllProperties, в значениях словарей булевый параметр отвечает за то, будет ли отображаться данный параметр в панели, изменяется он через панель параметров, и сохраняет значения пользователя в xml файле рядом с библиотекой палитры.

Код - C# [Выбрать]
  1.     public class CurvePropertiesDataClass : SelectedDataClass
  2.     {
  3.  
  4.         public CurvePropertiesDataClass()
  5.         {
  6.             Name = "Данные кривых";
  7.             AllProperties = new Dictionary<string, bool>
  8.             {
  9.                 { "Замкнуто", true },
  10.                 { "Угол", true },
  11.                 { "Вертикальный угол", true },
  12.                 { "Толщина", true },
  13.                 { "Уровень", true },
  14.                 { "Длина", true },
  15.                 { "Длина (сумма)", true },
  16.                 { "Площадь", true },
  17.                 { "Площадь (сумма)", true },
  18.             };
  19.         }
  20.     }
3) переопределяем нужные методы:
а) метод, вызывается перед получением данных из автокада, в нем я обычно определяю требуемую точность округления параметров, например
определение точности в автокаде
Код - C# [Выбрать]
  1.         public override void PreAcadUpdateAction()
  2.         {
  3.             object luprec = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("LUPREC");
  4.  
  5.             if (luprec != null && int.TryParse(luprec.ToString(), out int result))
  6.             {
  7.                 Preсision = result;
  8.             }  
  9.         }
определение точности высот в цивиле
Код - C# [Выбрать]
  1.         public override void PreAcadUpdateAction()
  2.         {        
  3.             Preсision = Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument.Settings.DrawingSettings.AmbientSettings.Elevation.Precision.Value;
  4.         }
б) собственно само считывание нужных параметров, возвратить мы должны список классов Property, в которые мы и запишем нужные параметры, в этот метод передается класс объекта, для возможности переименования нужного объекта, по умолчанию в названии пишется название класса
Код - C# [Выбрать]
  1.     public class Object
  2.     {
  3.         public Object(ObjectId id)
  4.         {
  5.             ObjectId = id;
  6.             Name = id.ObjectClass.Name;
  7.             ClassName = id.ObjectClass.Name;
  8.         }
  9.         public string Name { get; set; }
  10.         public string ClassName { get; set; }
  11.         public ObjectId ObjectId { get; }
  12.         public List<Property> Properties { get; set; } = new List<Property>();
  13.     }
и собтсвенно сам объект автокада как сущность Entity, с которой мы и должны считать нужные параметры, как на примере ниже, в полях параметра можно установить различные флаги, что параметр только для чтения, что аналогичные параметры должны суммироваться, что при выборе этого параметра надо сделать какой-либо действие и тд, из основного, параметру надо дать название, соответствующее добавленному в AllProperties, считанное значение, и наш класс в поле Parent.
       
Код - C# [Выбрать]
  1. public override List<Property> GetProperties(ADB.Entity e, PaletteProperties.Object o)
  2.        {
  3.            List<Property> properties = new List<Property>();
  4.            
  5.            if (e is Curve curve && curve.IsAcadCurve())
  6.            {
  7.                if (o != null && o.Name == o.ClassName)
  8.                {
  9.                    if (e is Line) o.Name = "Отрезок";
  10.                    else if (e is Polyline) o.Name = "Полилиния";
  11.                    else if (e is Circle) o.Name = "Круг";
  12.                    else if (e is Ellipse) o.Name = "Эллипс";
  13.                    else if (e is Arc) o.Name = "Дуга";
  14.                    else if (e is Spline) o.Name = "Сплайн";
  15.                    else if (e is Polyline3d) o.Name = "3dПолилиния";
  16.                }
  17.  
  18.                if (e is Line l && (AllProperties["Угол"] || AllProperties["Вертикальный угол"]))
  19.                {
  20.                    double angle = 0;
  21.                    double vAngle = 0;
  22.                    Vector3d direction = (l.EndPoint - l.StartPoint).GetNormal();
  23.                    Vector3d proj = new Vector3d(direction.X, direction.Y, 0);
  24.                    if (proj.IsZeroLength()) proj = Vector3d.XAxis;
  25.                    if (!direction.IsZeroLength())
  26.                    {
  27.                        angle = Vector3d.XAxis.GetAngleTo(proj, Vector3d.ZAxis) * 180 / Math.PI;
  28.                        if (direction.Z != 0)
  29.                        {                      
  30.                            Vector3d rotDir = proj.TransformBy(Matrix3d.Rotation(-Math.PI / 2, Vector3d.ZAxis, Point3d.Origin));
  31.                            vAngle = proj.GetAngleTo(direction, rotDir) * 180 / Math.PI;
  32.                        }  
  33.                    }
  34.                    if (AllProperties["Угол"]) properties.Add(new Property("Угол", angle, false, this) { Group = "Параметры" });
  35.                    if (AllProperties["Вертикальный угол"]) properties.Add(new Property("Вертикальный угол", vAngle, false, this) { Group = "Параметры" });
  36.                }
  37.  
  38.                if (AllProperties["Длина"] || AllProperties["Длина (сумма)"])
  39.                {
  40.                    double length = curve.GetLength();
  41.                    if (AllProperties["Длина"])
  42.                    {
  43.                        if (e is Line || e is Circle) properties.Add(new Property("Длина", length, false, this) { Group = "Геометрия" });
  44.                        else properties.Add(new Property("Длина", length, true, this) { Group = "Геометрия" });
  45.                    }    
  46.                        
  47.                    if (AllProperties["Длина (сумма)"]) properties.Add(new Property("Длина (сумма)", length, true, this) { Group = "Геометрия", IsSum = true });
  48.                }
  49.  
  50.                if (AllProperties["Площадь"] || AllProperties["Площадь (сумма)"])
  51.                {
  52.                    double area = 0;
  53.                    bool error = false;
  54.                    try
  55.                    {
  56.                        area = curve.Area;
  57.                    }
  58.                    catch
  59.                    {
  60.                        error = true;
  61.                    }
  62.                    if (AllProperties["Площадь"]) properties.Add(new Property("Площадь", area, true, this) { Group = "Геометрия", Error = error });
  63.                    if (AllProperties["Площадь (сумма)"]) properties.Add(new Property("Площадь (сумма)", area, true, this) { Group = "Геометрия", IsSum = true, Error = error });
  64.                }      
  65.            }
  66.            return properties;
  67.        }
В принципе это все, что требуется, для вывода каких либо данных в панель.
3) Для того, что бы данные из нашего нового класса пошли в панель нам требуется подгрузить наш класс, для этого делаем небольшой класс, который автоматически загрузит данные

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.Runtime;
  2. using PaletteProperties;
  3. using System;
  4.  
  5. namespace CurveProperties
  6. {
  7.     public class AddPalette : IExtensionApplication
  8.     {
  9.         public void Initialize()
  10.         {
  11.             //подписываемся на момент полной загрузки автокада,
  12.             //что бы подгружать наш класс точно после того, как загрузится основная библиотека
  13.             Autodesk.AutoCAD.ApplicationServices.Core.Application.Idle += Wait;
  14.         }
  15.         public void Terminate() { }
  16.         private static void Wait(object sender, EventArgs e)
  17.         {
  18.             if (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager != null)
  19.             {
  20.                 //отписываемся
  21.                 Autodesk.AutoCAD.ApplicationServices.Core.Application.Idle -= Wait;
  22.                 //подгружаем в панель наш класс
  23.                 CreatePaletteClass.Create(new CurvePropertiesDataClass());
  24.             }
  25.         }
  26.     }
  27. }

Оффлайн alzАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 108
  • Карма: 12
Re: Аналог панели свойств
« Ответ #4 : 02-01-2025, 20:53:40 »
Что бы изменить данные после изменения в панели требуется переопределить метод SetProperties, который вернет список наших параметров, в переданных параметрах нас интересует 2 значения, первое это флаг property.Change, который показывает был ли изменен параметр в панели и property.NewValue, в котором записано новое значение параметра, соответственно сначала проверяем требуется ли изменять, и если да то присваиваем новое значение переданному объекту

       
Код - C# [Выбрать]
  1.  public override void SetProperties(ADB.Entity e, List<Property> properties)
  2.         {            
  3.             foreach (Property property in properties)
  4.             {
  5.                 if (!property.Change) continue;
  6.  
  7.                 property.Change = false;
  8.  
  9.                 switch (property.Name)
  10.                 {                  
  11.                     case "Длина":
  12.                         {
  13.                             if (property.NewValue is double d)
  14.                             {
  15.                                 if (e is Line l)
  16.                                 {
  17.                                    
  18.                                     Vector3d direction = (l.EndPoint - l.StartPoint).GetNormal();
  19.                                     if (direction.IsZeroLength()) direction = Vector3d.XAxis;
  20.  
  21.                                     l.EndPoint = l.StartPoint + direction * d;
  22.                                 }
  23.                                 else if (e is Circle c)
  24.                                 {
  25.                                     c.Radius = d / (2 * Math.PI);
  26.                                 }
  27.                             }
  28.                             break;
  29.                         }
  30.                     case "Угол":
  31.                         {
  32.                             if (property.NewValue is double d && e is Line l)
  33.                             {
  34.                                 while (d > 360) d -= 360;
  35.                                 while (d < 0) d += 360;
  36.  
  37.                                 d = d * Math.PI / 180;
  38.  
  39.                                 double angle = 0;
  40.  
  41.                                 Vector3d direction = l.EndPoint - l.StartPoint;
  42.                                 if (!direction.IsZeroLength())
  43.                                 {
  44.                                     angle = Vector3d.XAxis.GetAngleTo(new Vector3d(direction.X, direction.Y, 0), Vector3d.ZAxis);
  45.                                 }
  46.  
  47.                                 d -= angle;
  48.  
  49.                                 l.TransformBy(Matrix3d.Rotation(d, Vector3d.ZAxis, l.StartPoint));
  50.                             }
  51.                             break;
  52.                         }
  53.                     case "Вертикальный угол":
  54.                         {
  55.                             if (property.NewValue is double d && e is Line l)
  56.                             {
  57.                                 while (d > 360) d -= 360;
  58.                                 while (d < 0) d += 360;
  59.  
  60.                                 d = d * Math.PI / 180;
  61.  
  62.                                 double vAngle = 0;
  63.  
  64.                                 Vector3d direction = l.EndPoint - l.StartPoint;
  65.                                 Vector3d proj;
  66.                                 Vector3d rotDir = -Vector3d.YAxis;
  67.                                 if (!direction.IsZeroLength())
  68.                                 {
  69.                                     proj = new Vector3d(direction.X, direction.Y, 0);
  70.                                     if (proj.IsZeroLength()) proj = Vector3d.XAxis;
  71.                                     rotDir = proj.TransformBy(Matrix3d.Rotation(-Math.PI / 2, Vector3d.ZAxis, Point3d.Origin));
  72.                                     vAngle = proj.GetAngleTo(direction, rotDir);                                  
  73.                                 }
  74.  
  75.                                 d -= vAngle;
  76.  
  77.                                 l.TransformBy(Matrix3d.Rotation(d, rotDir, l.StartPoint));
  78.                             }
  79.                             break;
  80.                         }
  81.          
  82.                
  83.  
  84.                 }
  85.             }            
  86.         }

Оффлайн alzАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 108
  • Карма: 12
Re: Аналог панели свойств
« Ответ #5 : 02-01-2025, 21:19:56 »
После считывания параметров выбранных объектов панель объединяет из в классе UnitedProperty, в котором определен список вариантов для выбора, в него можно например расположить 2 варианта Да и Нет для определения какого либо булевого параметра, или же целый набор, например список цветов для выбора цвета объекта, для этого переопределяем метод AfterUnitedAction(UnitedProperty property, List<UnitedProperty> properties), ну и конкретно в этом случае добавляем вспомогательные объекты, в этом методе мы заполняем список вариантов, в который записываем основные цвета, 3 последних выбранных цвета и кнопку, по которой будет открываться окно выбора цвета.

Код - C# [Выбрать]
  1.        public override void AfterUnitedAction(UnitedProperty property, List<UnitedProperty> properties)      
  2.        {
  3.            //цвета по слою и по блоку
  4.            Color byLayer = Color.FromColorIndex(ColorMethod.ByAci, 255);
  5.            Color byBlock = Color.FromColorIndex(ColorMethod.ByAci, 255);
  6.  
  7.            //получаем слой, которому принадлежат выделенные объекты, если он один то (ПОСЛОЮ) будет перекрашен в цвет слоя
  8.            string layer = string.Empty;
  9.  
  10.            foreach (UnitedProperty unitedProperty in properties)
  11.            {
  12.                if (unitedProperty.Name == "Слой")
  13.                {
  14.                    if (!unitedProperty.IsVarious)
  15.                    {
  16.                        layer = unitedProperty.Value.ToString();
  17.                    }
  18.                    break;
  19.                }
  20.            }
  21.  
  22.            if (Layers.ContainsKey(layer)) byLayer = Layers[layer].Color;
  23.  
  24.            if (property.Name == "Цвет" && property.Value is Color selectedColor)
  25.            {
  26.                //список цветов в вариантах
  27.                List<Color> colors = new List<Color>();
  28.  
  29.                //если цвета параметра в списках нет то добавляем в список последних цветов
  30.                if (!property.IsVarious && !LastColors.Contains(selectedColor) && !BaseColors.Contains(selectedColor)) LastColors.Add(selectedColor);
  31.                //ограничиваем список последними тремя цветами, не входящими в основной пул
  32.                if (LastColors.Count > 3) LastColors.RemoveAt(0);
  33.  
  34.                //добавляем в список основные цвета
  35.                colors.AddRange(BaseColors);
  36.  
  37.                //добавляем в список последние цвета
  38.                foreach (Color color in LastColors) if (!colors.Contains(color)) colors.Add(color);
  39.  
  40.                //проходим по цветам и формируем параметры
  41.                foreach (Color color in colors)
  42.                {
  43.                    //получаем отображаемый цвет компонента
  44.                    Color objectColor = color;
  45.                    if (color.IsByLayer) objectColor = byLayer;
  46.                    else if (color.IsByBlock) objectColor = byBlock;
  47.  
  48.                    //создаем новый параметр
  49.                    Property prop = new Property
  50.                    {
  51.                        Value = color,
  52.                        Name = property.Name,
  53.                    };
  54.  
  55.                    //если параметр идентичен выбранному, то обозначаем это
  56.                    if (!property.IsVarious && property.Value.ToString() == prop.Value.ToString()) prop.IsSelected = true;
  57.  
  58.                    //добавляем компоненты параметра
  59.                    prop.Components.AddRange(GetPathColorComponents(objectColor));
  60.  
  61.                    //добавляем компонент с названием цвета во второй столбец первого ряда
  62.                    prop.Components.Add(new ValueComponent
  63.                    {
  64.                        ComponentHeight = 18,
  65.                        MarginLeft = 5,
  66.                        Value = color.ColorNameForDisplay,
  67.                        ComponentRow = 0,
  68.                        ComponentColumn = 1,
  69.                    });
  70.  
  71.                    property.Variants.Add(prop);
  72.                }
  73.  
  74.                //добавляем кнопку выбора цвета
  75.                property.Variants.Add(new Property { Name = property.Name, Value = "Выбрать", IsAction = true });
  76.            }
  77.            else return;
  78.  
  79.            //если выбраны разные цвета то добавляем пункт разных, и обозначаем что он выбран
  80.            if (property.IsVarious) property.Variants.Insert(0, new Property { Name = property.Name, IsVarious = true, IsSelected = true });
  81.  
  82.            if (property.IsVarious && property.Variants.Count == 1) property.Variants.Clear();
  83.        }
  84.  
  85.         /// <summary>
  86.         /// список слоев автокада
  87.         /// </summary>
  88.         private Dictionary<string, LayerData> Layers { get; set; } = new Dictionary<string, LayerData>();
  89.         /// <summary>
  90.         /// список последних используемых цветов
  91.         /// </summary>
  92.         private List<Color> LastColors { get; set; } = new List<Color>();
  93.         /// <summary>
  94.         /// Список базовых цветов
  95.         /// </summary>
  96.         private List<Color> BaseColors { get; set; } = new List<Color>
  97.             {
  98.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByLayer, 256),
  99.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByBlock, 0),
  100.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 1),
  101.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 2),
  102.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 3),
  103.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 4),
  104.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 5),
  105.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 6),
  106.                 Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 7),
  107.             };

Обработка нажатия на кнопку выбора цвета, добавленную в список варинатов в этой строке, флагом чего служит параметр IsAction
Код - C# [Выбрать]
  1.  //добавляем кнопку выбора цвета
  2.  property.Variants.Add(new Property { Name = property.Name, Value = "Выбрать", IsAction = true });

производится в методе ResultAction(Property property), который должен вернуть объект, который, если не является null будет записан в NewValue параметра, что вызовет изменение объектов в чертеже

Код - C# [Выбрать]
  1.         public override object ResultAction(Property property)
  2.         {
  3.             if (property.Name == "Цвет")
  4.             {                
  5.                 ColorDialog dialog = new ColorDialog();
  6.                 System.Windows.Forms.DialogResult dialogResult = dialog.ShowDialog();
  7.                 if (dialogResult == System.Windows.Forms.DialogResult.OK)
  8.                 {
  9.                     //если цвета параметра в списках нет то добавляем в список последних цветов
  10.                     if (!property.IsVarious && !LastColors.Contains(dialog.Color) && !BaseColors.Contains(dialog.Color)) LastColors.Add(dialog.Color);
  11.                     //ограничиваем список последними тремя цветами, не входящими в основной пул
  12.                     if (LastColors.Count > 3) LastColors.RemoveAt(0);
  13.  
  14.                     return dialog.Color;
  15.                 }
  16.             }
  17.             return null;          
  18.         }