2 // Copyright (C) 2010 Novell Inc. http://novell.com
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 using System.Collections.Generic;
25 using System.ComponentModel;
27 using System.Reflection;
28 using System.Windows.Markup;
29 using System.Xaml.Schema;
33 // This type caches assembly attribute search results. To do this,
34 // it registers AssemblyLoaded event on CurrentDomain when it should
35 // reflect dynamic in-scope asemblies.
36 // It should be released at finalizer.
37 public class XamlSchemaContext
39 public XamlSchemaContext (IEnumerable<Assembly> referenceAssemblies)
40 : this (referenceAssemblies, null)
44 public XamlSchemaContext (XamlSchemaContextSettings settings)
45 : this (null, settings)
49 public XamlSchemaContext (IEnumerable<Assembly> referenceAssemblies, XamlSchemaContextSettings settings)
51 if (referenceAssemblies != null)
52 reference_assemblies = new List<Assembly> (referenceAssemblies);
54 AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoaded;
59 FullyQualifyAssemblyNamesInClrNamespaces = settings.FullyQualifyAssemblyNamesInClrNamespaces;
60 SupportMarkupExtensionsWithDuplicateArity = settings.SupportMarkupExtensionsWithDuplicateArity;
65 if (reference_assemblies == null)
66 AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoaded;
69 IList<Assembly> reference_assemblies;
71 // assembly attribute caches
72 List<string> xaml_nss;
73 Dictionary<string,string> prefixes;
74 Dictionary<string,string> compat_nss;
75 Dictionary<string,List<XamlType>> all_xaml_types;
76 XamlType [] empty_xaml_types = new XamlType [0];
78 public bool FullyQualifyAssemblyNamesInClrNamespaces { get; private set; }
80 public IList<Assembly> ReferenceAssemblies {
81 get { return reference_assemblies; }
84 IEnumerable<Assembly> AssembliesInScope {
85 get { return reference_assemblies ?? AppDomain.CurrentDomain.GetAssemblies (); }
88 public bool SupportMarkupExtensionsWithDuplicateArity { get; private set; }
90 public virtual IEnumerable<string> GetAllXamlNamespaces ()
92 if (xaml_nss == null) {
93 xaml_nss = new List<string> ();
94 foreach (var ass in AssembliesInScope)
95 FillXamlNamespaces (ass);
100 public virtual ICollection<XamlType> GetAllXamlTypes (string xamlNamespace)
102 if (xamlNamespace == null)
103 throw new ArgumentNullException ("xamlNamespace");
104 if (all_xaml_types == null) {
105 all_xaml_types = new Dictionary<string,List<XamlType>> ();
106 foreach (var ass in AssembliesInScope)
107 FillAllXamlTypes (ass);
111 if (all_xaml_types.TryGetValue (xamlNamespace, out l))
114 return empty_xaml_types;
117 public virtual string GetPreferredPrefix (string xmlns)
120 throw new ArgumentNullException ("xmlns");
121 if (prefixes == null) {
122 prefixes = new Dictionary<string,string> ();
123 foreach (var ass in AssembliesInScope)
127 return prefixes.TryGetValue (xmlns, out ret) ? ret : "p"; // default
130 protected internal XamlValueConverter<TConverterBase> GetValueConverter<TConverterBase> (Type converterType, XamlType targetType)
131 where TConverterBase : class
133 return new XamlValueConverter<TConverterBase> (converterType, targetType);
136 public virtual XamlDirective GetXamlDirective (string xamlNamespace, string name)
138 throw new NotImplementedException ();
141 Dictionary<Type,XamlType> xaml_types = new Dictionary<Type,XamlType> ();
143 public virtual XamlType GetXamlType (Type type)
146 if (!xaml_types.TryGetValue (type, out t)) {
147 t = new XamlType (type, this);
148 xaml_types.Add (type, t);
153 public XamlType GetXamlType (XamlTypeName xamlTypeName)
155 if (xamlTypeName == null)
156 throw new ArgumentNullException ("xamlTypeName");
158 var n = xamlTypeName;
160 if (TryGetCompatibleXamlNamespace (n.Namespace, out dummy))
161 n = new XamlTypeName (dummy, n.Name, n.TypeArguments);
164 if (n.Namespace == XamlLanguage.Xaml2006Namespace) {
165 // FIXME: I'm not really sure if these *special*
166 // names should be resolved here. There just
167 // does not seem to be any other appropriate
171 return XamlLanguage.Array;
173 return XamlLanguage.Member;
175 return XamlLanguage.Null;
177 return XamlLanguage.Property;
179 return XamlLanguage.Static;
181 return XamlLanguage.Type;
183 ret = XamlLanguage.AllTypes.FirstOrDefault (t => t.NameEquals (n));
187 return GetAllXamlTypes (n.Namespace).FirstOrDefault (t => t.NameEquals (n));
190 protected internal virtual XamlType GetXamlType (string xamlNamespace, string name, params XamlType [] typeArguments)
192 return GetXamlType (new XamlTypeName (xamlNamespace, name, typeArguments.ToTypeNames ()));
195 protected internal virtual Assembly OnAssemblyResolve (string assemblyName)
200 public virtual bool TryGetCompatibleXamlNamespace (string xamlNamespace, out string compatibleNamespace)
202 if (xamlNamespace == null)
203 throw new ArgumentNullException ("xamlNamespace");
204 if (compat_nss == null) {
205 compat_nss = new Dictionary<string,string> ();
206 foreach (var ass in AssembliesInScope)
207 FillCompatibilities (ass);
209 return compat_nss.TryGetValue (xamlNamespace, out compatibleNamespace);
212 void OnAssemblyLoaded (object o, AssemblyLoadEventArgs e)
214 if (reference_assemblies != null)
215 return; // do nothing
217 if (xaml_nss != null)
218 FillXamlNamespaces (e.LoadedAssembly);
219 if (prefixes != null)
220 FillPrefixes (e.LoadedAssembly);
221 if (compat_nss != null)
222 FillCompatibilities (e.LoadedAssembly);
223 if (all_xaml_types != null)
224 FillAllXamlTypes (e.LoadedAssembly);
227 // cache updater methods
228 void FillXamlNamespaces (Assembly ass)
230 foreach (XmlnsDefinitionAttribute xda in ass.GetCustomAttributes (typeof (XmlnsDefinitionAttribute), false))
231 xaml_nss.Add (xda.XmlNamespace);
234 void FillPrefixes (Assembly ass)
236 foreach (XmlnsPrefixAttribute xpa in ass.GetCustomAttributes (typeof (XmlnsPrefixAttribute), false))
237 prefixes.Add (xpa.XmlNamespace, xpa.Prefix);
240 void FillCompatibilities (Assembly ass)
242 foreach (XmlnsCompatibleWithAttribute xca in ass.GetCustomAttributes (typeof (XmlnsCompatibleWithAttribute), false))
243 compat_nss.Add (xca.OldNamespace, xca.NewNamespace);
246 void FillAllXamlTypes (Assembly ass)
248 foreach (XmlnsDefinitionAttribute xda in ass.GetCustomAttributes (typeof (XmlnsDefinitionAttribute), false)) {
249 var l = new List<XamlType> ();
250 all_xaml_types.Add (xda.XmlNamespace, l);
251 foreach (var t in ass.GetTypes ())
252 if (t.Namespace == xda.ClrNamespace)
253 l.Add (GetXamlType (t));