PropertyGrid : Dictionary Not Displaying Values using ICustomTypeDescriptor

PropertyGrid : Dictionary Not Displaying Values using ICustomTypeDescriptor

Currently I can only get the names of the dynamic properties to display not the values, the values result in the follow errors:

System.Windows.Data Error: 40 : BindingExpression path error: 'Test' property not found on 'object' ''ConcurrentDictionary<code>2' (HashCode=47097466)'. BindingExpression:Path=Test.With.Dots; DataItem='ConcurrentDictionary</code>2' (HashCode=47097466); target element is 'DescriptorPropertyDefinition' (HashCode=52822235); target property is 'Value' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'Test2' property not found on 'object' ''ConcurrentDictionary<code>2' (HashCode=47097466)'. BindingExpression:Path=Test2.With.Dots; DataItem='ConcurrentDictionary</code>2' (HashCode=47097466); target element is 'DescriptorPropertyDefinition' (HashCode=57448811); target property is 'Value' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'Test' property not found on 'object' ''ConcurrentDictionary<code>2' (HashCode=47097466)'. BindingExpression:Path=Test; DataItem='ConcurrentDictionary</code>2' (HashCode=47097466); target element is 'DescriptorPropertyDefinition' (HashCode=25770419); target property is 'Value' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'Test2' property not found on 'object' ''ConcurrentDictionary<code>2' (HashCode=47097466)'. BindingExpression:Path=Test2; DataItem='ConcurrentDictionary</code>2' (HashCode=47097466); target element is 'DescriptorPropertyDefinition' (HashCode=24589509); target property is 'Value' (type 'Object')

MainWindow.xaml

<Window
    x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    Title="MainWindow"
    Width="525"
    Height="350"
    mc:Ignorable="d">
    <Grid>
        <xctk:PropertyGrid x:Name="PropertyGrid" />
    </Grid>
</Window>

MainWindow.xaml.cs

namespace WpfApplication1
{
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Constructors and Destructors

        public MainWindow()
        {
            this.InitializeComponent();

            this.Variables["Test"] = false;
            this.Variables["Test2"] = 200;
            this.Variables["Test.With.Dots"] = 200.5;
            this.Variables["Test2.With.Dots"] = "help";

            this.PropertyGrid.SelectedObject = new DictionaryPropertyGridAdapter<string, object>(this.Variables);
        }

        #endregion

        public IDictionary<string, object> Variables { get; set; } = new ConcurrentDictionary<string, object>();
    }
}

DictionaryPropertyGridAdapter.cs

namespace WpfApplication1
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Reflection;
    using System.Runtime.CompilerServices;

    [RefreshProperties(RefreshProperties.All)]
    public class DictionaryPropertyGridAdapter<T, U> : ICustomTypeDescriptor, INotifyPropertyChanged
    {
        #region Fields

        private readonly IDictionary<T, U> dictionary;

        #endregion

        #region Constructors and Destructors

        public DictionaryPropertyGridAdapter(IDictionary<T, U> dictionary)
        {
            this.dictionary = dictionary;
        }

        #endregion

        #region Events

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        [Browsable(false)]
        public U this[T key]
        {
            get
            {
                return this.dictionary[key];
            }
            set
            {
                this.dictionary[key] = value;
            }
        }

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return null;
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            ArrayList properties = new ArrayList();
            foreach (var e in this.dictionary)
            {
                properties.Add(new DictionaryPropertyDescriptor(this.dictionary, e.Key));
            }

            PropertyDescriptor[] props = (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor));

            return new PropertyDescriptorCollection(props);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this.dictionary;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public class DictionaryPropertyDescriptor : PropertyDescriptor
        {
            #region Fields

            private readonly IDictionary<T, U> dictionary;

            private readonly T key;

            #endregion

            #region Constructors and Destructors

            internal DictionaryPropertyDescriptor(IDictionary<T, U> dictionary, T key)
                : base(key.ToString(), null)
            {
                this.dictionary = dictionary;
                this.key = key;
            }

            #endregion

            public override Type ComponentType => null;

            public override bool IsReadOnly => false;

            public override Type PropertyType => this.dictionary[this.key].GetType();

            public override bool CanResetValue(object component)
            {
                return false;
            }

            public override object GetValue(object component)
            {
                return this.dictionary[this.key];
            }

            public override void ResetValue(object component)
            {

            }

            public override void SetValue(object component, object value)
            {
                this.dictionary[this.key] = (U)value;
            }

            public override bool ShouldSerializeValue(object component)
            {
                return false;
            }
        }
    }
}