File: MS\Internal\Xml\Linq\ComponentModel\XComponentModel.cs
Web Access
Project: src\src\libraries\System.ComponentModel.TypeConverter\src\System.ComponentModel.TypeConverter.csproj (System.ComponentModel.TypeConverter)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Xml.Linq;
 
namespace MS.Internal.Xml.Linq.ComponentModel
{
    internal sealed class XTypeDescriptionProvider<T> : TypeDescriptionProvider
    {
        public XTypeDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(T)))
        {
        }
 
        public override ICustomTypeDescriptor GetTypeDescriptor([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type, object? instance)
        {
            return new XTypeDescriptor<T>(base.GetTypeDescriptor(type, instance));
        }
    }
 
    internal sealed class XTypeDescriptor<T> : CustomTypeDescriptor
    {
        public XTypeDescriptor(ICustomTypeDescriptor? parent) : base(parent)
        {
        }
 
        [RequiresUnreferencedCode(PropertyDescriptor.PropertyDescriptorPropertyTypeMessage)]
        public override PropertyDescriptorCollection GetProperties()
        {
            return GetProperties(null);
        }
 
        [RequiresUnreferencedCode(PropertyDescriptor.PropertyDescriptorPropertyTypeMessage + " " + AttributeCollection.FilterRequiresUnreferencedCodeMessage)]
        public override PropertyDescriptorCollection GetProperties(Attribute[]? attributes)
        {
            PropertyDescriptorCollection properties = new PropertyDescriptorCollection(null);
            if (attributes == null)
            {
                if (typeof(T) == typeof(XElement))
                {
                    properties.Add(new XElementAttributePropertyDescriptor());
                    properties.Add(new XElementDescendantsPropertyDescriptor());
                    properties.Add(new XElementElementPropertyDescriptor());
                    properties.Add(new XElementElementsPropertyDescriptor());
                    properties.Add(new XElementValuePropertyDescriptor());
                    properties.Add(new XElementXmlPropertyDescriptor());
                }
                else if (typeof(T) == typeof(XAttribute))
                {
                    properties.Add(new XAttributeValuePropertyDescriptor());
                }
            }
            foreach (PropertyDescriptor property in base.GetProperties(attributes))
            {
                properties.Add(property);
            }
            return properties;
        }
    }
 
    internal abstract class XPropertyDescriptor<T, TProperty> : PropertyDescriptor where T : XObject
    {
        public XPropertyDescriptor(string name) : base(name, null)
        {
        }
 
        public override Type ComponentType
        {
            get { return typeof(T); }
        }
 
        public override bool IsReadOnly
        {
            get { return true; }
        }
 
        public override Type PropertyType
        {
            get { return typeof(TProperty); }
        }
 
        public override bool SupportsChangeEvents
        {
            get { return true; }
        }
 
        public override void AddValueChanged(object component, EventHandler handler)
        {
            bool hasValueChangedHandler = GetValueChangedHandler(component) != null;
            base.AddValueChanged(component, handler);
            if (hasValueChangedHandler)
                return;
            T? c = component as T;
            if (c != null && GetValueChangedHandler(component) != null)
            {
                c.Changing += new EventHandler<XObjectChangeEventArgs>(OnChanging);
                c.Changed += new EventHandler<XObjectChangeEventArgs>(OnChanged);
            }
        }
 
        public override bool CanResetValue(object component)
        {
            return false;
        }
 
        public override void RemoveValueChanged(object component, EventHandler handler)
        {
            base.RemoveValueChanged(component, handler);
            T? c = component as T;
            if (c != null && GetValueChangedHandler(component) == null)
            {
                c.Changing -= new EventHandler<XObjectChangeEventArgs>(OnChanging);
                c.Changed -= new EventHandler<XObjectChangeEventArgs>(OnChanged);
            }
        }
 
        public override void ResetValue(object component)
        {
        }
 
        public override void SetValue(object? component, object? value)
        {
        }
 
        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
 
        protected virtual void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
        }
 
        protected virtual void OnChanging(object? sender, XObjectChangeEventArgs args)
        {
        }
    }
 
    internal sealed class XElementAttributePropertyDescriptor : XPropertyDescriptor<XElement, object>
    {
        private XDeferredSingleton<XAttribute>? _value;
        private XAttribute? _changeState;
 
        public XElementAttributePropertyDescriptor() : base("Attribute")
        {
        }
 
        public override object GetValue(object? component)
        {
            return _value = new XDeferredSingleton<XAttribute>((e, n) => e.Attribute(n), (component as XElement)!, null);
        }
 
        protected override void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Add:
                    XAttribute? a = sender as XAttribute;
                    if (a != null && _value.element == a.Parent && _value.name == a.Name)
                    {
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
                case XObjectChange.Remove:
                    a = sender as XAttribute;
                    if (a != null && _changeState == a)
                    {
                        _changeState = null;
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
            }
        }
 
        protected override void OnChanging(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Remove:
                    XAttribute? a = sender as XAttribute;
                    _changeState = a != null && _value.element == a.Parent && _value.name == a.Name ? a : null;
                    break;
            }
        }
    }
 
    internal sealed class XElementDescendantsPropertyDescriptor : XPropertyDescriptor<XElement, IEnumerable<XElement>>
    {
        private XDeferredAxis<XElement>? _value;
        private XName? _changeState;
 
        public XElementDescendantsPropertyDescriptor() : base("Descendants")
        {
        }
 
        public override object GetValue(object? component)
        {
            return _value = new XDeferredAxis<XElement>((e, n) => n != null ? e.Descendants(n) : e.Descendants(), (component as XElement)!, null);
        }
 
        protected override void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Add:
                case XObjectChange.Remove:
                    XElement? e = sender as XElement;
                    if (e != null && (_value.name == e.Name || _value.name == null))
                    {
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
                case XObjectChange.Name:
                    e = sender as XElement;
                    if (e != null && _value.element != e && _value.name != null && (_value.name == e.Name || _value.name == _changeState))
                    {
                        _changeState = null;
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
            }
        }
 
        protected override void OnChanging(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Name:
                    XElement? e = sender as XElement;
                    _changeState = e?.Name;
                    break;
            }
        }
    }
 
    internal sealed class XElementElementPropertyDescriptor : XPropertyDescriptor<XElement, object>
    {
        private XDeferredSingleton<XElement>? _value;
        private XElement? _changeState;
 
        public XElementElementPropertyDescriptor() : base("Element")
        {
        }
 
        public override object GetValue(object? component)
        {
            return _value = new XDeferredSingleton<XElement>((e, n) => e.Element(n), (component as XElement)!, null);
        }
 
        protected override void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Add:
                    XElement? e = sender as XElement;
                    if (e != null && _value.element == e.Parent && _value.name == e.Name && _value.element.Element(_value.name) == e)
                    {
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
                case XObjectChange.Remove:
                    e = sender as XElement;
                    if (e != null && _changeState == e)
                    {
                        _changeState = null;
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
                case XObjectChange.Name:
                    e = sender as XElement;
                    if (e != null)
                    {
                        if (_value.element == e.Parent && _value.name == e.Name && _value.element.Element(_value.name) == e)
                        {
                            OnValueChanged(_value.element, EventArgs.Empty);
                        }
                        else if (_changeState == e)
                        {
                            _changeState = null;
                            OnValueChanged(_value.element, EventArgs.Empty);
                        }
                    }
                    break;
            }
        }
 
        protected override void OnChanging(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Remove:
                case XObjectChange.Name:
                    XElement? e = sender as XElement;
                    _changeState = e != null && _value.element == e.Parent && _value.name == e.Name && _value.element.Element(_value.name) == e ? e : null;
                    break;
            }
        }
    }
 
    internal sealed class XElementElementsPropertyDescriptor : XPropertyDescriptor<XElement, IEnumerable<XElement>>
    {
        private XDeferredAxis<XElement>? _value;
        private object? _changeState;
 
        public XElementElementsPropertyDescriptor() : base("Elements")
        {
        }
 
        public override object GetValue(object? component)
        {
            return _value = new XDeferredAxis<XElement>((e, n) => n != null ? e.Elements(n) : e.Elements(), (component as XElement)!, null);
        }
 
        protected override void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Add:
                    XElement? e = sender as XElement;
                    if (e != null && _value.element == e.Parent && (_value.name == e.Name || _value.name == null))
                    {
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
                case XObjectChange.Remove:
                    e = sender as XElement;
                    if (e != null && _value.element == (_changeState as XContainer) && (_value.name == e.Name || _value.name == null))
                    {
                        _changeState = null;
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
                case XObjectChange.Name:
                    e = sender as XElement;
                    if (e != null && _value.element == e.Parent && _value.name != null && (_value.name == e.Name || _value.name == (_changeState as XName)))
                    {
                        _changeState = null;
                        OnValueChanged(_value.element, EventArgs.Empty);
                    }
                    break;
            }
        }
 
        protected override void OnChanging(object? sender, XObjectChangeEventArgs args)
        {
            if (_value == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Remove:
                    XElement? e = sender as XElement;
                    _changeState = e?.Parent;
                    break;
                case XObjectChange.Name:
                    e = sender as XElement;
                    _changeState = e?.Name;
                    break;
            }
        }
    }
 
    internal sealed class XElementValuePropertyDescriptor : XPropertyDescriptor<XElement, string>
    {
        private XElement? _element;
 
        public XElementValuePropertyDescriptor() : base("Value")
        {
        }
 
        public override bool IsReadOnly
        {
            get { return false; }
        }
 
        public override object GetValue(object? component)
        {
            _element = component as XElement;
            if (_element == null)
                return string.Empty;
            return _element.Value;
        }
 
        public override void SetValue(object? component, object? value)
        {
            _element = component as XElement;
            if (_element == null)
                return;
            _element.Value = (value as string)!;
        }
 
        protected override void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
            if (_element == null)
                return;
            switch (args.ObjectChange)
            {
                case XObjectChange.Add:
                case XObjectChange.Remove:
                    if (sender is XElement || sender is XText)
                    {
                        OnValueChanged(_element, EventArgs.Empty);
                    }
                    break;
                case XObjectChange.Value:
                    if (sender is XText)
                    {
                        OnValueChanged(_element, EventArgs.Empty);
                    }
                    break;
            }
        }
    }
 
    internal sealed class XElementXmlPropertyDescriptor : XPropertyDescriptor<XElement, string>
    {
        private XElement? _element;
 
        public XElementXmlPropertyDescriptor() : base("Xml")
        {
        }
 
        public override object GetValue(object? component)
        {
            _element = component as XElement;
            if (_element == null)
                return string.Empty;
            return _element.ToString(SaveOptions.DisableFormatting);
        }
 
        protected override void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
            if (_element == null)
                return;
            OnValueChanged(_element, EventArgs.Empty);
        }
    }
 
    internal sealed class XAttributeValuePropertyDescriptor : XPropertyDescriptor<XAttribute, string>
    {
        private XAttribute? _attribute;
 
        public XAttributeValuePropertyDescriptor() : base("Value")
        {
        }
 
        public override bool IsReadOnly
        {
            get { return false; }
        }
 
        public override object GetValue(object? component)
        {
            _attribute = component as XAttribute;
            if (_attribute == null)
                return string.Empty;
            return _attribute.Value;
        }
 
        public override void SetValue(object? component, object? value)
        {
            _attribute = component as XAttribute;
            if (_attribute == null)
                return;
            _attribute.Value = (value as string)!;
        }
 
        protected override void OnChanged(object? sender, XObjectChangeEventArgs args)
        {
            if (_attribute == null)
                return;
            if (args.ObjectChange == XObjectChange.Value)
            {
                OnValueChanged(_attribute, EventArgs.Empty);
            }
        }
    }
 
    internal sealed class XDeferredAxis<T> : IEnumerable<T>, IEnumerable where T : XObject
    {
        private readonly Func<XElement, XName?, IEnumerable<T>> _func;
        internal XElement element;
        internal XName? name;
 
        public XDeferredAxis(Func<XElement, XName?, IEnumerable<T>> func, XElement element, XName? name)
        {
            ArgumentNullException.ThrowIfNull(func);
            ArgumentNullException.ThrowIfNull(element);
 
            _func = func;
            this.element = element;
            this.name = name;
        }
 
        public IEnumerator<T> GetEnumerator()
        {
            return _func(element, name).GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
 
        public IEnumerable<T> this[string expandedName]
        {
            get
            {
                ArgumentNullException.ThrowIfNull(expandedName);
                if (name == null)
                {
                    name = expandedName;
                }
                else if (name != expandedName)
                {
                    return Enumerable.Empty<T>();
                }
                return this;
            }
        }
    }
 
    internal sealed class XDeferredSingleton<T> where T : XObject
    {
        private readonly Func<XElement, XName, T?> _func;
        internal XElement element;
        internal XName? name;
 
        public XDeferredSingleton(Func<XElement, XName, T?> func, XElement element, XName? name)
        {
            ArgumentNullException.ThrowIfNull(func);
            ArgumentNullException.ThrowIfNull(element);
 
            _func = func;
            this.element = element;
            this.name = name;
        }
 
        public T? this[string expandedName]
        {
            get
            {
                ArgumentNullException.ThrowIfNull(expandedName);
                if (name == null)
                {
                    name = expandedName;
                }
                else if (name != expandedName)
                {
                    return null;
                }
                return _func(element, name);
            }
        }
    }
}