C# PropertyGrid 简单使用

发布时间:2025-12-09 16:13:30 浏览次数:5

目录

一、 导入数据

二、 PropertyGrid 的简单属性配置

三、 设置字段属性

四、 字段的下拉框

五、 多级展开

六、 显示内容的排序

6.1 属性排序

6.1.1 自定义排序

6.1.2 根据字段封装顺序

6.2 类别排序 

七、 闪屏问题

八、 主要参考


一、 导入数据

propertyGrid1.SelectedObject = new Level1(); 

  • 显示Level1类中所有 public 属性 Get Set 封装的字段。
propertyGrid1.SelectedObject = new Level1();public class Level1{private int nVal1;private int nVal2;private int nVal3;public int NVal1 { get => nVal1; set => nVal1 = value; }public int NVal2 { get => nVal2; set => nVal2 = value; }public int NVal3 { get => nVal3; set => nVal3 = value; }}

propertyGrid1.SelectedObjects = new object[] { new Level1(), new Level2() };

  • 显示Level2 和 Level2 中所有公共属性 

 

propertyGrid1.SelectedObjects = new object[] { new Level1(), new Level2() };public class Level1{private int nVal1;private int nVal2;private int nVal3;public int NVal1 { get => nVal1; set => nVal1 = value; }public int NVal2 { get => nVal2; set => nVal2 = value; }public int NVal3 { get => nVal3; set => nVal3 = value; }}public class Level2{private int nVal3;private int nVal4;private int nVal5;public int NVal3 { get => nVal3; set => nVal3 = value; }public int NVal4 { get => nVal4; set => nVal4 = value; }public int NVal5 { get => nVal5; set => nVal5 = value; }}

二、 PropertyGrid 的简单属性配置

  • BackColor 更改其背景色。
  • HelpBackColor 更改助窗口背景色。
  • HelpForeColor 更改助窗口字体颜色。
  • HelpVisible 显示隐藏帮助窗口。
  • ToolbarVisible 显示隐藏工具栏。
  • LargeButtons 显示大型工具栏按钮。
  • PropertySort 按字母顺序对属性进行排序。
  • BackColor 更改拆分器颜色。
  • LineColor 更改网格线和边框。

三、 设置字段属性

  • DescriptionAttribute - 设置属性在属性下方的说明帮助窗格中显示的属性的文本。 这是为具有焦点的活动属性提供帮助文本的有用方法。 将此属性应用于 MaxRepeatRate 该属性。
  • CategoryAttribute 设置属性在网格中所属的类别。 当需要按类别名称分组的属性时,这非常有用。 如果属性未指定类别,则会将其分配给 Misc 类别。 将此属性应用于所有属性。
  • BrowsableAttribute – 指示属性是否显示在网格中。 如果要从网格中隐藏属性,这非常有用。 默认情况下,公共属性始终显示在网格中。 将此属性应用于 SettingsChanged 该属性。
  • ReadOnlyAttribute – 指示属性是否为只读。 如果要使属性在网格中不可编辑,这非常有用。 默认情况下,具有 get 和 set 访问器函数的公共属性在网格中可编辑。 将此属性应用于 AppVersion 该属性。
  • DefaultValueAttribute – 标识属性的默认值。 如果想要为属性提供默认值,然后确定该属性的值是否不同于默认值,则这非常有用。 将此属性应用于所有属性。
  • DefaultPropertyAttribute – 标识类的默认属性。 类的默认属性在网格中选择类时首先获取焦点。 将此属性应用于 AppSettings 类。
  • DisplayNameAttribute - 实际显示的名称

 

[DefaultProperty("NVal1")]public class Level1{private int nVal1;private int nVal2;private int nVal3;[Category("Level"), DefaultValue("123"), ReadOnly(false), Browsable(true), Description("This Is Description")]public int NVal1 { get => nVal1; set => nVal1 = value; }[Category("Level"),Browsable(false)]public int NVal2 { get => nVal2; set => nVal2 = value; }[Category("Level"), DefaultValue("456"), ReadOnly(true)]public int NVal3 { get => nVal3; set => nVal3 = value; }}

四、 字段的下拉框

常用属性 PropertyGrid 中已经封装了下拉框属性 

字符串:

1. 通过继承重写 StringConverter 函数

/* 创建从类型转换器类继承的类。 * 由于属性 DefaultFileName 属于 String 类型* 因此可以从 StringConverter 继承。 * 如果属性类型的类型转换器不存在,则可以从 * TypeConverter 继承;在这种情况下,不需要这样做。*/ public class MyStringConverter : StringConverter{//重写 GetStandardValuesSupported 方法并返回 true 以指示此对象支持可从列表中选择的标准值集。public override bool GetStandardValuesSupported( ITypeDescriptorContext context){return true;}/* 重写 GetStandardValues 方法,并返回用标准值填充的 StandardValuesCollection 。 * 创建 StandardValuesCollection 的一种方法是在构造函数中提供值数组。 * 对于选项窗口应用程序,可以使用填充有建议的默认文件名的 字符串 数组。*/ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context){return new StandardValuesCollection(new string[]{"Str2", "Str3", "Str4"});}/* (可选) 如果希望用户能够键入不在下拉列表中的值,* 请重写 GetStandardValuesExclusive 方法并返回 false。 * 这基本上将下拉列表样式更改为组合框样式。*/ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context){return false;}

2. 通过Enum.ToString()实现,将String[] 变为 Enum,通过 Enum 实现下拉框

public class Level1{private bool bVal = true;private Size sizeVal = new Size(100,200);private Font fontVal= new Font("宋体", 9, FontStyle.Regular);private Color colVal = Color.Red;private EnumVal eVal = EnumVal.E02;private String sVal = "Str1";[CategoryAttribute("下拉框")]public bool BVal { get => bVal; set => bVal = value; }[CategoryAttribute("下拉框")]public Size SizeVal { get => sizeVal; set => sizeVal = value; }[CategoryAttribute("下拉框")]public Font FontVal { get => fontVal; set => fontVal = value; }[CategoryAttribute("下拉框")]public Color ColVal { get => colVal; set => colVal = value; }[CategoryAttribute("下拉框")]public EnumVal EVal { get => eVal; set => eVal = value; }[CategoryAttribute("下拉框"), TypeConverter(typeof(MyStringConverter))]public string SVal { get => sVal; set => sVal = value; }}

五、 多级展开

public class Level1{private SpellingOptions spell = new SpellingOptions();/* 6. 将 TypeConverterAttribute 应用于示例中的类 SpellingOptions 目标类。*/[TypeConverterAttribute(typeof(SpellingOptionsConverter))]public SpellingOptions Spell { get => spell; set => spell = value; }}public class SpellingOptions{private bool spellCheckWhileTyping = true;private bool spellCheckCAPS = false;private bool suggestCorrections = true;[DefaultValueAttribute(true)]public bool SpellCheckWhileTyping{get { return spellCheckWhileTyping; }set { spellCheckWhileTyping = value; }}[DefaultValueAttribute(false)]public bool SpellCheckCAPS{get { return spellCheckCAPS; }set { spellCheckCAPS = value; }}[DefaultValueAttribute(true)]public bool SuggestCorrections{get { return suggestCorrections; }set { suggestCorrections = value; }}}/* 1. 创建继承自 ExpandableObjectConverter 的类。* 若要获取 PropertyGrid 以展开 SpellingOptions 该属性,需要创建 TypeConverter。 * TypeConverter 提供了一种从一种类型转换为另一种类型的方法。 * PropertyGrid 使用 TypeConverter 将对象类型转换为字符串,该字符串用于在网格中显示对象值。 * 在编辑期间, TypeConverter 将从 String 转换回对象类型。 * .NET Framework提供了 ExpandableObjectConverter 类,以便更轻松地执行此操作。*/public class SpellingOptionsConverter : ExpandableObjectConverter{/* 2. 如果参数与使用此类型的SpellingOptions转换器的类相同,* 则重写 CanConvertTo 方法并返回 truedestinationType;* 否则,返回基类 CanConvertTo 方法的值。*/ public override bool CanConvertTo(ITypeDescriptorContext context, System.Type destinationType){if (destinationType == typeof(SpellingOptions))return true;return base.CanConvertTo(context, destinationType);}/* 3. 重写 ConvertTo 方法,并确保 destinationType 参数是 字符串 ,* 并且该值与使用此类型转换器 SpellingOptions 的类(示例中的类) 的类型相同。 * 如果任一情况为 false,则返回基类 ConvertTo 方法的值;* 否则返回值对象的字符串表示形式。 字符串表示形式需要用唯一分隔符分隔类的每个属性。 * 由于整个字符串将显示在 PropertyGrid 中,* 因此你需要选择一个不减去可读性的分隔符;逗号通常效果良好。*/ public override object ConvertTo(ITypeDescriptorContext context,CultureInfo culture,object value,System.Type destinationType){if (destinationType == typeof(System.String) &&value is SpellingOptions){SpellingOptions so = (SpellingOptions)value;return "Typing:" + so.SpellCheckWhileTyping +", CAPS: " + so.SpellCheckCAPS +", Suggest: " + so.SuggestCorrections;}return base.ConvertTo(context, culture, value, destinationType);}/* 4. (可选) 可以通过指定类型转换器可以从字符串转换来启用对网格中* 对象的字符串表示形式的编辑。 为此,请先重写 CanConvertFrom 方法,* 如果源 Type 参数的类型为 String,则返回 true;否则,* 返回基类 CanConvertFrom 方法的值。*/ public override bool CanConvertFrom(ITypeDescriptorContext context,System.Type sourceType){if (sourceType == typeof(string))return true;return base.CanConvertFrom(context, sourceType);}/* 5. 若要启用对对象的基类的编辑,* 还需要重写 ConvertFrom 方法,并确保值参数为 String。 * 如果不是 String,则返回基类 ConvertFrom 方法的值;* 否则,请根据值参数返回类的新实例, (SpellingOptions 示例中的类) 。 * 需要从值参数分析类的每个属性的值。 * 了解在 ConvertTo 方法中创建的带分隔符的字符串的格式将有助于执行分析。*/public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value){if (value is string){try{string s = (string)value;int colon = s.IndexOf(':');int comma = s.IndexOf(',');if (colon != -1 && comma != -1){string checkWhileTyping = s.Substring(colon + 1,(comma - colon - 1));colon = s.IndexOf(':', comma + 1);comma = s.IndexOf(',', comma + 1);string checkCaps = s.Substring(colon + 1,(comma - colon - 1));colon = s.IndexOf(':', comma + 1);string suggCorr = s.Substring(colon + 1);SpellingOptions so = new SpellingOptions();so.SpellCheckWhileTyping = Boolean.Parse(checkWhileTyping);so.SpellCheckCAPS = Boolean.Parse(checkCaps);so.SuggestCorrections = Boolean.Parse(suggCorr);return so;}}catch{throw new ArgumentException( "Can not convert '" + (string)value + "' to type SpellingOptions");}}return base.ConvertFrom(context, culture, value);}}

六、 显示内容的排序

6.1 属性排序

  • PropertyGrid 默认支持的排序方式
  • 自定义顺序的排序方式
  • 根据字段封装顺序的排序方式

  

6.1.1 自定义排序

[TypeConverter(typeof(PropertySorter))]public class Level1{int n01 = 1;int n02 = 2;int n03 = 3;int n04 = 4;int n05 = 5;int n06 = 6;[PropertyOrder(1)]public int N01 { get => n01; set => n01 = value; }[PropertyOrder(2)]public int N04 { get => n04; set => n04 = value; }[PropertyOrder(3)]public int N02 { get => n02; set => n02 = value; }[PropertyOrder(4)]public int N05 { get => n05; set => n05 = value; }[PropertyOrder(5)]public int N03 { get => n03; set => n03 = value; }[PropertyOrder(6)]public int N06 { get => n06; set => n06 = value; }}public class PropertySorter : ExpandableObjectConverter{public override bool GetPropertiesSupported(ITypeDescriptorContext context){return true;}public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes){//// This override returns a list of properties in order//PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(value, attributes);ArrayList orderedProperties = new ArrayList();foreach (PropertyDescriptor pd in pdc){Attribute attribute = pd.Attributes[typeof(PropertyOrderAttribute)];if (attribute != null){//// If the attribute is found, then create an pair object to hold it//PropertyOrderAttribute poa = (PropertyOrderAttribute)attribute;orderedProperties.Add(new PropertyOrderPair(pd.Name, poa.Order));}else{//// If no order attribute is specifed then given it an order of 0//orderedProperties.Add(new PropertyOrderPair(pd.Name, 0));}}//// Perform the actual order using the value PropertyOrderPair classes// implementation of IComparable to sort//orderedProperties.Sort();//// Build a string list of the ordered names//ArrayList propertyNames = new ArrayList();foreach (PropertyOrderPair pop in orderedProperties){propertyNames.Add(pop.Name);}//// Pass in the ordered list for the PropertyDescriptorCollection to sort by//return pdc.Sort((string[])propertyNames.ToArray(typeof(string)));}}[AttributeUsage(AttributeTargets.Property)]public class PropertyOrderAttribute : Attribute{//// Simple attribute to allow the order of a property to be specified//private int _order;public PropertyOrderAttribute(int order){_order = order;}public int Order{get{return _order;}}}public class PropertyOrderPair : IComparable{private int _order;private string _name;public string Name{get{return _name;}}public PropertyOrderPair(string name, int order){_order = order;_name = name;}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;}}

6.1.2 根据字段封装顺序

[TypeConverter(typeof(PropertySorter))]public class Level1{int n01 = 1;int n02 = 2;int n03 = 3;int n04 = 4;int n05 = 5;int n06 = 6;public int N01 { get => n01; set => n01 = value; }public int N04 { get => n04; set => n04 = value; }public int N02 { get => n02; set => n02 = value; }public int N05 { get => n05; set => n05 = value; }public int N03 { get => n03; set => n03 = value; }public int N06 { get => n06; set => n06 = value; }}public class PropertySorter : ExpandableObjectConverter{public override bool GetPropertiesSupported(ITypeDescriptorContext context){return true;}public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes){PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(value, attributes);ArrayList propertyNames = new ArrayList();foreach (PropertyDescriptor pd in pdc)propertyNames.Add(pd.Name);return pdc.Sort((string[])propertyNames.ToArray(typeof(string)));}}

6.2 类别排序 

1. PropertyGrid.PropertySort = CategorizedAlphabetical

2. 数据类中添加类别排序List

private List<String> categorys = new List<string>() { ... };

 3. 添加 PropertyGrid 的 Paint 事件

private void propertyGrid1_Paint(object sender, PaintEventArgs e){var categorysinfo = propertyGrid1.SelectedObject.GetType().GetField("categorys", BindingFlags.NonPublic | BindingFlags.Instance);if (categorysinfo != null){var categorys = categorysinfo.GetValue(propertyGrid1.SelectedObject) as List<String>;propertyGrid1.CollapseAllGridItems();GridItemCollection currentPropEntries = typeof(PropertyGrid).GetField("currentPropEntries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(propertyGrid1) as GridItemCollection;var newarray = currentPropEntries.Cast<GridItem>().OrderBy((t) => categorys.IndexOf(t.Label)).ToArray();currentPropEntries.GetType().GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentPropEntries, newarray);propertyGrid1.ExpandAllGridItems();object obj = propertyGrid1.Tag;if (obj != null)propertyGrid1.PropertySort = (PropertySort)obj;}propertyGrid1.Paint -= new PaintEventHandler(propertyGrid1_Paint);propertyGrid1.CollapseAllGridItems();}

七、 闪屏问题

Form.DoubleBuffered = true; 或者 SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

八、 主要参考

充分利用 .NET Framework PropertyGrid 控件 | Microsoft Learn

c# PropertyGrid 自定义属性排序_楚楚3107的博客-CSDN博客

PropertyGrid控件 分类(Category)及属性(Property)排序_propertygrid 排序_衣舞晨风的博客-CSDN博客

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477