两点C#的propertyGrid的使用心得
2013-09-13 14:16
246 查看
最近接触C#的PropertyGrid比较多,得到了两个小心得记录一下。
大家知道在类的某个属性中加[ReadOnlyAttribute(true)]声明标记后,此类的对象的这个属性在PropertyGrid中就表现为灰色不可更改,请问大家有没有什么办法动态地让这个属性在PropertyGrid中的显示变为可读写么?
以下的方法试过,不好用
1、想在程序里改声明标记,可是不行
2、另外写个类,同样的属性标记为[ReadOnlyAttribute(false)],然后重新selectobject,可是太复杂了。
用反射可以实现动态改变,只读、可见等等,这些属性都可以改变。
以下两个方法分别实现可见性和只读属性的动态改变:
void SetPropertyVisibility(object obj, string propertyName, bool visible)
{
Type type = typeof(BrowsableAttribute);
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
AttributeCollection attrs = props[propertyName].Attributes;
FieldInfo fld = type.GetField("browsable", BindingFlags.Instance | BindingFlags.NonPublic);
fld.SetValue(attrs[type], visible);
}
void SetPropertyReadOnly(object obj, string propertyName, bool readOnly)
{
Type type = typeof(System.ComponentModel.ReadOnlyAttribute);
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
AttributeCollection attrs = props[propertyName].Attributes;
FieldInfo fld = type.GetField("isReadOnly", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance);
fld.SetValue(attrs[type], readOnly);
}
使用时,SetPropertyVisibility(obj, "名称", true);
obj指的就是你的SelectObject, “名称”是你SelectObject的一个属性
当然,调用这两个方法后,重新SelectObject一下,就可以了
心得:
(1)如果对属性框中所有属性一起进行控制,可以不添加 [ReadOnlyAttribute(false)]标记,propertyName可以是任何属性名称。[注:这里讲得很不清楚]
(2)如果仅仅对某一个属性进行控制,则必须在每个属性的描述中添加 [ReadOnlyAttribute(false)]标记。propertyName必须是所要控制的属性名。
原文中提到的思路是在运行时,通过反射的方式修改每一个Property的ReadOnlyAttribute。只是心得那里説不很不清楚,要对整个对象而非具体的属性进行控制时怎么办。
我的第一个想法是遍历所有的Property,对每一个都设置ReadOnly,但是这样是错误的,而且有副作用。后来经过试验,我直接对PropertyGrid的Object设置ReadOnly。
这里説一下,在找解决办法的时候,还去顺便了解了一下c#在运行时,动态添加Attribute的内容,这个内容留下次再记录好了。
还找到一篇讲反射可以通过FieldInfo.SetValue设置任何字段的值的文章:/article/4701504.html
ConvertFrom函数会在PropertyGrid中的字符串被修改保存后被调用
ConvertTo函数则是在最初显示PropertyGrid以及对List进行修改之后被调用
第1点是关于控制PropertyGrid中属性的只读属性的。
我遇到的问题是这样的,我需要在运行时根据SVN的状态动态控制PropertyGrid中的属性的读写控制。以前的做法比较简单,直接是PropertyGrid.Enabled(false)。这样的坏处是完全使Grid完全失效,连滚动条也不可用了,不便于查看属性。后来上网查阅相关的资料,网上有比较的是同一篇文章的复制,原文出处我已经找不到了。先把原文贴出来如下:大家知道在类的某个属性中加[ReadOnlyAttribute(true)]声明标记后,此类的对象的这个属性在PropertyGrid中就表现为灰色不可更改,请问大家有没有什么办法动态地让这个属性在PropertyGrid中的显示变为可读写么?
以下的方法试过,不好用
1、想在程序里改声明标记,可是不行
2、另外写个类,同样的属性标记为[ReadOnlyAttribute(false)],然后重新selectobject,可是太复杂了。
用反射可以实现动态改变,只读、可见等等,这些属性都可以改变。
以下两个方法分别实现可见性和只读属性的动态改变:
void SetPropertyVisibility(object obj, string propertyName, bool visible)
{
Type type = typeof(BrowsableAttribute);
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
AttributeCollection attrs = props[propertyName].Attributes;
FieldInfo fld = type.GetField("browsable", BindingFlags.Instance | BindingFlags.NonPublic);
fld.SetValue(attrs[type], visible);
}
void SetPropertyReadOnly(object obj, string propertyName, bool readOnly)
{
Type type = typeof(System.ComponentModel.ReadOnlyAttribute);
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
AttributeCollection attrs = props[propertyName].Attributes;
FieldInfo fld = type.GetField("isReadOnly", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance);
fld.SetValue(attrs[type], readOnly);
}
使用时,SetPropertyVisibility(obj, "名称", true);
obj指的就是你的SelectObject, “名称”是你SelectObject的一个属性
当然,调用这两个方法后,重新SelectObject一下,就可以了
心得:
(1)如果对属性框中所有属性一起进行控制,可以不添加 [ReadOnlyAttribute(false)]标记,propertyName可以是任何属性名称。[注:这里讲得很不清楚]
(2)如果仅仅对某一个属性进行控制,则必须在每个属性的描述中添加 [ReadOnlyAttribute(false)]标记。propertyName必须是所要控制的属性名。
原文中提到的思路是在运行时,通过反射的方式修改每一个Property的ReadOnlyAttribute。只是心得那里説不很不清楚,要对整个对象而非具体的属性进行控制时怎么办。
我的第一个想法是遍历所有的Property,对每一个都设置ReadOnly,但是这样是错误的,而且有副作用。后来经过试验,我直接对PropertyGrid的Object设置ReadOnly。
private void button1_Click(object sender, EventArgs e) { Type readonlyType = typeof(System.ComponentModel.ReadOnlyAttribute); PropertyDescriptorCollection props = TypeDescriptor.GetProperties(propertyGrid1.SelectedObject); FieldInfo fld = readonlyType.GetField("isReadOnly", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.CreateInstance); AttributeCollection attrs = TypeDescriptor.GetAttributes(propertyGrid1.SelectedObject); fld.SetValue(attrs[typeof(ReadOnlyAttribute)], gridReadOnly); gridReadOnly = !gridReadOnly; }
这里説一下,在找解决办法的时候,还去顺便了解了一下c#在运行时,动态添加Attribute的内容,这个内容留下次再记录好了。
还找到一篇讲反射可以通过FieldInfo.SetValue设置任何字段的值的文章:/article/4701504.html
第2点是PropertyGrid中使用TypeConverter
PropertyGrid中对于自定义的类型显示支持有限,最好是自己去实现自己的TypeConverter,把类型转换来进行显示。我写了一个简单的例子,把List类型转换成string。public class MyColorConverter : TypeConverter { public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { if (value == null) { return new List<int>(); } string stringValue = value as string; if (stringValue != null) { List<int> result = new List<int>(); string[] vs = stringValue.Split(new char[] { ',' }); foreach (string eachString in vs) { result.Add(int.Parse(eachString)); } return result; } else { return base.ConvertFrom(context, culture, value); } } public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType) { if (destinationType == typeof(string)) { return true; } return base.CanConvertTo(context, destinationType); } public override System.ComponentModel.PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, System.Attribute[] attributes) { throw new Exception("The method or operation is not implemented."); } public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) { List<int> list = value as List<int>; if (list != null && list.Count > 0) { StringBuilder sb = new StringBuilder(); foreach (int v in list) { sb.AppendFormat("{0},", v); } sb.Remove(sb.Length - 1, 1); return sb.ToString(); } return ""; } else { return base.ConvertTo(context, culture, value, destinationType); } } public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string)) { return true; } return base.CanConvertFrom(context, sourceType); } }
private List<int> color1 = new List<int>(); [Category("main")] [DisplayName("颜色1")] [TypeConverter(typeof(MyColorConverter))] public List<int> Color1 { get { return color1; } set { color1 = value; } }
ConvertFrom函数会在PropertyGrid中的字符串被修改保存后被调用
ConvertTo函数则是在最初显示PropertyGrid以及对List进行修改之后被调用
相关文章推荐
- 两点C#的propertyGrid的使用心得【转】
- 两点C#的propertyGrid的使用心得
- C# webBrowser控件使用心得
- C# 中使用OPenCV(Emgu)心得
- 在C#中 webbrowser的使用心得
- C# winform 编程 向ACCESS数据库导入EXCEL表使用心得
- 一次使用c#的canvas心得
- UltraWinGrid使用心得(C#)
- C# using语句使用心得总结
- 关于javascript和c#中日期的两点比较--以防在使用ajax时出错
- C# Builder 使用心得
- c# 文本框使用心得(TextBox)
- 关于C#多线程、网络编程与计时器Timer的一点使用心得
- .net c#线程使用心得
- 关于C#窗体基本控件使用心得(1)
- C#中委托如何使用?一点学习心得
- C#中SQL SERVER 2008字符数据类型使用心得
- C# 中使用OPenCV(Emgu)心得
- 百度地图和高德地图坐标系的互相转换 四种Sandcastle方法生成c#.net帮助类帮助文档 文档API生成神器SandCastle使用心得 ASP.NET Core
- 【转载】WebDriver(C#)之十点使用心得