I have a PropertyGrid with some class-properties bound to it.
Every property has an EditorAttribute
where i defined a custom class to make changes.
My wish is to make the string-property only editable through this Editor-class and not by editing through the PropertyGrid-textfield.
I tried changing its ReadOnly
-attribute to true
and then changing this value inside my editor-class before resetting it inside the properties setter-method with Reflection, but thats not working properly as the textfield stays in focus mode and I can still make changes. Furthermore for my this is more like a workaround, than an acceptable solution.
Is there a way to access the setter of my property only by the EditorComponent
-class and not by the PropertyGrid?
My custom Editor-class:
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
using (EditorForm f = new Forms.EditorForm(value.ToString()))
{
if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
PropertyDescriptor descriptor = context.PropertyDescriptor;
if (descriptor != null)
{
ReadOnlyAttribute attribute = descriptor.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
if (attribute != null)
{
System.Reflection.FieldInfo fieldToChange = attribute.GetType().GetField("isReadOnly", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (fieldToChange != null)
{
fieldToChange.SetValue(attribute, false); // setting it to false
value = f.Text;
}
}
}
}
}
return value;
}
and after this I rechange it in my setter-method:
private string _myText = String.Empty;
[Editor(typeof(...), typeof(UITypeEditor)),
ReadOnly(true)]
public string MyText
{
get { return _myText; }
set
{
_myText = value;
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["MyText"];
if (descriptor != null)
{
ReadOnlyAttribute attribute = descriptor.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
if (attribute != null)
{
System.Reflection.FieldInfo fieldToChange = attribute.GetType().GetField("isReadOnly", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (fieldToChange != null)
fieldToChange.SetValue(attribute, true); // resetting it to true
}
}
}
}
CodePudding user response:
You can add additional TypeConverter
which will prevent editing (by just discarding any conversions from string to destinatino type (even destination is also a string)).
After this you can remove all wired stuff with editing ReadOnlyAttribute
in rutime.
public class TestClass
{
[Editor(typeof(CustomEditor), typeof(UITypeEditor))]
[TypeConverter(typeof(ReadOnlyConverter))]
public string MyText { get; set; }
}
public class ReadOnlyConverter : TypeConverter
{
//just empty class
}
public class CustomEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
=> UITypeEditorEditStyle.Modal;
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
var strVal = value as string;
var svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
using (var editorForm = new EditorForm())
{
editorForm.Value = strVal;
svc.ShowDialog(editorForm);
value = editorForm.Value;
};
return value;
}
}
Additionally, you may want to add edditional check in EditValue
to be sure service is available, input value is a real string
and so on.
You can also override members of ReadOnlyConverter
to explicitly disable string conversion and not rely to default implementation.