PropertyGrid is customizable using attributes on the displayed classes.
Using a TypeConverter you can control the look & feel of properties and/or objects in the PropertyGrid. You can use it to add "virtual" properties, or leave properties out. Also the name of the property can be changed / localized. But a Typeconverter is somewhat harder to implement as the other options.
With the UITypeEditor you can control how a property should be edited (inline, show your own dialog, colorpicker, ...)
You can attach a DisplayName to a property, to change the name. If you override the class, you can translate the propertynames. This question has an example how to do this.
And (like Rune Grimstad answered) you leave out properties by putting a [Browsable(false)] attribute on them.
Another nice one is the DefaultValue, if the value of an attribute matches the value provided by the DefaultValue, the value uses the normal font. If it differs it uses a Bold font.
Your problem is that you do not want to inherit from TextBox or other classes all the time. You can encapsulate the Textbox in a wrapper, that only exposes (via a TypeConverter) the properties you need. I've hacked something that does this:
class BaseWrapper<T> {
public BaseWrapper(T tb) {
this.Wrapped = tb;
}
[Browsable(false)]
public T Wrapped { get; set; }
public object GetMember(string name) {
var prop = this.Wrapped.GetType().GetProperty(name);
return prop.GetValue(this.Wrapped, null);
}
public void SetMember(string name, object value) {
var prop = this.Wrapped.GetType().GetProperty(name);
prop.SetValue(this.Wrapped, value, null);
}
}
class BaseConverter<T> : TypeConverter {
protected class pd : SimplePropertyDescriptor {
public pd(string displayName, string name) : base(typeof(BaseWrapper<T>), displayName, typeof(string)) {
this.PropName = name;
}
public string PropName { get; set; }
public override object GetValue(object component) {
var wrapper = (BaseWrapper<T>)component;
return wrapper.GetMember(this.PropName);
}
public override void SetValue(object component, object value) {
var wrapper = (BaseWrapper<T>)component;
wrapper.SetMember(this.PropName, value);
}
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
return true;
}
}
[TypeConverter(typeof(TextBoxConverter))]
class TextboxWrapper : BaseWrapper<TextBox> {
public TextboxWrapper(TextBox t) : base(t) { }
}
class TextBoxConverter : BaseConverter<TextBox> {
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
return new PropertyDescriptorCollection(new PropertyDescriptor[] {
new pd("Название предприятия", "Text")
});
}
}
To make a textbox the selected object, you use:
this.propertyGrid1.SelectedObject = new TextboxWrapper(this.textBox1);
The place to further work this out is in the pd (ugly name, I know) class, to include the data type, and a localized labels.