Reputation: 13659
I could no longer find an exact solution to my problem in the internet so I'm asking this question. Hope you may be able to help me.
I have the following classes:
public Item
{
public FieldType MyField { get; set; }
public string Description { get; set; }
public int Capacity { get; set; }
}
public FieldType
{
public string Value { get; set; }
public string FieldCode { get; set; }
public string TableCode { get; set; }
}
In my form, I created an instance of Item class. Which contains the following members:
Is it possible to only show the Value
member of MyField
property in the PropertyGrid
?
Below is how I assign the selected object property of the PropertyGrid
.
void Form1(object sender, EventArgs e)
{
propertyGrid1.SelectedObject = new Item();
}
Upvotes: 0
Views: 1973
Reputation: 125302
Solution 1 - Add a property
You can add a property to Item
class to get and set MyField.Value
:
public string Value
{
get
{
if (MyField != null)
return MyField.Value;
return null;
}
set
{
if (MyField != null)
MyField.Value = value;
}
}
• Preferably define that property in a partial class.
• Use this option when you have access to codes of the classes. If those classes are not yours, use 3rd solution.
Solution 2 - Use ExpandableObjectConverter
You can decorate the MyField
property of Item
class with ExpandableObjectConverter
. Also decorate FieldType
with [Browsable(false)]
of FieldType
class to hide it in property grid if you want:
[TypeConverter(typeof(ExpandableObjectConverter))]
public FieldType MyField { get; set; }
• To customize the text which is shown in front of MyField
, you can override ToString
method of FieldType
and return Value
. Also you can do it using a custom TypeConverter
and overriding its ConvertTo
method.
Solution 3 - Use a custom TypeDescriptor
It's not as easy as the first solution, but the output is completely like what you get using the first solution. It's suitable for cases that you can not manipulate those classes.
You can use it this way:
var item = new Item() { MyField = new FieldType() { Value = "Some Value" } };
TypeDescriptor.AddProvider(new MyTypeDescriptionProvider(), item);
this.propertyGrid1.SelectedObject = item;
Or by decorating Item
class with:
[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
public class Item
Custom Property Descriptor
public class MyPropertyDescriptor : PropertyDescriptor
{
private PropertyDescriptor subProperty;
private PropertyDescriptor parentProperty;
public MyPropertyDescriptor(PropertyDescriptor parent, PropertyDescriptor sub)
: base(sub, null)
{
subProperty = sub;
parentProperty = parent;
}
public override bool IsReadOnly { get { return subProperty.IsReadOnly; } }
public override void ResetValue(object component)
{
subProperty.ResetValue(parentProperty.GetValue(component));
}
public override bool CanResetValue(object component)
{
return subProperty.CanResetValue(parentProperty.GetValue(component));
}
public override bool ShouldSerializeValue(object component)
{
return subProperty.ShouldSerializeValue(parentProperty.GetValue(component));
}
public override Type ComponentType { get { return parentProperty.ComponentType; } }
public override Type PropertyType { get { return subProperty.PropertyType; } }
public override object GetValue(object component)
{
return subProperty.GetValue(parentProperty.GetValue(component));
}
public override void SetValue(object component, object value)
{
subProperty.SetValue(parentProperty.GetValue(component), value);
OnValueChanged(component, EventArgs.Empty);
}
}
Custom type Descriptor
public class MyTypeDescriptor : CustomTypeDescriptor
{
ICustomTypeDescriptor original;
public MyTypeDescriptor(ICustomTypeDescriptor originalDescriptor)
: base(originalDescriptor)
{
original = originalDescriptor;
}
public override PropertyDescriptorCollection GetProperties()
{
return this.GetProperties(new Attribute[] { });
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
var properties = original.GetProperties().Cast<PropertyDescriptor>().ToList();
var parent = properties.Where(x => x.Name == "MyField").First();
var sub = TypeDescriptor.GetProperties(typeof(FieldType))["Value"];
properties.Remove(parent);
properties.Add(new MyPropertyDescriptor(parent, sub));
return new PropertyDescriptorCollection(properties.ToArray());
}
}
Custom TypeDescriptorProvider
public class MyTypeDescriptionProvider : TypeDescriptionProvider
{
public MyTypeDescriptionProvider()
: base(TypeDescriptor.GetProvider(typeof(object))) { }
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
object instance)
{
ICustomTypeDescriptor baseDes = base.GetTypeDescriptor(objectType, instance);
return new MyTypeDescriptor(baseDes);
}
}
• Use this option if Item
and FieldType
are not yours. If those classes are yours and you can change their code, use first solution.
Upvotes: 1
Reputation: 666
Im not really sure of what you are looking for but here are 2 answers
1.(as I understood it)
if you want it to show only Value
when you try and view the properties of a MyField
Instance then all you need to do is add a constructor to the MyField
so you can assign the other two values and change the public property to private
like so
public FieldType
{
public string Value { get; set; }
private string FieldCode { get; set; }
private string TableCode { get; set; }
}
2.(this will hide the MyField
from your propertyGrid)
Override the ToString()
method of FielType
like so
public override string ToString()
{
return Value;
}
then set your MyField
to private and encapsulate it. returning the instance as a string. which would use the overridden value.
like so
private FieldType MyField;
public string value{ get{return MyField.ToString();}set;}
your MyField will return the overridden ToString
value which returns Value.
Upvotes: 0
Reputation: 146557
Yes, easy:
add a computed read only property to Item
public Item
{
public FieldType MyField { get; set; }
public string MyFieldValue => MyField.Value;
public string Description { get; set; }
public int Capacity { get; set; }
}
Upvotes: 2