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

RadPropertyGrid binding issue with ExpandoObject property whose value is null

6 Answers 268 Views
PropertyGrid
This is a migrated thread and some comments may be shown as answers.
Lauren
Top achievements
Rank 1
Lauren asked on 13 Jan 2014, 08:51 PM
I have a situation where I'm setting the RadPropertyGrid's Item to an ExpandoObject instance whose properties have been defined at run-time. I'm listening for the PropertyChanged event of the ExpandoObject to tell when a property has been updated.

I'm using the AutoGeneratingPropertyDefinition event to catch properties with specific names and assign an EditorDataTemplate that uses a RadNumericUpDown control. The problem is that the property value (let's just use the name "Prop1") is set by a nullable double, so sometimes Prop1 has a value, and sometimes its null. If Prop1 has a numeric value everything works great with the property editor, and I can change the field for Prop1 and it will change its corresponding value in the ExpandoObject perfectly.

However if Prop1 is set to null, its field shows up in the PropertyGrid but when I change the value I don't get any PropertyChanged event from the ExpandoObject. The event fires if I set a value to Prop1 in code-behind, but not if I try to change it from the PropertyGrid. This leads me to believe there is some sort of binding issue with the property grid and ExpandoObject properties with null values.

Any suggestions?

6 Answers, 1 is accepted

Sort by
0
Yoan
Telerik team
answered on 16 Jan 2014, 05:43 PM
Hello Lauren,

Unfortunately with the supplied information I cannot figure out what is going on. Would it be possible to share with us more details on your exact implementation? It would be great if you can send me a small sample with dummy data in order to investigate the issue locally.

Thank you in advance.


Regards,
Yoan
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Lauren
Top achievements
Rank 1
answered on 16 Jan 2014, 10:47 PM
Yoan,

Thank you for your reply. I actually found another way around my issue. Instead of using an ExpandoObject, I created my own class that inherits DynamicObject and implements ICustomTypeDescriptor and INotifyPropertyChanged. I also created a custom PropertyDescriptor class implementation as well. That way I keep track of what type a property is "supposed" to be even if it is null (which ExpandoObject currently does not do).

Thanks again!
- Lauren
0
Yoan
Telerik team
answered on 20 Jan 2014, 01:38 PM
Hi Lauren,

I am glad to hear that you have resolved the problem by yourself. 

Please, don't hesitate to ask if you need any further help.

Regards,
Yoan
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Chris
Top achievements
Rank 1
answered on 06 Nov 2015, 05:41 PM

Lauren,

     Would you mind sharing your solution. I'm trying to accomplish the same thing. Thank you.

0
Ivan Ivanov
Telerik team
answered on 11 Nov 2015, 05:19 PM
Hi,

I prepared a sample project with RadPropertyGrid with dynamic properties. You can use it as a starting point if you have any further questions.

Regards,
Ivan Ivanov
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
Chris
Top achievements
Rank 1
answered on 11 Nov 2015, 05:51 PM

Thank you Ivan.

 

For anyone else that is pursuing this approach, here is the code that is working for me.

 

private sealed class MyDynObject : DynamicObject, ICustomTypeDescriptor, INotifyPropertyChanged
  {
    private class OrderedProperty
    {
      public IProperty Property { get; set; }
      public int Order { get; set; }
    }
 
    private readonly Dictionary<string, OrderedProperty> dynamicProperties
      = new Dictionary<string, OrderedProperty>();
 
    public MyDynObject(ReadOnlyObservableCollection<IProperty> properties)
    {
      for (var i = 0; i < properties.Count; i++)
      {
        var property = properties[i];
        dynamicProperties.Add(property.Name, new OrderedProperty()
        {
          Property = property,
          Order = i
        });
        PropertyChangedEventManager.AddHandler(property, Property_PropertyChanged, nameof(IProperty.Value));
      }
    }
 
    private void Property_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      if (nameof(IProperty.Value).Equals(e.PropertyName))
      {
        OnPropertyChanged(((IProperty)sender).Name);
      }
    }
 
    public override IEnumerable<string> GetDynamicMemberNames()
    {
      return dynamicProperties.Keys;
    }
 
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
      if (dynamicProperties.ContainsKey(binder.Name))
      {
        result = dynamicProperties[binder.Name].Property.Value;
        return true;
      }
      result = null;
      return false;
    }
 
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
      if (dynamicProperties.ContainsKey(binder.Name))
      {
        dynamicProperties[binder.Name].Property.Value = value;
        OnPropertyChanged(binder.Name);
        return true;
      }
      return false;
    }
 
    #region Implementation of INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
 
    private void OnPropertyChanged(string propertyName)
    {
      if (PropertyChanged == null)
      {
        return;
      }
 
      var eventArgs = new PropertyChangedEventArgs(propertyName);
      PropertyChanged(this, eventArgs);
    }
    #endregion
 
    #region Implementation of ICustomTypeDescriptor
    public AttributeCollection GetAttributes()
    {
      throw new NotImplementedException();
    }
 
    public string GetClassName()
    {
      return GetType().Name;
    }
 
    public string GetComponentName()
    {
      throw new NotImplementedException();
    }
 
    public TypeConverter GetConverter()
    {
      throw new NotImplementedException();
    }
 
    public EventDescriptor GetDefaultEvent()
    {
      throw new NotImplementedException();
    }
 
    public PropertyDescriptor GetDefaultProperty()
    {
      throw new NotImplementedException();
    }
 
    public object GetEditor(Type editorBaseType)
    {
      throw new NotImplementedException();
    }
 
    public EventDescriptorCollection GetEvents()
    {
      throw new NotImplementedException();
    }
 
    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
      throw new NotImplementedException();
    }
 
    public PropertyDescriptorCollection GetProperties()
    {
      var properties = dynamicProperties
          .Select(pair => new DynamicPropertyDescriptor(this,
              pair.Key, pair.Value.Property.ValueType, GetAttributes(pair.Value)));
      return new PropertyDescriptorCollection(properties.Cast<PropertyDescriptor>().ToArray());
    }
 
    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
      throw new NotImplementedException();
    }
 
    public object GetPropertyOwner(PropertyDescriptor pd)
    {
      throw new NotImplementedException();
    }
 
    private Attribute[] GetAttributes(OrderedProperty orderedProperty)
    {
      var attributes = new Attribute[2];
      attributes[0] = new DisplayAttribute
      {
        Name = orderedProperty.Property.Name,
        Description = orderedProperty.Property.Description,
        GroupName = orderedProperty.Property.GroupName,
        Order = orderedProperty.Order
      };
      attributes[1] = new ReadOnlyAttribute(orderedProperty.Property.IsReadOnly);
      return attributes;
    }
    #endregion
 
 
 
 
    private class DynamicPropertyDescriptor : PropertyDescriptor
    {
      private readonly MyDynObject model;
 
      public DynamicPropertyDescriptor(MyDynObject model,
          string propertyName, Type propertyType, Attribute[] propertyAttributes)
          : base(propertyName, propertyAttributes)
      {
        this.model = model;
        PropertyType = propertyType;
      }
 
      public override bool CanResetValue(object component)
      {
        return true;
      }
 
      public override object GetValue(object component)
      {
        return model.dynamicProperties[Name].Property.Value;
      }
 
      public override void ResetValue(object component)
      {
      }
 
      public override void SetValue(object component, object value)
      {
        model.dynamicProperties[Name].Property.Value = value;
      }
 
      public override bool ShouldSerializeValue(object component)
      {
        return false;
      }
 
      public override Type ComponentType => typeof(MyDynObject);
 
      public override bool IsReadOnly => model.dynamicProperties[Name].Property.IsReadOnly;
 
      public override Type PropertyType { get; }
    }
  }

 

public interface IProperty : INotifyPropertyChanged
  {
    string Name { get; }
 
    object Value { get; set; }
 
    Type ValueType { get; }
 
    string Description { get; }
 
    bool IsReadOnly { get; }
 
    string GroupName { get; }
  }

 

Tags
PropertyGrid
Asked by
Lauren
Top achievements
Rank 1
Answers by
Yoan
Telerik team
Lauren
Top achievements
Rank 1
Chris
Top achievements
Rank 1
Ivan Ivanov
Telerik team
Share this question
or