Custom EditorAttribute

6 posts, 0 answers
  1. Hafsa
    Hafsa avatar
    8 posts
    Member since:
    Mar 2013

    Posted 10 Feb Link to this post

    Hello,

    I am using the RadPropertyGrid EditorAttribute to define the editor for a property. Currently, I only have the ability to pass the TargetProperty to my editor through this attribute. However, I would like to be able to pass some extra properties such as filters (not necessarily through binding).

     My current code looks like this:

    [Telerik.Windows.Controls.Data.PropertyGrid.Editor(typeof(MultipleTagsEditorPreview), "Value", Telerik.Windows.Controls.Data.PropertyGrid.EditorStyle.None)]
    public ObservableCollection<TagConfiguration> Tags {get;set;} //Full block removed for brevity

    What I would like to do is something like this:

    [Telerik.Windows.Controls.Data.PropertyGrid.Editor(typeof(MultipleTagsEditorPreview), "Value", Telerik.Windows.Controls.Data.PropertyGrid.EditorStyle.None, "Filter1,Filter2,Filter3")]
     public ObservableCollection<TagConfiguration> Tags { get;set;}
     

    For obvious reasons, I can't create a new editor for every combination of filters. I think it might be easier to inherit the EditorAttribute class and override it to contain a Filters property and have my own constructor that calls the base constructor. But I am not sure how to pass my properties to the editor once it has been instantiated by the RadPropertyGrid. Is there some behavior that I can override to do this? For example:

    MultipleTagsEditorPreview editor = Activator.CreateInstance(this.EditorType);
    editor.Filters = this.Filters; //this is where I would pass the filters to my editor
    return editor;

     

    Any help would be appreciated,

    Thanks

     

  2. Maya
    Admin
    Maya avatar
    4062 posts

    Posted 15 Feb Link to this post

    Hello Hafsa,

    Why don't you try passing the DataContext and then handle the logic inside your custom control?
    Generally, when you have the following definition: 
    [Telerik.Windows.Controls.Data.PropertyGrid.Editor(typeof(PhoneEditorControl)]

    The DataContext of the editor will be the corresponding property. And if that property is a kind of a ViewModel and holds the information you need (the Filters), you will be able to bind the custom control as you need. 

    Regards,
    Maya
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. UI for WPF is Visual Studio 2017 Ready
  4. BENN
    BENN avatar
    59 posts
    Member since:
    Dec 2011

    Posted 16 Feb in reply to Maya Link to this post

    Because Maya,

    Sometimes you just switch from one property grid to another, or already written a code and don't want to change your entire code for it.

    Sometimes, and bound property is just a simple observable collection, or even a value type (like an int), and you don't want to create a view model just for it.

     

    I'll give you an example: The opacity, width and height of elements in WPF are double. Microsoft does not wrap then with another class (because it is pointless), but however, you still see the Visual Studio property grid, and also in Blend property grid, that the Editor for these properties is a slider, whereas in the Opacity, it is limited for values 0 to 1 (or 0 to 100%)

     

    I had the same problem. I have a custom slider that gets in the Ctor some properties like min, max etc. It was a UserControl, so I couldn't inherit just the code (assuming that the user control is located on another assembly). It that was working, I would also need to have like 7 sub classes for the custom slider, which each of them just passes a different min max etc.

    This is off course, an absurd.

     

    Activator.CreateInstance gets params in its ctor, so you could pass some arguments in the Editor attribute to be used.

    However, this is not the best solution, since most controls don't have a ctor that accepts parameters (since it is meant to be used in Xaml).

     

    For this reason (and due to the Editor limitation), I had to figure a solution.

     

    I've made up with a custom attribute called PropertyValueAttribute:

     

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
    public class PropertyValueAttribute : Attribute
    {
        string _propertyName;
        object _value
            ;
        public PropertyValueAttribute(string propertyName, object value)
        {
            _propertyName = propertyName;
            _value = value;
        }
     
        public override object TypeId
        {
            get
            {
                return this;
            }
        }
     
        public string PropertyName
        {
            get
            {
                return _propertyName;
            }
        }
     
        public object Value
        {
            get
            {
                return _value;
            }
        }
    }

     

    Then, I put it above my property, for example:

     

    [Display(Name = "Opacity", GroupName = "Properties of Appearance", Order = 500),
    Telerik.Windows.Controls.Data.PropertyGrid.Editor(typeof(CustomSliderView), "Value"), PropertyValue("Minimum", 0), PropertyValue("Maximum", 100), PropertyValue("AdditionalChar", "%")]
    public int ElementOpacity
    {
        get
        {
            return (int)(Opacity * 100);
        }
        set
        {
            Opacity = value / 100.0;
        }
    }

     

    Then, when the actual editor is being created... Which is in the FieldLoaded Event, I apply my properties as follows:

    private void propertyGrid_FieldLoaded(object sender, FieldEventArgs e)
    {
        var pd = e.Field.DataContext as PropertyDefinition;
     
        // Prevent reflection if not needed
        if (pd != null)
        {
            var desc = pd.SourceProperty.Descriptor as PropertyDescriptor;
            for (int i = 0; i < desc.Attributes.Count; i++)
            {
                var att = desc.Attributes[i];
                if (att is PropertyValueAttribute)
                {
                    PropertyInfo propertyInfo = e.Field.Content.GetType().GetProperty((att as PropertyValueAttribute).PropertyName);
                    // make sure object has the property we are after
                    if (propertyInfo != null)
                    {
                        propertyInfo.SetValue(e.Field.Content, (att as PropertyValueAttribute).Value, null);
                    }
                }
            }
        }
    }

     

    This off course doesn't work when you merge several objects into one (by selecting Union or Intersect, and passing an IEnumerable of objects), since in this case you ignore all attributes (including the editor), but this is a special scenario.

     

     

     


     
  5. Maya
    Admin
    Maya avatar
    4062 posts

    Posted 18 Feb Link to this post

    Hello Benn,

    My suggestion was to create a wrapper object that will hold all the information from the custom attribute and everything else you need and to use that type for the property of the business object - so instead of being int ElementOpacity to be MyViewModel ElementOpacity. Then, when you work with the editor, you will be able to set the properties - like Maximum, Minimum, etc. to your custom editor. My presumption was that you will work with one custom editor for similar properties, i.e. slider for numeric properties. 
    Nevertheless, I am happy to see that you found a  more appropriate solution for your scenario. Let us know in case we can be of any further assistance.

    Regards,
    Maya
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  6. BENN
    BENN avatar
    59 posts
    Member since:
    Dec 2011

    Posted 18 Feb in reply to Maya Link to this post

    Hi Maya,

    Actually, I'm not the original author of this thread. I just replied in order to suggest why wrapping the property with an object is not always a good solution, and to also offer the author a solution.

  7. Hafsa
    Hafsa avatar
    8 posts
    Member since:
    Mar 2013

    Posted 23 Feb Link to this post

    Thanks Maya and Benn for your answers! Maya, using the DataContext indeed works. Benn, your solution is very creative and useful for my particular scenario, especially since I don't have to create extra variables to bind to. Thanks a lot.

    Hafsa

Back to Top
UI for WPF is Visual Studio 2017 Ready