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

  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单C# PropertyGrid 实例: ```csharp using System.ComponentModel; using System.Windows.Forms; public class Person { public string Name { get; set; } public int Age { get; set; } public string Gender { get; set; } } public class MainForm : Form { private PropertyGrid propertyGrid; private Person person; public MainForm() { InitializeComponent(); InitializePerson(); InitializePropertyGrid(); } private void InitializeComponent() { this.propertyGrid = new PropertyGrid(); this.SuspendLayout(); // // propertyGrid // this.propertyGrid.Dock = DockStyle.Fill; this.propertyGrid.Location = new System.Drawing.Point(0, 0); this.propertyGrid.Name = "propertyGrid"; this.propertyGrid.Size = new System.Drawing.Size(284, 262); this.propertyGrid.TabIndex = 0; // // MainForm // this.ClientSize = new System.Drawing.Size(284, 262); this.Controls.Add(this.propertyGrid); this.Name = "MainForm"; this.Text = "PropertyGrid Example"; this.ResumeLayout(false); } private void InitializePerson() { person = new Person(); person.Name = "John Doe"; person.Age = 30; person.Gender = "Male"; } private void InitializePropertyGrid() { propertyGrid.SelectedObject = person; } } ``` 在此示例中,我们创建了一个名为“Person”的类,该类具有三个属性:Name、Age 和 Gender。然后,我们创建一个名为“MainForm”的窗体,并在其中添加一个 PropertyGrid 控件。在 MainForm 的构造函数中,我们初始化了 Person 对象并将其分配给 PropertyGrid 的 SelectedObject 属性。这将使 PropertyGrid 显示 Person 对象的所有属性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值