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?
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
0
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
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 >>
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
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
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
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 >>
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
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
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; } }