简体   繁体   中英

Make a property only editable through the bound Editor(component)

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
         }
      }
    }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM