/
NestedContainer.cs
176 lines (155 loc) · 5.63 KB
/
NestedContainer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// 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;
}
}
}
}
}
}