File: System\ComponentModel\NestedContainer.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.Diagnostics.CodeAnalysis;
using System.Globalization;
 
namespace System.ComponentModel
{
    /// <summary>
    /// A nested container is a container that is owned by another component. Nested
    /// containers can be found by querying a component site's services for NestedConainter.
    /// Nested containers are a useful tool to establish owner relationships among components.
    /// All components within a nested container are named with the owning component's name
    /// as a prefix.
    /// </summary>
    public class NestedContainer : Container, INestedContainer
    {
        /// <summary>
        /// Creates a new NestedContainer.
        /// </summary>
        public NestedContainer(IComponent owner)
        {
            ArgumentNullException.ThrowIfNull(owner);
 
            Owner = owner;
            Owner.Disposed += new EventHandler(OnOwnerDisposed);
        }
 
        /// <summary>
        /// The component that owns this nested container.
        /// </summary>
        public IComponent Owner { get; }
 
        /// <summary>
        /// Retrieves the name of the owning component. This may be overridden to
        /// provide a custom owner name. The default searches the owner's site for
        /// INestedSite and calls FullName, or ISite.Name if there is no nested site.
        /// If neither is available, this returns null.
        /// </summary>
        protected virtual string? OwnerName
        {
            get
            {
                string? ownerName = null;
                if (Owner != null && Owner.Site != null)
                {
                    if (Owner.Site is INestedSite nestedOwnerSite)
                    {
                        ownerName = nestedOwnerSite.FullName;
                    }
                    else
                    {
                        ownerName = Owner.Site.Name;
                    }
                }
 
                return ownerName;
            }
        }
 
        /// <summary>
        /// Creates a site for the component within the container.
        /// </summary>
        protected override ISite CreateSite(IComponent component, string? name)
        {
            ArgumentNullException.ThrowIfNull(component);
 
            return new Site(component, this, name);
        }
 
        /// <summary>
        /// Override of Container's dispose.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                Owner.Disposed -= new EventHandler(OnOwnerDisposed);
            }
            base.Dispose(disposing);
        }
 
        protected override object? GetService(Type service)
        {
            if (service == typeof(INestedContainer))
            {
                return this;
            }
            else
            {
                return base.GetService(service);
            }
        }
 
        /// <summary>
        /// Called when our owning component is destroyed.
        /// </summary>
        private void OnOwnerDisposed(object? sender, EventArgs e) => Dispose();
 
        /// <summary>
        /// Simple site implementation. We do some special processing to name the site, but
        /// that's about it.
        /// </summary>
        private sealed class Site : INestedSite
        {
            private string? _name;
 
            internal Site(IComponent component, NestedContainer container, string? name)
            {
                Component = component;
                Container = container;
                _name = name;
            }
 
            // The component sited by this component site.
            public IComponent Component { get; }
 
            // The container in which the component is sited.
            public IContainer Container { get; }
 
            public object? GetService(Type service)
            {
                return ((service == typeof(ISite)) ? this : ((NestedContainer)Container).GetService(service));
            }
 
            // Indicates whether the component is in design mode.
            public bool DesignMode
            {
                get
                {
                    IComponent owner = ((NestedContainer)Container).Owner;
                    if (owner != null && owner.Site != null)
                    {
                        return owner.Site.DesignMode;
                    }
                    return false;
                }
            }
 
            public string? FullName
            {
                get
                {
                    if (_name != null)
                    {
                        string? ownerName = ((NestedContainer)Container).OwnerName;
                        string childName = _name;
                        if (ownerName != null)
                        {
                            childName = ownerName + "." + childName;
                        }
 
                        return childName;
                    }
 
                    return _name;
                }
            }
 
            // The name of the component.
            public string? Name
            {
                get => _name;
                [RequiresUnreferencedCode("The Type of components in the container cannot be statically discovered to validate the name.")]
                set
                {
                    if (value == null || _name == null || !value.Equals(_name))
                    {
                        ((NestedContainer)Container).ValidateName(Component, value);
                        _name = value;
                    }
                }
            }
        }
    }
}