This is a migrated thread and some comments may be shown as answers.

Run-Time defined EditorAttribute

1 Answer 133 Views
PropertyGrid
This is a migrated thread and some comments may be shown as answers.
Noel
Top achievements
Rank 1
Noel asked on 01 Oct 2014, 05:28 PM
Hello,

I ran into a snag recently that I realized was probably not a "common" request or feature set (due to most documentation/code examples).
The EditorAttribute  attribute class does its job for the compile-time defining of custom controls for properties. This part works well, however I was wondering if there is any other way to define custom controls of specific types for the RadPropertyGrid class at runtime?

Where was my "snag"?
Since The "target property" is passed to the constructor of the EditorAttribute when it is declared as an attribute above any given class's property/variable, any "target property" defined becomes a "static declaration" due to it being bound to a class's property's CustomProperty's constructor argument list within the assembly which ends up being a read-only list at run-time.

What scenario would require "run-time" defined EditorAttributes?
Since our scenario is a bit complex (run-time construction of classes), the easiest way to describe the issue would be that a "data container class" could have the same EditorAttribute defined for a generic property (as an example an Object class) of which could require the defined User Control Editor class to utilize different TargetProperty depending upon the type of the given example "Object class".

My temporary Fix (or potentially permanent with some instantiation reduction optimizations):
====================================================================
   public class CustomEditorAttribute : EditorAttribute
    {

        public CustomEditorAttribute(Type editorType)
            : base(editorType, GetTargetProperty(editorType), GetEditorStyle(editorType))
        {

        }

        public CustomEditorAttribute(Type editorType, EditorStyle editorStyle)
            : base(editorType, GetTargetProperty(editorType), GetEditorStyle(editorType))
        {

        }

        public CustomEditorAttribute(Type editorType, string targetProperty)
            : base(editorType, GetTargetProperty(editorType), GetEditorStyle(editorType))
        {
        }

        public CustomEditorAttribute(Type editorType, string targetProperty, EditorStyle editorStyle)
            : base(editorType, GetTargetProperty(editorType), GetEditorStyle(editorType))
        {

        }

        static CustomPropertyControl GetPropertyControl(Type type)
        {
            if (type.IsSubclassOf(typeof(CustomPropertyControl )))
            {
                return (CustomPropertyControl )InternalLib.AssemblyClassHelper.GetObjectInstance(type);
            }
            else
            {
                throw new Exception("The type (" + type.Name + ") is not a valid PropertyControl type!");
            }
        }

        public static String GetTargetProperty(Type type)
        {
            return GetPropertyControl(type).GetPropertyTargetName();
        }

        public static EditorStyle GetEditorStyle(Type type)
        {
            return GetPropertyControl(type).GetEditorStyle();
        }

    }
====================================================================
So, my current run-time assignment of EditorAttribute arguments "fix" was to derive from the EditorAttribute class and pass the results of statically defined methods within said class that invoke an instance of the Custom Editor Control class type defined within the EditorAttribute declaration in question.  The above code could also be modified further by passing a specific class type that is not the editor class in question, but a "type" container class which then could be modified at run-time based on different states of the application at the time of invocation.


Usage of the EditorAttribute Example:
====================================================================
...
        [InternalLib.PropertyControls.FieldProperties.CustomEditorAttribute(typeof(InternalLib.PropertyControls.ImagePropertyControl))]
        public Image ImageProperty
        {
            get
            {
                return imageProperty;
            }
            set
            {
                if (value != null && this.imageProperty != value)
                {
                    this.imageProperty = value;
                    this.OnPropertyChanged("ControlImage");
                    if (OnImageSourceChanged != null)
                    {
                        OnImageSourceChanged.Invoke(this.imageProperty.Source);
                    }
                }
            }
        }
...

Where:
public partial class ImagePropertyControl:CustomPropertyControl
{
...
        public override String GetPropertyTargetName()
        {
            return "SelectedItem";  //The control houses a RadListBox and as such the "SelectedItem" property of the listbox is the target property
        }

        public override EditorStyle GetEditorStyle()
        {
            return EditorStyle.Modal;
        } 

...
}

And where:
    public class BaseCustomPropertyControl:UserControl
    {
        
        public virtual String GetPropertyTargetName()
        {
            return String.Empty;
        }

        public virtual EditorStyle GetEditorStyle()
        {
            return EditorStyle.None;
        }
    }
====================================================================
However, it seems like a lot of work to simply be able to define the TargetPropery and the EditorStyle at run-time for a specific type.

Is there some way to (more easily) add EditorAttribute's programmatically to a RadPropertyGrid?

If not, then I figured I would post my current solution here in the event anyone else was trying to define class property EditorAttributes at run-time and needed one possible way to do it.

Cheers,

-Noel


p.s. 
~Side-Note on the included Code~
The code snippet included has an major optimization/instantiation issue.  One optimization one could do would be to create a
static dictionary in the BaseCustomPropertyControl class that is populated via a method always called in the BaseCustomPropertyControl
constructor that then in turn invokes the GetPropertyTargetName and GetEditorStyle methods (or is virtual and the child class is responsible
for returning proper information), stores both values into another container class/structure, and then adds the Key, as the Type, and
the Value, as the hypothetical container class, to the static dictionary which could then be checked via a static method defined within the
BaseCustomPropertyControl prior to constructing an entire new class instance each time.  This would reduce the number of
"bogus/ghost" instances of the child class derived from the BaseCustomPropertyControl (in this case it is the
ImagePropertyControl).  That would then reduce the number of times it would have to instantiate custom property controls (editors) when getting the TargetProperty and EditorStyle.
So, the example included in this post is strictly just a quick and dirty version.

1 Answer, 1 is accepted

Sort by
0
Maya
Telerik team
answered on 06 Oct 2014, 12:46 PM
Hello Noel,

Indeed, currently EditorAttribute will need to know the target property before the initialization and for the time being we have not received such a feature request. Nevertheless, I will log it into our system for further research to verify whether we can support this scenario as well. 
Thanks for the feedback and the provided solution. I am sure the community appreciates your cooperation. I have updated your Telerik points.


Regards,
Maya
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
Tags
PropertyGrid
Asked by
Noel
Top achievements
Rank 1
Answers by
Maya
Telerik team
Share this question
or