Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / ExportProvider.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.ComponentModel.Composition.Primitives;\r
7 using System.Globalization;\r
8 using System.Linq;\r
9 using Microsoft.Internal;\r
10 \r
11 namespace System.ComponentModel.Composition.Hosting\r
12 {\r
13     /// <summary>\r
14     ///     Defines the <see langword="abstract"/> base class for export providers, which provide\r
15     ///     methods for retrieving <see cref="Export"/> objects.\r
16     /// </summary>\r
17     public abstract partial class ExportProvider\r
18     {\r
19         /// <summary>\r
20         ///     Initializes a new instance of the <see cref="ExportProvider"/> class.\r
21         /// </summary>\r
22         protected ExportProvider()\r
23         {\r
24         }\r
25 \r
26         /// <summary>\r
27         ///     Occurs when the exports in the <see cref="ExportProvider"/> have changed.\r
28         /// </summary>\r
29         public event EventHandler<ExportsChangeEventArgs> ExportsChanged;\r
30 \r
31         /// <summary>\r
32         ///     Occurs when the exports in the <see cref="ExportProvider"/> are changing.\r
33         /// </summary>\r
34         public event EventHandler<ExportsChangeEventArgs> ExportsChanging;\r
35 \r
36         /// <summary>\r
37         ///     Returns all exports that match the conditions of the specified import.\r
38         /// </summary>\r
39         /// <param name="definition">\r
40         ///     The <see cref="ImportDefinition"/> that defines the conditions of the \r
41         ///     <see cref="Export"/> objects to get.\r
42         /// </param>\r
43         /// <result>\r
44         ///     An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match \r
45         ///     the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an \r
46         ///     empty <see cref="IEnumerable{T}"/>.\r
47         /// </result>\r
48         /// <exception cref="ArgumentNullException">\r
49         ///     <paramref name="definition"/> is <see langword="null"/>.\r
50         /// </exception>\r
51         /// <exception cref="ImportCardinalityMismatchException">\r
52         ///     <para>\r
53         ///         <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and \r
54         ///         there are zero <see cref="Export"/> objects that match the conditions of the specified \r
55         ///         <see cref="ImportDefinition"/>.\r
56         ///     </para>\r
57         ///     -or-\r
58         ///     <para>\r
59         ///         <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or \r
60         ///         <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/> \r
61         ///         objects that match the conditions of the specified <see cref="ImportDefinition"/>.\r
62         ///     </para>\r
63         /// </exception>\r
64         public IEnumerable<Export> GetExports(ImportDefinition definition)\r
65         {\r
66             return GetExports(definition, null);\r
67         }\r
68 \r
69         /// <summary>\r
70         ///     Returns all exports that match the conditions of the specified import.\r
71         /// </summary>\r
72         /// <param name="definition">\r
73         ///     The <see cref="ImportDefinition"/> that defines the conditions of the \r
74         ///     <see cref="Export"/> objects to get.\r
75         /// </param>\r
76         /// <result>\r
77         ///     An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match \r
78         ///     the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an \r
79         ///     empty <see cref="IEnumerable{T}"/>.\r
80         /// </result>\r
81         /// <exception cref="ArgumentNullException">\r
82         ///     <paramref name="definition"/> is <see langword="null"/>.\r
83         /// </exception>\r
84         /// <exception cref="ImportCardinalityMismatchException">\r
85         ///     <para>\r
86         ///         <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and \r
87         ///         there are zero <see cref="Export"/> objects that match the conditions of the specified \r
88         ///         <see cref="ImportDefinition"/>.\r
89         ///     </para>\r
90         ///     -or-\r
91         ///     <para>\r
92         ///         <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or \r
93         ///         <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/> \r
94         ///         objects that match the conditions of the specified <see cref="ImportDefinition"/>.\r
95         ///     </para>\r
96         /// </exception>\r
97         public IEnumerable<Export> GetExports(ImportDefinition definition, AtomicComposition atomicComposition)\r
98         {\r
99             Requires.NotNull(definition, "definition");\r
100 \r
101             IEnumerable<Export> exports;\r
102             ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports);\r
103             switch(result)\r
104             {\r
105                 case ExportCardinalityCheckResult.Match:\r
106                     return exports;\r
107                 case ExportCardinalityCheckResult.NoExports:\r
108                     throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_NoExports, definition.Constraint.Body.ToString()));\r
109                 default:\r
110                     Assumes.IsTrue(result == ExportCardinalityCheckResult.TooManyExports);\r
111                     throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_TooManyExports, definition.Constraint.Body.ToString()));\r
112             }\r
113         }\r
114 \r
115         /// <summary>\r
116         ///     Returns all exports that match the conditions of the specified import.\r
117         /// </summary>\r
118         /// <param name="definition">\r
119         ///     The <see cref="ImportDefinition"/> that defines the conditions of the \r
120         ///     <see cref="Export"/> objects to get.\r
121         /// </param>\r
122         /// <param name="exports">\r
123         ///     When this method returns, contains an <see cref="IEnumerable{T}"/> of <see cref="Export"/> \r
124         ///     objects that match the conditions defined by <see cref="ImportDefinition"/>, if found; \r
125         ///     otherwise, an empty <see cref="IEnumerable{T}"/>.\r
126         /// </param>\r
127         /// <returns>\r
128         ///     <see langword="true"/> if <see cref="ImportDefinition.Cardinality"/> is \r
129         ///     <see cref="ImportCardinality.ZeroOrOne"/> or <see cref="ImportCardinality.ZeroOrMore"/> and \r
130         ///     there are zero <see cref="Export"/> objects that match the conditions of the specified \r
131         ///     <see cref="ImportDefinition"/>. <see langword="true"/> if \r
132         ///     <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or \r
133         ///     <see cref="ImportCardinality.ExactlyOne"/> and there is exactly one <see cref="Export"/> \r
134         ///     that matches the conditions of the specified <see cref="ImportDefinition"/>; otherwise, \r
135         ///     <see langword="false"/>.\r
136         /// </returns>\r
137         /// <exception cref="ArgumentNullException">\r
138         ///     <paramref name="definition"/> is <see langword="null"/>.\r
139         /// </exception>\r
140         public bool TryGetExports(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports)\r
141         {\r
142             Requires.NotNull(definition, "definition");\r
143 \r
144             exports = null;\r
145             ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports);\r
146             return (result == ExportCardinalityCheckResult.Match);\r
147         }\r
148     \r
149         /// <summary>\r
150         ///     Returns all exports that match the constraint defined by the specified definition.\r
151         /// </summary>\r
152         /// <param name="definition">\r
153         ///     The <see cref="ImportDefinition"/> that defines the conditions of the \r
154         ///     <see cref="Export"/> objects to return.\r
155         /// </param>\r
156         /// <result>\r
157         ///     An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match \r
158         ///     the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an \r
159         ///     empty <see cref="IEnumerable{T}"/>.\r
160         /// </result>\r
161         /// <remarks>\r
162         ///     <note type="inheritinfo">\r
163         ///         Overriders of this method should not treat cardinality-related mismatches \r
164         ///         as errors, and should not throw exceptions in those cases. For instance,\r
165         ///         if <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> \r
166         ///         and there are zero <see cref="Export"/> objects that match the conditions of the \r
167         ///         specified <see cref="ImportDefinition"/>, an <see cref="IEnumerable{T}"/> should be returned.\r
168         ///     </note>\r
169         /// </remarks>\r
170         protected abstract IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition);\r
171 \r
172         /// <summary>\r
173         ///     Raises the <see cref="ExportsChanged"/> event.\r
174         /// </summary>\r
175         /// <param name="e">\r
176         ///     An <see cref="ExportsChangeEventArgs"/> containing the data for the event.\r
177         /// </param>\r
178         protected virtual void OnExportsChanged(ExportsChangeEventArgs e)\r
179         {\r
180             EventHandler<ExportsChangeEventArgs> changedEvent = this.ExportsChanged;\r
181             if (changedEvent != null)\r
182             {\r
183                 CompositionResult result = CompositionServices.TryFire(changedEvent, this, e);\r
184                 result.ThrowOnErrors(e.AtomicComposition);\r
185             }\r
186         }\r
187 \r
188         /// <summary>\r
189         ///     Raises the <see cref="ExportsChanging"/> event.\r
190         /// </summary>\r
191         /// <param name="e">\r
192         ///     An <see cref="ExportsChangeEventArgs"/> containing the data for the event.\r
193         /// </param>\r
194         protected virtual void OnExportsChanging(ExportsChangeEventArgs e)\r
195         {\r
196             EventHandler<ExportsChangeEventArgs> changingEvent = this.ExportsChanging;\r
197             if (changingEvent != null)\r
198             {\r
199                 CompositionResult result = CompositionServices.TryFire(changingEvent, this, e);\r
200                 result.ThrowOnErrors(e.AtomicComposition);\r
201             }\r
202         }\r
203 \r
204         private ExportCardinalityCheckResult TryGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports)\r
205         {\r
206             Assumes.NotNull(definition);\r
207 \r
208             exports = this.GetExportsCore(definition, atomicComposition);\r
209 \r
210             if (exports == null)\r
211             {\r
212                 exports = Enumerable.Empty<Export>();\r
213             }\r
214 \r
215             var checkResult = ExportServices.CheckCardinality(definition, exports);\r
216 \r
217             // Export providers treat >1 match as zero for cardinality 0-1 imports\r
218             // If this policy is moved we need to revisit the assumption that the\r
219             // ImportEngine made during previewing the only required imports to \r
220             // now also preview optional imports.\r
221             if (checkResult == ExportCardinalityCheckResult.TooManyExports &&\r
222                 definition.Cardinality == ImportCardinality.ZeroOrOne)\r
223             {\r
224                 checkResult = ExportCardinalityCheckResult.Match;\r
225                 exports = Enumerable.Empty<Export>();\r
226             }\r
227 \r
228             return checkResult;\r
229         }\r
230     }\r
231 }\r