Property grid losing data...

Grids for WPF Forum

Posted 13 years ago by SledgeHammer01
Version: 10.2.0531
Avatar
I have a property grid thats bound to an object through a couple of layers of indirection. A bit complicated to explain that part :).

I have this class:

    public class PropertyDescriptorDataAccessorEx : PropertyDescriptorDataAccessor
    {
        #region Fields

        private string _strDisplayName;
        private string _strDescription;
        private bool _bIsReadonly;

        #endregion

        #region Constructors

        public PropertyDescriptorDataAccessorEx(object target, string propertyName)
            : base(target, propertyName)
        {
            // set the default values

            _strDisplayName = propertyName;
            _bIsReadonly = base.IsReadOnly;

            // need to use reflection to get the description

            Type t = target.GetType();

            if (t != null)
            {
                PropertyInfo pi = t.GetProperty(propertyName);

                if (pi != null)
                {
                    DescriptionAttribute[] da = (DescriptionAttribute[])pi.GetCustomAttributes(typeof(DescriptionAttribute), false);

                    if (da != null)
                        _strDescription = da[0].Description;
                }
            }
        }

        public PropertyDescriptorDataAccessorEx(object target, string propertyName, string displayName, string description)
            : base(target, propertyName)
        {
            _strDisplayName = displayName;
            _strDescription = description;
            _bIsReadonly = base.IsReadOnly;
        }

        #endregion

        #region Properties

        public bool IsReadOnlyEx
        {
            get
            {
                return _bIsReadonly;
            }

            set
            {
                if (_bIsReadonly != value)
                {
                    _bIsReadonly = value;

                    // fire the change notifications

                    OnPropertyChanged("IsReadOnly");
                    OnPropertyChanged("IsReadOnlyInternal");
                }
            }
        }

        #endregion

        #region Overrides

        public override bool IsReadOnly
        {
            get
            {
                return _bIsReadonly;
            }
        }

        protected override string DescriptionInternal
        {
            get
            {
                return _strDescription;
            }
        }

        protected override string DisplayNameInternal
        {
            get
            {
                return _strDisplayName;
            }
        }

        #endregion
    }
This class allows me to toggle item read-only states in the property grid at runtime. I have used it in various places and it seems like it works fine.

However, in one particular view, its causing the property grid to set the property to null. However, ReadOnly False -> True works FINE, but True -> False fails. It seems to set the property to null.

The setter looks like its getting called from somewhere within the property grid.

Here is the call stack from IsReadOnly = False -> my setter getting called with null. Hopefully you can see whats going on from the call stack, because ripping this out into a sample app is going to be almost impossible.

ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.ReflectionPropertyDescriptor.SetValue(object component = {FirstAmerican.RubiSoft.TemplateManager.FieldProxyIndirect}, object value = null) + 0xfb bytes
ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.PropertyDescriptorDataAccessor.ValueInternal.set(object value = null) + 0x16c bytes
ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.CachedPropertyDataAccessorBase.Value.set(object value = null) + 0x94 bytes
ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.PropertyGridDataAccessorItem.Value.set(object value = null) + 0x74 bytes
[Native to Managed Transition]
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.SetValue(object item, object value) + 0x106 bytes
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.UpdateValue(object value) + 0xa3 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.UpdateSource(object value = null) + 0x99 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.UpdateValue() + 0x66 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.Update(bool synchronous) + 0x4f bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Dirty() + 0x30 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.SetValue(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, object value) + 0x27 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp = {System.Windows.DependencyProperty}, object value = null, System.Windows.PropertyMetadata metadata = {System.Windows.FrameworkPropertyMetadata}, bool coerceWithDeferredReference = false, bool coerceWithCurrentValue = true, System.Windows.OperationType operationType = Unknown, bool isInternal) + 0x3c7 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty dp, object value) + 0x35 bytes
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.UpdatePublicSelectionProperties() + 0x1d4 bytes
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.SelectionChanger.End() + 0x6f bytes
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(object item, bool assumeInItemsCollection) + 0x11d bytes
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.OnSelectedIndexChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) + 0xf5 bytes
WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x4c bytes
PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x50 bytes
WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) + 0x3c bytes
WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex = {System.Windows.EntryIndex}, System.Windows.DependencyProperty dp = {System.Windows.DependencyProperty}, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry = {System.Windows.EffectiveValueEntry}, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) + 0x723 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) + 0x2eb bytes
WindowsBase.dll!System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty dp, object value) + 0x35 bytes
PresentationFramework.dll!System.Windows.Controls.ComboBox.TextUpdated(string newText = "", bool textBoxUpdated = false) + 0x1f3 bytes
PresentationFramework.dll!System.Windows.Controls.ComboBox.OnTextChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) + 0x89 bytes
WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x4c bytes
PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x50 bytes
WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) + 0x3c bytes
WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex = {System.Windows.EntryIndex}, System.Windows.DependencyProperty dp = {System.Windows.DependencyProperty}, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry = {System.Windows.EffectiveValueEntry}, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) + 0x723 bytes
WindowsBase.dll!System.Windows.DependencyObject.InvalidateProperty(System.Windows.DependencyProperty dp) + 0xad bytes
PresentationFramework.dll!System.Windows.StyleHelper.InvalidateDependents(System.Windows.Style ownerStyle, System.Windows.FrameworkTemplate frameworkTemplate, System.Windows.DependencyObject container = {System.Windows.Controls.ContentPresenter}, System.Windows.DependencyProperty dp, ref MS.Utility.FrugalStructList<System.Windows.ChildPropertyDependent> dependents, bool invalidateOnlyContainer = false) + 0x7a bytes
PresentationFramework.dll!System.Windows.StyleHelper.OnBindingValueInTemplateChanged(object sender, MS.Internal.Data.BindingValueChangedEventArgs e = {MS.Internal.Data.BindingValueChangedEventArgs}) + 0xe0 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.ChangeValue(object newValue, bool notify) + 0x8f bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.TransferValue(object newValue, bool isASubPropertyChange) + 0x1f2 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.ScheduleTransfer(bool isASubPropertyChange) + 0x3b bytes
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.NewValueAvailable(bool dependencySourcesChanged, bool initialValue, bool isASubPropertyChange) + 0x5c bytes
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(int k, System.ComponentModel.ICollectionView collectionView, object newValue, bool isASubPropertyChange) + 0x1d4 bytes
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.OnDependencyPropertyChanged(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, bool isASubPropertyChange) + 0x97 bytes
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.OnSourceInvalidation(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, bool isASubPropertyChange) + 0x1c bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.HandlePropertyInvalidation(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs args) + 0xa8 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.OnPropertyInvalidation(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs args) + 0x5f bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.OnPropertyInvalidation(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs args) + 0xcc bytes
WindowsBase.dll!System.Windows.DependentList.InvalidateDependents(System.Windows.DependencyObject source = {System.Windows.Controls.ComboBox}, System.Windows.DependencyPropertyChangedEventArgs sourceArgs) + 0x89 bytes
WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) + 0x19b bytes
WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex = {System.Windows.EntryIndex}, System.Windows.DependencyProperty dp = {System.Windows.DependencyProperty}, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry = {System.Windows.EffectiveValueEntry}, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) + 0x723 bytes
WindowsBase.dll!System.Windows.DependencyObject.InvalidateProperty(System.Windows.DependencyProperty dp) + 0xad bytes
PresentationFramework.dll!System.Windows.StyleHelper.InvalidateDependents(System.Windows.Style ownerStyle, System.Windows.FrameworkTemplate frameworkTemplate, System.Windows.DependencyObject container = {System.Windows.Controls.ContentPresenter}, System.Windows.DependencyProperty dp, ref MS.Utility.FrugalStructList<System.Windows.ChildPropertyDependent> dependents, bool invalidateOnlyContainer = false) + 0x7a bytes
PresentationFramework.dll!System.Windows.StyleHelper.OnBindingValueInTemplateChanged(object sender, MS.Internal.Data.BindingValueChangedEventArgs e = {MS.Internal.Data.BindingValueChangedEventArgs}) + 0xe0 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.ChangeValue(object newValue, bool notify) + 0x8f bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.TransferValue(object newValue, bool isASubPropertyChange) + 0x1f2 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.ScheduleTransfer(bool isASubPropertyChange) + 0x3b bytes
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.NewValueAvailable(bool dependencySourcesChanged, bool initialValue, bool isASubPropertyChange) + 0x5c bytes
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(int k, System.ComponentModel.ICollectionView collectionView, object newValue, bool isASubPropertyChange) + 0x1d4 bytes
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.OnSourcePropertyChanged(object o, string propName) + 0x84 bytes
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.System.Windows.IWeakEventListener.ReceiveWeakEvent(System.Type managerType, object sender, System.EventArgs e) + 0xa2 bytes
WindowsBase.dll!System.Windows.WeakEventManager.DeliverEventToList(object sender = {ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.PropertyGridDataAccessorItem}, System.EventArgs args = {System.ComponentModel.PropertyChangedEventArgs}, System.Windows.WeakEventManager.ListenerList list = {System.Windows.WeakEventManager.ListenerList}) + 0x5e bytes
WindowsBase.dll!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(object sender = {ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.PropertyGridDataAccessorItem}, System.ComponentModel.PropertyChangedEventArgs args) + 0x43a bytes
ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.PropertyGridDataAccessorItem.OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e = {System.ComponentModel.PropertyChangedEventArgs}) + 0x45 bytes
ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.PropertyGridDataAccessorItem.ReceiveWeakEvent(System.Type managerType = {Name = "PropertyChangedEventManager" FullName = "System.ComponentModel.PropertyChangedEventManager"}, object sender = {FirstAmerican.RubiSoft.UI.PropertyDescriptorDataAccessorEx}, System.EventArgs e = {System.ComponentModel.PropertyChangedEventArgs}) + 0x1f8 bytes
WindowsBase.dll!System.Windows.WeakEventManager.DeliverEventToList(object sender = {FirstAmerican.RubiSoft.UI.PropertyDescriptorDataAccessorEx}, System.EventArgs args = {System.ComponentModel.PropertyChangedEventArgs}, System.Windows.WeakEventManager.ListenerList list = {System.Windows.WeakEventManager.ListenerList}) + 0x5e bytes
WindowsBase.dll!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(object sender = {FirstAmerican.RubiSoft.UI.PropertyDescriptorDataAccessorEx}, System.ComponentModel.PropertyChangedEventArgs args) + 0x43a bytes
ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.DataAccessorBase.OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e = {System.ComponentModel.PropertyChangedEventArgs}) + 0x42 bytes
ActiproSoftware.PropertyGrid.Wpf351.dll!ActiproSoftware.Windows.Controls.PropertyGrid.Primitives.DataAccessorBase.OnPropertyChanged(string propertyName = "IsReadOnly") + 0x40 bytes
FirstAmerican.RubiSoft.UI.dll!FirstAmerican.RubiSoft.UI.PropertyDescriptorDataAccessorEx.IsReadOnlyEx.set(bool value = false) Line 307 + 0xf bytes C#

Comments (4)

Posted 13 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hello,

It looks like the Selector control you are using is updating it's value and the PropertyGrid is just passing that value on to the property. So you may want to double check what value the Selector (maybe a ComboBox) is "selecting".

If you can't find the issue, please put together a small sample project that reproduces the issue and email it over to our support address. Once we have that we can take a closer look.


Actipro Software Support

Posted 13 years ago by SledgeHammer01
Avatar
The properties that are getting cleared are enums, so they are using the stock Actipro ComboBox editor.

The property is just defined like this:

[Description("Specifies the method used to identify the field.")]
public IdentifyType IdentifyType
{
get
{
return _fp.IdentifyType;
}

set
{
if (_fp.IdentifyType != value)
{
_fp.IdentifyType = value;
FirePropertyChangeNotification("IdentifyType");
}
}
}

So its not even specifying a custom editor. I use the same technique elsewhere and it works fine, but I will try put together a sample.
Posted 13 years ago by SledgeHammer01
Avatar
Miraculously, I was able to easily duplicate this in a small sample :). I have sent it to support.
Posted 13 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hello,

We've responded in detail to your support ticket, but wanted to include additional information for other users. This turns out to be a defect introduced in .NET 4. The behavior above is not present when targeting .NET 3.5.

The only workaround is to use a custom property editor, based on our BuiltinEditors.DynamicValueTemplateKey DataTemplate, but that expliclty binds the ComboBox Text or SelectedItem property. The default BuiltinEditors.DynamicValueTemplateKey DataTemplate toggles the binding between Text and SelectedItem, based on whether the property supports free-text entry, using Triggers. It appears that these Triggers are not being correctly applied in this case.


Actipro Software Support

The latest build of this product (v24.1.1) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.