OK, It would appear I have given you the earlier version of TestClass that didn't cause the problem because it wasn't using INotifyPropertyChanged handling that the one below does use. It would appear that it is when you are creating the binding to the value so I am guessing it must be using one way to source binding without the PropertyChanged event rather than TwoWay. (Note, I can't see how to add a file on this discussion ... presume there isn't that facility).
Code being used, xaml:
Code being used, xaml:
<Grid>
<Grid.DataContext>
<local:TestClass />
</Grid.DataContext>
<xctk:PropertyGrid SelectedObject="{Binding}" />
</Grid>
Latest version of testclass.cs:using System;
using System.Collections.Generic;
using System.ComponentModel;
public class TestSubData : INotifyPropertyChanged
{
public TestSubData()
{
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
private string mExtendedField;
public string ExtendedField
{
get { return mExtendedField; }
set
{
if (value != mExtendedField)
{
mExtendedField = value;
OnPropertyChanged("ExtendedField");
}
}
}
}
public class TestClass : ICustomTypeDescriptor
{
public TestClass()
{
SubInfo = new TestSubData();
this.Name = "My Name " + (new Random((int)DateTime.Now.Ticks).Next()).ToString();
this.SubInfo.ExtendedField = Name.Replace("Name", "Exended Value");
}
public string Name { get; set; }
[Browsable(false)]
public TestSubData SubInfo { get; set; }
#region ICustomTypeDescriptor implementation
#region Standard implementation
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
string ICustomTypeDescriptor.GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
string ICustomTypeDescriptor.GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
#endregion
#region Custom implmenetation
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
return GetCombinedProperties(attributes);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return GetCombinedProperties(null);
}
PropertyDescriptorCollection GetCombinedProperties(Attribute[] attributes)
{
PropertyDescriptorCollection ourPropsCollection = TypeDescriptor.GetProperties(this, attributes, true);
List<PropertyDescriptor> ourProps = new List<PropertyDescriptor>();
foreach (PropertyDescriptor prop in ourPropsCollection)
ourProps.Add(prop);
if (SubInfo == null)
SubInfo = new TestSubData();
if (SubInfo != null)
{
PropertyDescriptorCollection setProps = TypeDescriptor.GetProperties(SubInfo, attributes, true);
if (setProps != null)
{
foreach (PropertyDescriptor prop in setProps)
{
try
{
ourProps.Add(prop);
}
catch (Exception ex)
{
if (ex == null)
throw;
}
}
}
}
return new PropertyDescriptorCollection(ourProps.ToArray());
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this, true);
if (props.Contains(pd))
return this;
else
return SubInfo;
}
#endregion
#endregion ICustomTypeDescriptor implementation
}