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

Custom EditorAttribute

7 Answers 336 Views
PropertyGrid
This is a migrated thread and some comments may be shown as answers.
Hafsa
Top achievements
Rank 1
Hafsa asked on 10 Feb 2016, 10:24 AM

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

 

7 Answers, 1 is accepted

Sort by
0
Maya
Telerik team
answered on 15 Feb 2016, 09:14 AM
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
0
BENN
Top achievements
Rank 1
answered on 16 Feb 2016, 08:33 AM

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.

 

 

 


 
0
Maya
Telerik team
answered on 18 Feb 2016, 03:17 PM
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
0
BENN
Top achievements
Rank 1
answered on 18 Feb 2016, 04:53 PM

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.

0
Hafsa
Top achievements
Rank 1
answered on 23 Feb 2016, 12:03 PM

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

0
William
Top achievements
Rank 1
answered on 02 Feb 2017, 05:05 PM
You say that the DataContext of the editor will be the target property (specified in the Editor statement), but when I look at the DataContext for my custom editor (a UserControl), it refers only to the UserControl's ViewModel. Does the EditorAttribute logic handle classes rather than simple properties for it's target property?
0
Stefan Nenchev
Telerik team
answered on 07 Feb 2017, 01:38 PM
Hello William,

I am not absolutely sure of your setup but by default, the DataContext of the UserControl would be the property for which it is used as an editor. For example, in the Editor Attribute demo in our SDK Samples Application, the DataContext of the Custom Control(PhoneEditorControl) would be the object of type PhoneNumber, so you can bind to its relevant properties(CountryCode, Number, RegionCode). What are you trying to achieve at your end? Can you provide more details on your setup?

Regards,
Stefan Nenchev
Telerik by Progress
Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which you to write beautiful native mobile apps using a single shared C# codebase.
Tags
PropertyGrid
Asked by
Hafsa
Top achievements
Rank 1
Answers by
Maya
Telerik team
BENN
Top achievements
Rank 1
Hafsa
Top achievements
Rank 1
William
Top achievements
Rank 1
Stefan Nenchev
Telerik team
Share this question
or