C# PropertyGrid 简单使用

Posted Thomas会写字

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# PropertyGrid 简单使用相关的知识,希望对你有一定的参考价值。

目录

一、 导入数据

二、 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博客

以上是关于C# PropertyGrid 简单使用的主要内容,如果未能解决你的问题,请参考以下文章

C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)

C# WinForm PropertyGrid用法

C#自定义PropertyGrid属性

C#自定义PropertyGrid属性

C# 如何定义让PropertyGrid控件显示[...]按钮,并且点击后以下拉框形式显示自定义控件编辑属性值

c#用propertyGrid控件