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 ()
44 public XamlSchemaContext (IEnumerable<Assembly> referenceAssemblies)
45 : this (referenceAssemblies, null)
49 public XamlSchemaContext (XamlSchemaContextSettings settings)
50 : this (null, settings)
54 public XamlSchemaContext (IEnumerable<Assembly> referenceAssemblies, XamlSchemaContextSettings settings)
56 if (referenceAssemblies != null)
57 reference_assemblies = new List<Assembly> (referenceAssemblies);
59 AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoaded;
64 FullyQualifyAssemblyNamesInClrNamespaces = settings.FullyQualifyAssemblyNamesInClrNamespaces;
65 SupportMarkupExtensionsWithDuplicateArity = settings.SupportMarkupExtensionsWithDuplicateArity;
70 if (reference_assemblies == null)
71 AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoaded;
74 IList<Assembly> reference_assemblies;
76 // assembly attribute caches
77 List<string> xaml_nss;
78 Dictionary<string,string> prefixes;
79 Dictionary<string,string> compat_nss;
80 Dictionary<string,List<XamlType>> all_xaml_types;
81 XamlType [] empty_xaml_types = new XamlType [0];
83 public bool FullyQualifyAssemblyNamesInClrNamespaces { get; private set; }
85 public IList<Assembly> ReferenceAssemblies {
86 get { return reference_assemblies; }
89 IEnumerable<Assembly> AssembliesInScope {
90 get { return reference_assemblies ?? AppDomain.CurrentDomain.GetAssemblies (); }
93 public bool SupportMarkupExtensionsWithDuplicateArity { get; private set; }
95 public virtual IEnumerable<string> GetAllXamlNamespaces ()
97 if (xaml_nss == null) {
98 xaml_nss = new List<string> ();
99 foreach (var ass in AssembliesInScope)
100 FillXamlNamespaces (ass);
105 public virtual ICollection<XamlType> GetAllXamlTypes (string xamlNamespace)
107 if (xamlNamespace == null)
108 throw new ArgumentNullException ("xamlNamespace");
109 if (all_xaml_types == null) {
110 all_xaml_types = new Dictionary<string,List<XamlType>> ();
111 foreach (var ass in AssembliesInScope)
112 FillAllXamlTypes (ass);
116 if (all_xaml_types.TryGetValue (xamlNamespace, out l))
119 return empty_xaml_types;
122 public virtual string GetPreferredPrefix (string xmlns)
125 throw new ArgumentNullException ("xmlns");
126 if (prefixes == null) {
127 prefixes = new Dictionary<string,string> ();
128 foreach (var ass in AssembliesInScope)
132 return prefixes.TryGetValue (xmlns, out ret) ? ret : "p"; // default
135 protected internal XamlValueConverter<TConverterBase> GetValueConverter<TConverterBase> (Type converterType, XamlType targetType)
136 where TConverterBase : class
138 return new XamlValueConverter<TConverterBase> (converterType, targetType);
141 public virtual XamlDirective GetXamlDirective (string xamlNamespace, string name)
143 throw new NotImplementedException ();
146 Dictionary<Type,XamlType> xaml_types = new Dictionary<Type,XamlType> ();
148 public virtual XamlType GetXamlType (Type type)
151 if (!xaml_types.TryGetValue (type, out t)) {
152 t = new XamlType (type, this);
153 xaml_types.Add (type, t);
158 public XamlType GetXamlType (XamlTypeName xamlTypeName)
160 if (xamlTypeName == null)
161 throw new ArgumentNullException ("xamlTypeName");
163 var n = xamlTypeName;
165 if (TryGetCompatibleXamlNamespace (n.Namespace, out dummy))
166 n = new XamlTypeName (dummy, n.Name, n.TypeArguments);
169 if (n.Namespace == XamlLanguage.Xaml2006Namespace) {
170 // FIXME: I'm not really sure if these *special*
171 // names should be resolved here. There just
172 // does not seem to be any other appropriate
176 return XamlLanguage.Array;
178 return XamlLanguage.Member;
180 return XamlLanguage.Null;
182 return XamlLanguage.Property;
184 return XamlLanguage.Static;
186 return XamlLanguage.Type;
188 ret = XamlLanguage.AllTypes.FirstOrDefault (t => t.NameEquals (n));
192 return GetAllXamlTypes (n.Namespace).FirstOrDefault (t => t.NameEquals (n));
195 protected internal virtual XamlType GetXamlType (string xamlNamespace, string name, params XamlType [] typeArguments)
197 return GetXamlType (new XamlTypeName (xamlNamespace, name, typeArguments.ToTypeNames ()));
200 protected internal virtual Assembly OnAssemblyResolve (string assemblyName)
205 public virtual bool TryGetCompatibleXamlNamespace (string xamlNamespace, out string compatibleNamespace)
207 if (xamlNamespace == null)
208 throw new ArgumentNullException ("xamlNamespace");
209 if (compat_nss == null) {
210 compat_nss = new Dictionary<string,string> ();
211 foreach (var ass in AssembliesInScope)
212 FillCompatibilities (ass);
214 return compat_nss.TryGetValue (xamlNamespace, out compatibleNamespace);
217 void OnAssemblyLoaded (object o, AssemblyLoadEventArgs e)
219 if (reference_assemblies != null)
220 return; // do nothing
222 if (xaml_nss != null)
223 FillXamlNamespaces (e.LoadedAssembly);
224 if (prefixes != null)
225 FillPrefixes (e.LoadedAssembly);
226 if (compat_nss != null)
227 FillCompatibilities (e.LoadedAssembly);
228 if (all_xaml_types != null)
229 FillAllXamlTypes (e.LoadedAssembly);
232 // cache updater methods
233 void FillXamlNamespaces (Assembly ass)
235 foreach (XmlnsDefinitionAttribute xda in ass.GetCustomAttributes (typeof (XmlnsDefinitionAttribute), false))
236 xaml_nss.Add (xda.XmlNamespace);
239 void FillPrefixes (Assembly ass)
241 foreach (XmlnsPrefixAttribute xpa in ass.GetCustomAttributes (typeof (XmlnsPrefixAttribute), false))
242 prefixes.Add (xpa.XmlNamespace, xpa.Prefix);
245 void FillCompatibilities (Assembly ass)
247 foreach (XmlnsCompatibleWithAttribute xca in ass.GetCustomAttributes (typeof (XmlnsCompatibleWithAttribute), false))
248 compat_nss.Add (xca.OldNamespace, xca.NewNamespace);
251 void FillAllXamlTypes (Assembly ass)
253 foreach (XmlnsDefinitionAttribute xda in ass.GetCustomAttributes (typeof (XmlnsDefinitionAttribute), false)) {
254 var l = new List<XamlType> ();
255 all_xaml_types.Add (xda.XmlNamespace, l);
256 foreach (var t in ass.GetTypes ())
257 if (t.Namespace == xda.ClrNamespace)
258 l.Add (GetXamlType (t));