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