You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
9.0 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SigmaDrawerStyle
{
/// <summary>
/// 属性排序类
/// </summary>
/// <seealso cref="System.ComponentModel.ExpandableObjectConverter" />
public class PropertySorter : ExpandableObjectConverter
{
#region Methods
/// <inheritdoc/>
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public static Dictionary<Type, PropertyDescriptorCollection> GlobalPropertyDescriptor = new Dictionary<Type, PropertyDescriptorCollection>();
/// <inheritdoc/>
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
// 1. 动态逻辑必须禁用缓存,否则状态切换无法实时生效
// Type typeObj = value.GetType();
// if (GlobalPropertyDescriptor.TryGetValue(typeObj, out PropertyDescriptorCollection properties))
// {
// return properties;
// }
// 2. 获取原始属性
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(value, attributes);
// 3. 动态获取当前对象的 RulerDataStyle 值(使用反射避免命名空间引用错误)
int currentStyle = -1;
var styleProp = pdc["RulerDataStyle"];
if (styleProp != null)
{
var val = styleProp.GetValue(value);
if (val != null) currentStyle = Convert.ToInt32(val);
}
// 原始属性
List<PropertyOrderPair> orderedProperties = new List<PropertyOrderPair>();
List<string> lstOriginCategory = new List<string>();
List<string> lstCategoryTab = new List<string>();
List<string> lstCategoryNoTab = new List<string>();
foreach (PropertyDescriptor pd in pdc)
{
Attribute attribute = pd.Attributes[typeof(PropertyOrderAttribute)];
string strCategory = pd.Category;
if (attribute != null)
{
PropertyOrderAttribute poa = (PropertyOrderAttribute)attribute;
orderedProperties.Add(new PropertyOrderPair(pd.Name, poa.Order, strCategory));
}
else
{
// 没有序号的设置序号为 0
orderedProperties.Add(new PropertyOrderPair(pd.Name, 0, strCategory));
}
if (!lstOriginCategory.Contains(strCategory))
{
lstOriginCategory.Add(strCategory);
if (strCategory.IndexOf('\t') >= 0)
{
lstCategoryTab.Add(strCategory);
}
else
{
lstCategoryNoTab.Add(strCategory);
}
}
}
List<string> lstCategoryTabFinal = new List<string>();
List<string> lstCategoryNoTabFinal = new List<string>();
if (lstCategoryNoTab.Count > 1)
{
//char chNull = (char)0x0009;
char chNull = '\u200B';
lstCategoryTab.Sort();
for (int i = 0; i < lstCategoryTab.Count; i++)
{
string strCategory = lstCategoryTab[i];
strCategory = strCategory.Trim('\t');
strCategory = strCategory.PadLeft(strCategory.Length + lstOriginCategory.Count - i - 1, chNull);
lstCategoryTabFinal.Add(strCategory);
}
for (int i = 0; i < lstCategoryNoTab.Count; i++)
{
string strCategory = lstCategoryNoTab[i];
strCategory = strCategory.PadLeft(strCategory.Length + lstOriginCategory.Count - lstCategoryTab.Count - i - 1, chNull);
lstCategoryNoTabFinal.Add(strCategory);
}
}
List<PropertyDescriptor> finalList = new List<PropertyDescriptor>();
foreach (PropertyDescriptor pd in pdc)
{
string strCagegory = pd.Category;
if (lstCategoryNoTab.Count > 1)
{
int nIndex = lstCategoryTab.IndexOf(strCagegory);
if (nIndex >= 0)
{
strCagegory = lstCategoryTabFinal[nIndex];
}
else
{
nIndex = lstCategoryNoTab.IndexOf(strCagegory);
if (nIndex >= 0)
{
strCagegory = lstCategoryNoTabFinal[nIndex];
}
}
}
// 重新构建属性特性
var attrList = new List<Attribute>();
foreach (Attribute attr in pd.Attributes)
{
if (attr is CategoryAttribute)
{
attrList.Add(new CategoryAttribute(strCagegory));
}
else
{
attrList.Add(attr);
}
}
// 逻辑:如果当前属性是 RulerNumber且检测到的 Style 为 1 或 2 动态设置 RulerNumber 为只读
if (pd.Name == "RulerNumber" && (currentStyle == 1 || currentStyle == 2))
{
attrList.RemoveAll(a => a is ReadOnlyAttribute);
attrList.Add(new ReadOnlyAttribute(true));
}
// --------------------------------------------
finalList.Add(TypeDescriptor.CreateProperty(pd.ComponentType, pd, attrList.ToArray()));
}
// 重新设置类别属性
orderedProperties.Sort();
int nPropertyCount = orderedProperties.Count;
string[] saOrderNames = new string[nPropertyCount];
for (int i = 0; i < nPropertyCount; i++)
{
saOrderNames[i] = orderedProperties[i].Name;
}
PropertyDescriptorCollection result = new PropertyDescriptorCollection(finalList.ToArray(), true).Sort(saOrderNames);
// 返回结果(不存入 GlobalPropertyDescriptor
return result;
}
#endregion
}
#region Helper Class - PropertyOrderAttribute
[AttributeUsage(AttributeTargets.Property)]
public class PropertyOrderAttribute : Attribute
{
//
// Simple attribute to allow the order of a property to be specified
//
private int _order;
/// <summary>
/// Initializes a new instance of the <see cref="PropertyOrderAttribute"/> class.
/// </summary>
/// <param name="order"></param>
public PropertyOrderAttribute(int order)
{
_order = order;
}
public int Order
{
get
{
return _order;
}
}
}
#endregion
#region Helper Class - PropertyOrderPair
public class PropertyOrderPair : IComparable
{
private int _order;
private string _name;
public string Category { get; set; }
public string Name
{
get
{
return _name;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="PropertyOrderPair"/> class.
/// </summary>
/// <param name="name">名称</param>
/// <param name="order">顺序号</param>
public PropertyOrderPair(string name, int order)
{
_order = order;
_name = name;
}
/// <summary>
/// Initializes a new instance of the <see cref="PropertyOrderPair"/> class.
/// </summary>
/// <param name="name">名称.</param>
/// <param name="order">序号.</param>
/// <param name="category">分类.</param>
public PropertyOrderPair(string name, int order, string category)
: this(name, order)
{
this.Category = category;
}
public int CompareTo(object obj)
{
//
// Sort the pair objects by ordering by order value
// Equal values get the same rank
//
int otherOrder = ((PropertyOrderPair)obj)._order;
if (otherOrder == _order)
{
//
// If order not specified, sort by name
//
string otherName = ((PropertyOrderPair)obj)._name;
return string.Compare(_name, otherName);
}
else if (otherOrder > _order)
{
return -1;
}
return 1;
}
}
#endregion
}