We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date
close icon

Dynamic Properties for PropertyGrid at runtime

Hello!

I have searched through many examples about the PropertyGrid, and none of which have solved this task. I have custom objects that have a dynamic list of attributes/properties which I am storing in a dictionary. The issue is I want to be able to add properties with custom names and values, and these properties can be added at runtime. Keep in mind, I would simply need a string for both the keys and values (no need to check for doubles, longs, or other types right now).

This is being done in MVVM, and as I mentioned, my view models don't have the Properties statically made at compile time. I would need to dynamically add the attributes to this property grid and then allow for editing the values. Is this even possible with the PropertyGrid?

Any help is greatly appreciated.

6 Replies

KP Kanniyappan Panneer Selvam Syncfusion Team September 16, 2019 04:46 PM UTC

Hi Austin Hale, 
 
Thanks for contacting Syncfusion support. 
 
Currently we are working on your queries at our end and we will provide more details on 17th September 2019. 
 
Regards, 
Kanniyappan P 



KP Kanniyappan Panneer Selvam Syncfusion Team September 17, 2019 01:14 PM UTC

Hi Austin Hale, 
 
Sorry for the delay. 
 
Currently we are working on to prepare a sample based on your requirement and we will update you the details with sample on 18th September, 2019. 
 
We appreciate your patience until then. 
 
Regards, 
Kanniyappan P 



AH Austin Hale September 18, 2019 02:58 PM UTC

Hello Kanniyappan Panneer Selvam!

I appreciate the quick response and look forward to viewing the sample that is being prepared. I'm not sure if this is the correct way to go about this task, but perhaps this may serve you further in understanding what I'm trying to accomplish:

In a viewmodel, I have made the following property, which I put as the propertyGrid.SelectedObject in my code behind of the xaml file:

     public PropertyBag Properties {get; set;}

The PropertyBag class implements a Dictionary(string, object) and the ICustomTypeDescriptor in the following way:

    ///
    /// PropertyBagList contains the property bag and its contents.
    ///
    public class PropertyBag : Dictionary-string, object-, ICustomTypeDescriptor
    {
        AttributeCollection ICustomTypeDescriptor.GetAttributes()
        {
            return new AttributeCollection(null);
        }

        string ICustomTypeDescriptor.GetClassName()
        {
            return null;
        }

        string ICustomTypeDescriptor.GetComponentName()
        {
            return null;
        }

        TypeConverter ICustomTypeDescriptor.GetConverter()
        {
            return null;
        }

        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        {
            return null;
        }

        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return null;
        }

        object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
        {
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return new EventDescriptorCollection(null);
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
        {
            return new EventDescriptorCollection(null);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return ((ICustomTypeDescriptor)this).GetProperties(null);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            List properties = new List();

            //Add property descriptors for each entry in the dictionary
            foreach (string key in this.Keys)
            {
                properties.Add(new PropertyBagPropertyDescriptor(key));
            }
            return new PropertyDescriptorCollection(properties.ToArray());
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }
    }


And lastly, I have a PropertyBagPropertyDescriptor set up as such:

    public class PropertyBagPropertyDescriptor : PropertyDescriptor
    {
        #region Constructor
        ///
        /// Constructor - sets the Property Descriptor class and sets the key as the name.
        ///
        /// The key to be set as the name of the descriptor.
        public PropertyBagPropertyDescriptor(string key) : base(key, null) { }
        #endregion

        #region Properties
        ///
        /// Gets the Property Type
        ///
        public override Type PropertyType
        {
            get { return typeof(string); }
        }

        ///
        /// Gets whether it's read only
        ///
        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override bool IsBrowsable => true;

        ///
        /// Gets the Component Type
        ///
        public override Type ComponentType
        {
            get { return typeof(Dictionary); }
        }
        #endregion

        #region Methods
        ///
        /// Gets the value from the dictionary.
        ///
        ///
        /// The value obtained from the dictionary.
        public override object GetValue(object component)
        {
            return ((Dictionary)component)[base.Name];
        }

        ///
        /// Sets the value in the dictionary.
        ///
        ///
        /// The value to be set in the dictionary.
        public override void SetValue(object component, object value)
        {
            ((Dictionary)component)[base.Name] = value;
        }

        ///
        /// Resets the value to empty string.
        ///
        ///
        public override void ResetValue(object component)
        {
            ((Dictionary)component)[base.Name] = null;
        }

        ///
        /// Gets whether value can be reset.
        ///
        ///
        /// Boolean for whether it can be reset.
        public override bool CanResetValue(object component)
        {
            return true;
        }

        ///
        /// Gets whether the value should be serialized.
        ///
        ///
        /// Boolean for if the value should be serialized.
        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
        #endregion
    }

Let me know if there is any confusion, or any ways I can fix it based on what I currently have. When I debug and step through, the Dictionary is being loaded with the correct custom keys and values, but they are still not showing up in the SyncFusion PropertyGrid. I'm not sure if I am missing something that SyncFusion is looking for and thus, it is not displaying properly. Any help is appreciated.



KP Kanniyappan Panneer Selvam Syncfusion Team September 18, 2019 03:57 PM UTC

Hi Austin Hale, 
 
Thanks for your patience. 
 
We have checked your query and prepared the sample based on your requirement. In our sample, we have added the properties (Key, value pair along with string type) with custom names and values and the properties with values are dynamically added with help of IDictionary property (Details) and the view model class (CandiateDetails) has assigned as selected object of PropertyGrid. Please find the code snippet, screenshot and sample for the same. 
 
Code Snippet: 
 
string candidateName = "John"
string candidateAddress = "435 East Coast Road"
int age = 30; 
candidateDetails.Details.Add("Name", candidateName); 
candidateDetails.Details.Add("Address", candidateAddress); 
candidateDetails.Details.Add("Age", age); 
propertyGrid.SelectedObject = candidateDetails; 
 
 
private IDictionary<string, object> details = new Dictionary<string, object>(); 
     
 
        public IDictionary<string, object> Details 
       
            get { return details; } 
            set 
           
                details = value; 
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Details")); 
           
        } 
 
 
Screenshot: 
 
 
 
 
Please try the above solution and let us know if it is helpful. 
 
Regards, 
Kanniyappan P 



AH Austin Hale September 18, 2019 08:34 PM UTC

Thank you so much! With that sample, I was able to make some changes and get ours working the way we intended.

One thing of note: we wanted to make sure it wouldn't update the view at runtime when we change the selected object (e.g. to a new Button( )). At first, it wouldn't work. We had to add a Dispatcher.Invoke to make sure it updating the view on the same (main) thread, otherwise, the view would not update.

Again, much appreciated!


KP Kanniyappan Panneer Selvam Syncfusion Team September 19, 2019 09:10 AM UTC

Hi Austin Hale, 
 
Thanks for your update. 
 
PropertyGrid control can be accessed in the same thread it was created, if we try to access it any other background thread, it will lead to crash. As you mentioned, you can access through dispatcher. 
  
Please let us know if you have any further queries. 
 
Regards, 
Kanniyappan P 


Loader.
Live Chat Icon For mobile
Up arrow icon