/// <summary>
        /// Registers type converter for <see cref="DataObject"/> with <see cref="DataObject.Type"/> equal to <paramref name="typeid"/>
        /// this type will be use as parameter for <see cref="TypeConverterAttribute"/> which is used by WindowsForms PropertyGrid
        /// </summary>
        /// <typeparam name="TEditor"></typeparam>
        /// <param name="typeid"></param>
        public static void RegisterConverter <TConverter>(string typeid)
            where TConverter : TypeConverter
        {
            var dataobj = DataObjectFactory.GetPropertyObject(typeid);

            if (dataobj is null)
            {
                return;
            }

            var type = dataobj.GetType();

            if (converterMapping.ContainsKey(type))
            {
                converterMapping[type] = typeof(TConverter);
            }
            else
            {
                converterMapping.Add(type, typeof(TConverter));
            }
        }
        /// <summary>
        /// Implementation for <see cref="DataObject.ReadXmlElement(string, XmlReader)"/>
        /// </summary>
        /// <param name="elementName"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        protected override bool ReadXmlElement(string elementName, XmlReader reader)
        {
            // call base implementation
            if (base.ReadXmlElement(elementName, reader))
            {
                return(true);
            }

            /// Read underlying type for <see cref="ContainerDataObject"/> created from CLR objects
            if (elementName == nameof(TypeInfo))
            {
                ObjectType = reader.ReadObjectXml <TypeInfo>();

                return(true);
            }

            /// Read <see cref="DataObject"/> implementation
            else
            {
                if (DataObjectFactory.GetPropertyObject(reader.GetAttribute(TYPE_ID_ATTRIBUTE)) is DataObject obj)
                {
                    using (var newReader = XmlReader.Create(new StringReader(reader.ReadOuterXml())))
                    {
                        newReader.Read();

                        obj.ReadXml(newReader);

                        if (obj.Type != DataObjectType.NotSupported)
                        {
                            _container.Add(obj);
                        }
                    }

                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Implementation for <see cref="DataObject.ReadXmlElement(string, XmlReader)"/>
        /// </summary>
        /// <param name="elementName"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        protected override bool ReadXmlElement(string elementName, XmlReader reader)
        {
            // call base
            if (base.ReadXmlElement(elementName, reader))
            {
                return(true);
            }

            /// Read DataObject implementation
            if (elementName == ContainerDataObject.DC_START_ELEMENT_NAME)
            {
                var obj = DataObjectFactory.GetPropertyObject("dc");

                if (obj != null)
                {
                    using (var newReader = XmlReader.Create(new StringReader(reader.ReadOuterXml())))
                    {
                        newReader.Read();

                        obj.ReadXml(newReader);

                        readingHelper.Add(obj);
                    }
                }

                return(true);
            }

            /// Read type info
            else if (elementName == nameof(TypeInfo))
            {
                CollectionType = reader.ReadObjectXml <TypeInfo>();

                return(true);
            }

            return(false);
        }
 /// <summary>
 /// Implementation for <see cref="DataContainerBase.GetUnitializedDataObject(string)"/>
 /// </summary>
 /// <param name="type"></param>
 /// <returns></returns>
 protected override DataObject GetUnitializedDataObject(string type)
 {
     return(DataObjectFactory.GetPropertyObject(type));
 }