/
ReferenceConverter.cs
209 lines (183 loc) · 7.47 KB
/
ReferenceConverter.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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Globalization;
using System.Runtime.InteropServices;
namespace System.ComponentModel
{
/// <summary>
/// Provides a type converter to convert object references to and from various
/// other representations.
/// </summary>
public class ReferenceConverter : TypeConverter
{
private static readonly string s_none = SR.UsingResourceKeys() ? "(none)" : SR.toStringNone;
private readonly Type _type;
/// <summary>
/// Initializes a new instance of the <see cref='System.ComponentModel.ReferenceConverter'/> class.
/// </summary>
public ReferenceConverter(Type type)
{
_type = type;
}
/// <summary>
/// Gets a value indicating whether this converter can convert an object in the
/// given source type to a reference object using the specified context.
/// </summary>
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
if (sourceType == typeof(string) && context != null)
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// Converts the given object to the reference type.
/// </summary>
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
if (value is string text)
{
text = text.Trim();
if (!string.Equals(text, s_none) && context != null)
{
// Try the reference service first.
if (context.GetService(typeof(IReferenceService)) is IReferenceService refSvc)
{
object? obj = refSvc.GetReference(text);
if (obj != null)
{
return obj;
}
}
// Now try IContainer
IContainer? cont = context.Container;
if (cont != null)
{
object? obj = cont.Components[text];
if (obj != null)
{
return obj;
}
}
}
return null;
}
return base.ConvertFrom(context, culture, value);
}
/// <summary>
/// Converts the given value object to the reference type using the specified context and arguments.
/// </summary>
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
{
if (destinationType == typeof(string))
{
if (value != null)
{
// Try the reference service first.
if (context?.GetService(typeof(IReferenceService)) is IReferenceService refSvc)
{
string? name = refSvc.GetName(value);
if (name != null)
{
return name;
}
}
// Now see if this is an IComponent.
if (!Marshal.IsComObject(value) && value is IComponent comp)
{
ISite? site = comp.Site;
string? name = site?.Name;
if (name != null)
{
return name;
}
}
// Couldn't find it.
return string.Empty;
}
return s_none;
}
return base.ConvertTo(context, culture, value, destinationType);
}
/// <summary>
/// Gets a collection of standard values for the reference data type.
/// </summary>
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context)
{
List<object?>? components = null;
if (context != null)
{
components = new List<object?> { null };
// Try the reference service first.
if (context.GetService(typeof(IReferenceService)) is IReferenceService refSvc)
{
object[] objs = refSvc.GetReferences(_type);
if (objs != null)
{
for (int i = 0; i < objs.Length; i++)
{
if (IsValueAllowed(context, objs[i]))
{
components.Add(objs[i]);
}
}
}
}
else
{
// Now try IContainer.
IContainer? cont = context.Container;
if (cont != null)
{
ComponentCollection objs = cont.Components;
foreach (IComponent obj in objs)
{
if (obj != null && _type != null && _type.IsInstanceOfType(obj) && IsValueAllowed(context, obj))
{
components.Add(obj);
}
}
}
}
components.Sort(new ReferenceComparer(this));
}
return new StandardValuesCollection(components);
}
/// <summary>
/// Gets a value indicating whether the list of standard values returned from
/// <see cref='System.ComponentModel.ReferenceConverter.GetStandardValues'/> is an exclusive list.
/// </summary>
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => true;
/// <summary>
/// Gets a value indicating whether this object supports a standard set of values
/// that can be picked from a list.
/// </summary>
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true;
/// <summary>
/// Gets a value indicating whether a particular value can be added to
/// the standard values collection.
/// </summary>
protected virtual bool IsValueAllowed(ITypeDescriptorContext context, object value) => true;
/// <summary>
/// IComparer object used for sorting references
/// </summary>
private readonly struct ReferenceComparer : IComparer<object>
{
private readonly ReferenceConverter _converter;
public ReferenceComparer(ReferenceConverter converter)
{
_converter = converter;
}
public int Compare(object? item1, object? item2)
{
string? itemName1 = _converter.ConvertToString(item1);
string? itemName2 = _converter.ConvertToString(item2);
return string.Compare(itemName1, itemName2, StringComparison.InvariantCulture);
}
}
}
}