Actually we have almost what we need on mobile profiles.
[mono-project.git] / mcs / class / System.Xaml / System.Xaml / XamlType.cs
blobac31f2cddc9481d78be9e5773fcf85883124830d
1 //
2 // Copyright (C) 2010 Novell Inc. http://novell.com
3 //
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:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
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.
23 using System;
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.Linq;
28 using System.Reflection;
29 using System.Windows.Markup;
30 using System.Xaml.Schema;
31 using System.Xml.Serialization;
33 namespace System.Xaml
35 public class XamlType : IEquatable<XamlType>
37 public XamlType (Type underlyingType, XamlSchemaContext schemaContext)
38 : this (underlyingType, schemaContext, null)
42 // static readonly Type [] predefined_types = {
43 // typeof (XData), typeof (Uri), typeof (TimeSpan), typeof (PropertyDefinition), typeof (MemberDefinition), typeof (Reference)
44 // };
46 public XamlType (Type underlyingType, XamlSchemaContext schemaContext, XamlTypeInvoker invoker)
47 : this (schemaContext, invoker)
49 if (underlyingType == null)
50 throw new ArgumentNullException ("underlyingType");
51 type = underlyingType;
52 underlying_type = type;
54 XamlType xt;
55 if (XamlLanguage.InitializingTypes) {
56 // These are special. Only XamlLanguage members are with shorthand name.
57 if (type == typeof (PropertyDefinition))
58 Name = "Property";
59 else if (type == typeof (MemberDefinition))
60 Name = "Member";
61 else
62 Name = GetXamlName (type);
63 PreferredXamlNamespace = XamlLanguage.Xaml2006Namespace;
64 } else if ((xt = XamlLanguage.AllTypes.FirstOrDefault (t => t.UnderlyingType == type)) != null) {
65 Name = xt.Name;
66 PreferredXamlNamespace = XamlLanguage.Xaml2006Namespace;
67 } else {
68 Name = GetXamlName (type);
69 PreferredXamlNamespace = String.Format ("clr-namespace:{0};assembly={1}", type.Namespace, type.Assembly.GetName ().Name);
71 if (type.IsGenericType) {
72 TypeArguments = new List<XamlType> ();
73 foreach (var gta in type.GetGenericArguments ())
74 TypeArguments.Add (schemaContext.GetXamlType (gta));
78 public XamlType (string unknownTypeNamespace, string unknownTypeName, IList<XamlType> typeArguments, XamlSchemaContext schemaContext)
79 : this (schemaContext, null)
81 if (unknownTypeNamespace == null)
82 throw new ArgumentNullException ("unknownTypeNamespace");
83 if (unknownTypeName == null)
84 throw new ArgumentNullException ("unknownTypeName");
85 if (schemaContext == null)
86 throw new ArgumentNullException ("schemaContext");
88 type = typeof (object);
89 Name = unknownTypeName;
90 PreferredXamlNamespace = unknownTypeNamespace;
91 TypeArguments = typeArguments != null && typeArguments.Count == 0 ? null : typeArguments;
92 explicit_ns = unknownTypeNamespace;
95 protected XamlType (string typeName, IList<XamlType> typeArguments, XamlSchemaContext schemaContext)
96 : this (String.Empty, typeName, typeArguments, schemaContext)
100 XamlType (XamlSchemaContext schemaContext, XamlTypeInvoker invoker)
102 if (schemaContext == null)
103 throw new ArgumentNullException ("schemaContext");
104 SchemaContext = schemaContext;
105 this.invoker = invoker ?? new XamlTypeInvoker (this);
108 Type type, underlying_type;
110 string explicit_ns;
112 // populated properties
113 XamlType base_type;
114 XamlTypeInvoker invoker;
116 internal EventHandler<XamlSetMarkupExtensionEventArgs> SetMarkupExtensionHandler {
117 get { return LookupSetMarkupExtensionHandler (); }
120 internal EventHandler<XamlSetTypeConverterEventArgs> SetTypeConverterHandler {
121 get { return LookupSetTypeConverterHandler (); }
124 public IList<XamlType> AllowedContentTypes {
125 get { return LookupAllowedContentTypes (); }
128 public XamlType BaseType {
129 get { return LookupBaseType (); }
132 public bool ConstructionRequiresArguments {
133 get { return LookupConstructionRequiresArguments (); }
136 public XamlMember ContentProperty {
137 get { return LookupContentProperty (); }
140 public IList<XamlType> ContentWrappers {
141 get { return LookupContentWrappers (); }
144 public XamlValueConverter<XamlDeferringLoader> DeferringLoader {
145 get { return LookupDeferringLoader (); }
148 public XamlTypeInvoker Invoker {
149 get { return LookupInvoker (); }
152 public bool IsAmbient {
153 get { return LookupIsAmbient (); }
156 public bool IsArray {
157 get { return LookupCollectionKind () == XamlCollectionKind.Array; }
160 // it somehow treats array as not a collection...
161 public bool IsCollection {
162 get { return LookupCollectionKind () == XamlCollectionKind.Collection; }
165 public bool IsConstructible {
166 get { return LookupIsConstructible (); }
169 public bool IsDictionary {
170 get { return LookupCollectionKind () == XamlCollectionKind.Dictionary; }
173 public bool IsGeneric {
174 get { return type.IsGenericType; }
177 public bool IsMarkupExtension {
178 get { return LookupIsMarkupExtension (); }
180 public bool IsNameScope {
181 get { return LookupIsNameScope (); }
183 public bool IsNameValid {
184 get { return XamlLanguage.IsValidXamlName (Name); }
187 public bool IsNullable {
188 get { return LookupIsNullable (); }
191 public bool IsPublic {
192 get { return LookupIsPublic (); }
195 public bool IsUnknown {
196 get { return LookupIsUnknown (); }
199 public bool IsUsableDuringInitialization {
200 get { return LookupUsableDuringInitialization (); }
203 public bool IsWhitespaceSignificantCollection {
204 get { return LookupIsWhitespaceSignificantCollection (); }
207 public bool IsXData {
208 get { return LookupIsXData (); }
211 public XamlType ItemType {
212 get { return LookupItemType (); }
215 public XamlType KeyType {
216 get { return LookupKeyType (); }
219 public XamlType MarkupExtensionReturnType {
220 get { return LookupMarkupExtensionReturnType (); }
223 public string Name { get; private set; }
225 public string PreferredXamlNamespace { get; private set; }
227 public XamlSchemaContext SchemaContext { get; private set; }
229 public bool TrimSurroundingWhitespace {
230 get { return LookupTrimSurroundingWhitespace (); }
233 public IList<XamlType> TypeArguments { get; private set; }
235 public XamlValueConverter<TypeConverter> TypeConverter {
236 get { return LookupTypeConverter (); }
239 public Type UnderlyingType {
240 get { return LookupUnderlyingType (); }
243 public XamlValueConverter<ValueSerializer> ValueSerializer {
244 get { return LookupValueSerializer (); }
247 internal string GetInternalXmlName ()
249 if (IsMarkupExtension && Name.EndsWith ("Extension", StringComparison.Ordinal))
250 return Name.Substring (0, Name.Length - 9);
251 var stn = XamlLanguage.SpecialNames.FirstOrDefault (s => s.Type == this);
252 return stn != null ? stn.Name : Name;
255 public static bool operator == (XamlType left, XamlType right)
257 return IsNull (left) ? IsNull (right) : left.Equals (right);
260 static bool IsNull (XamlType a)
262 return Object.ReferenceEquals (a, null);
265 public static bool operator != (XamlType left, XamlType right)
267 return !(left == right);
270 public bool Equals (XamlType other)
272 // It does not compare XamlSchemaContext.
273 return !IsNull (other) &&
274 UnderlyingType == other.UnderlyingType &&
275 Name == other.Name &&
276 PreferredXamlNamespace == other.PreferredXamlNamespace && TypeArguments.ListEquals (other.TypeArguments);
279 public override bool Equals (object obj)
281 var a = obj as XamlType;
282 return Equals (a);
285 public override int GetHashCode ()
287 if (UnderlyingType != null)
288 return UnderlyingType.GetHashCode ();
289 int x = Name.GetHashCode () << 7 + PreferredXamlNamespace.GetHashCode ();
290 if (TypeArguments != null)
291 foreach (var t in TypeArguments)
292 x = t.GetHashCode () + x << 5;
293 return x;
296 public override string ToString ()
298 return new XamlTypeName (this).ToString ();
299 //return String.IsNullOrEmpty (PreferredXamlNamespace) ? Name : String.Concat ("{", PreferredXamlNamespace, "}", Name);
302 public virtual bool CanAssignTo (XamlType xamlType)
304 if (this.UnderlyingType == null)
305 return xamlType == XamlLanguage.Object;
306 var ut = xamlType.UnderlyingType ?? typeof (object);
307 return ut.IsAssignableFrom (UnderlyingType);
310 public XamlMember GetAliasedProperty (XamlDirective directive)
312 return LookupAliasedProperty (directive);
315 public ICollection<XamlMember> GetAllAttachableMembers ()
317 return new List<XamlMember> (LookupAllAttachableMembers ());
320 public ICollection<XamlMember> GetAllMembers ()
322 return new List<XamlMember> (LookupAllMembers ());
325 public XamlMember GetAttachableMember (string name)
327 return LookupAttachableMember (name);
330 public XamlMember GetMember (string name)
332 return LookupMember (name, true);
335 public IList<XamlType> GetPositionalParameters (int parameterCount)
337 return LookupPositionalParameters (parameterCount);
340 public virtual IList<string> GetXamlNamespaces ()
342 throw new NotImplementedException ();
343 /* this does not work like documented!
344 if (explicit_ns != null)
345 return new string [] {explicit_ns};
346 var l = SchemaContext.GetAllXamlNamespaces ();
347 if (l != null)
348 return new List<string> (l);
349 return new string [] {String.Empty};
353 // lookups
355 protected virtual XamlMember LookupAliasedProperty (XamlDirective directive)
357 if (directive == XamlLanguage.Key) {
358 var a = this.GetCustomAttribute<DictionaryKeyPropertyAttribute> ();
359 return a != null ? GetMember (a.Name) : null;
361 if (directive == XamlLanguage.Name) {
362 var a = this.GetCustomAttribute<RuntimeNamePropertyAttribute> ();
363 return a != null ? GetMember (a.Name) : null;
365 if (directive == XamlLanguage.Uid) {
366 var a = this.GetCustomAttribute<UidPropertyAttribute> ();
367 return a != null ? GetMember (a.Name) : null;
369 if (directive == XamlLanguage.Lang) {
370 var a = this.GetCustomAttribute<XmlLangPropertyAttribute> ();
371 return a != null ? GetMember (a.Name) : null;
373 return null;
376 protected virtual IEnumerable<XamlMember> LookupAllAttachableMembers ()
378 if (UnderlyingType == null)
379 return BaseType != null ? BaseType.GetAllAttachableMembers () : empty_array;
380 if (all_attachable_members_cache == null) {
381 all_attachable_members_cache = new List<XamlMember> (DoLookupAllAttachableMembers ());
382 all_attachable_members_cache.Sort (TypeExtensionMethods.CompareMembers);
384 return all_attachable_members_cache;
387 IEnumerable<XamlMember> DoLookupAllAttachableMembers ()
389 // based on http://msdn.microsoft.com/en-us/library/ff184560.aspx
390 var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
392 var gl = new Dictionary<string,MethodInfo> ();
393 var sl = new Dictionary<string,MethodInfo> ();
394 var al = new Dictionary<string,MethodInfo> ();
395 //var rl = new Dictionary<string,MethodInfo> ();
396 var nl = new List<string> ();
397 foreach (var mi in UnderlyingType.GetMethods (bf)) {
398 string name = null;
399 if (mi.Name.StartsWith ("Get", StringComparison.Ordinal)) {
400 if (mi.ReturnType == typeof (void))
401 continue;
402 var args = mi.GetParameters ();
403 if (args.Length != 1)
404 continue;
405 name = mi.Name.Substring (3);
406 gl.Add (name, mi);
407 } else if (mi.Name.StartsWith ("Set", StringComparison.Ordinal)) {
408 // looks like the return type is *ignored*
409 //if (mi.ReturnType != typeof (void))
410 // continue;
411 var args = mi.GetParameters ();
412 if (args.Length != 2)
413 continue;
414 name = mi.Name.Substring (3);
415 sl.Add (name, mi);
416 } else if (mi.Name.EndsWith ("Handler", StringComparison.Ordinal)) {
417 var args = mi.GetParameters ();
418 if (args.Length != 2)
419 continue;
420 if (mi.Name.StartsWith ("Add", StringComparison.Ordinal)) {
421 name = mi.Name.Substring (3, mi.Name.Length - 3 - 7);
422 al.Add (name, mi);
423 }/* else if (mi.Name.StartsWith ("Remove", StringComparison.Ordinal)) {
424 name = mi.Name.Substring (6, mi.Name.Length - 6 - 7);
425 rl.Add (name, mi);
428 if (name != null && !nl.Contains (name))
429 nl.Add (name);
432 foreach (var name in nl) {
433 MethodInfo m;
434 var g = gl.TryGetValue (name, out m) ? m : null;
435 var s = sl.TryGetValue (name, out m) ? m : null;
436 if (g != null || s != null)
437 yield return new XamlMember (name, g, s, SchemaContext);
438 var a = al.TryGetValue (name, out m) ? m : null;
439 //var r = rl.TryGetValue (name, out m) ? m : null;
440 if (a != null)
441 yield return new XamlMember (name, a, SchemaContext);
445 static readonly XamlMember [] empty_array = new XamlMember [0];
447 protected virtual IEnumerable<XamlMember> LookupAllMembers ()
449 if (UnderlyingType == null)
450 return BaseType != null ? BaseType.GetAllMembers () : empty_array;
451 if (all_members_cache == null) {
452 all_members_cache = new List<XamlMember> (DoLookupAllMembers ());
453 all_members_cache.Sort (TypeExtensionMethods.CompareMembers);
455 return all_members_cache;
458 List<XamlMember> all_members_cache;
459 List<XamlMember> all_attachable_members_cache;
461 IEnumerable<XamlMember> DoLookupAllMembers ()
463 // This is a hack that is likely required due to internal implementation difference in System.Uri. Our Uri has two readonly collection properties
464 if (this == XamlLanguage.Uri)
465 yield break;
467 var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
469 foreach (var pi in UnderlyingType.GetProperties (bf))
470 if (pi.CanRead && (pi.CanWrite || IsCollectionType (pi.PropertyType) || typeof (IXmlSerializable).IsAssignableFrom (pi.PropertyType)) && pi.GetIndexParameters ().Length == 0)
471 yield return new XamlMember (pi, SchemaContext);
472 foreach (var ei in UnderlyingType.GetEvents (bf))
473 yield return new XamlMember (ei, SchemaContext);
476 static bool IsPublicAccessor (MethodInfo mi)
478 return mi != null && mi.IsPublic;
481 bool IsCollectionType (Type type)
483 if (type == null)
484 return false;
485 var xt = SchemaContext.GetXamlType (type);
486 return xt.LookupCollectionKind () != XamlCollectionKind.None;
489 protected virtual IList<XamlType> LookupAllowedContentTypes ()
491 // the actual implementation is very different from what is documented :(
492 return null;
495 var l = new List<XamlType> ();
496 if (ContentWrappers != null)
497 l.AddRange (ContentWrappers);
498 if (ContentProperty != null)
499 l.Add (ContentProperty.Type);
500 if (ItemType != null)
501 l.Add (ItemType);
502 return l.Count > 0 ? l : null;
506 protected virtual XamlMember LookupAttachableMember (string name)
508 return GetAllAttachableMembers ().FirstOrDefault (m => m.Name == name);
511 [MonoTODO]
512 protected virtual XamlType LookupBaseType ()
514 if (base_type == null) {
515 if (UnderlyingType == null)
516 // FIXME: probably something advanced is needed here.
517 base_type = new XamlType (typeof (object), SchemaContext, Invoker);
518 else
519 base_type = type.BaseType == null || type.BaseType == typeof (object) ? null : new XamlType (type.BaseType, SchemaContext, Invoker);
521 return base_type;
524 // This implementation is not verified. (No place to use.)
525 protected virtual XamlCollectionKind LookupCollectionKind ()
527 if (UnderlyingType == null)
528 return BaseType != null ? BaseType.LookupCollectionKind () : XamlCollectionKind.None;
529 if (type.IsArray)
530 return XamlCollectionKind.Array;
532 if (type.ImplementsAnyInterfacesOf (typeof (IDictionary), typeof (IDictionary<,>)))
533 return XamlCollectionKind.Dictionary;
535 if (type.ImplementsAnyInterfacesOf (typeof (IList), typeof (ICollection<>)))
536 return XamlCollectionKind.Collection;
538 return XamlCollectionKind.None;
541 protected virtual bool LookupConstructionRequiresArguments ()
543 if (UnderlyingType == null)
544 return false;
546 // not sure if it is required, but MemberDefinition return true while they are abstract and it makes no sense.
547 if (UnderlyingType.IsAbstract)
548 return true;
550 // FIXME: probably some primitive types are treated as special.
551 switch (Type.GetTypeCode (UnderlyingType)) {
552 case TypeCode.String:
553 return true;
554 case TypeCode.Object:
555 if (UnderlyingType == typeof (TimeSpan))
556 return false;
557 break;
558 default:
559 return false;
562 return UnderlyingType.GetConstructor (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) == null;
565 protected virtual XamlMember LookupContentProperty ()
567 var a = this.GetCustomAttribute<ContentPropertyAttribute> ();
568 return a != null && a.Name != null ? GetMember (a.Name) : null;
571 protected virtual IList<XamlType> LookupContentWrappers ()
573 if (GetCustomAttributeProvider () == null)
574 return null;
576 var arr = GetCustomAttributeProvider ().GetCustomAttributes (typeof (ContentWrapperAttribute), false);
577 if (arr == null || arr.Length == 0)
578 return null;
579 var l = new XamlType [arr.Length];
580 for (int i = 0; i < l.Length; i++)
581 l [i] = SchemaContext.GetXamlType (((ContentWrapperAttribute) arr [i]).ContentWrapper);
582 return l;
585 internal ICustomAttributeProvider GetCustomAttributeProvider ()
587 return LookupCustomAttributeProvider ();
590 protected internal virtual ICustomAttributeProvider LookupCustomAttributeProvider ()
592 return UnderlyingType;
595 protected virtual XamlValueConverter<XamlDeferringLoader> LookupDeferringLoader ()
597 throw new NotImplementedException ();
600 protected virtual XamlTypeInvoker LookupInvoker ()
602 return invoker;
605 protected virtual bool LookupIsAmbient ()
607 return this.GetCustomAttribute<AmbientAttribute> () != null;
610 // It is documented as if it were to reflect spec. section 5.2,
611 // but the actual behavior shows it is *totally* wrong.
612 // Here I have implemented this based on the nunit test results. sigh.
613 protected virtual bool LookupIsConstructible ()
615 if (UnderlyingType == null)
616 return true;
617 if (IsMarkupExtension)
618 return true;
619 if (UnderlyingType.IsAbstract)
620 return false;
621 if (!IsNameValid)
622 return false;
623 return true;
626 protected virtual bool LookupIsMarkupExtension ()
628 return typeof (MarkupExtension).IsAssignableFrom (UnderlyingType);
631 protected virtual bool LookupIsNameScope ()
633 return typeof (INameScope).IsAssignableFrom (UnderlyingType);
636 protected virtual bool LookupIsNullable ()
638 return !type.IsValueType || type.ImplementsInterface (typeof (Nullable<>));
641 protected virtual bool LookupIsPublic ()
643 return underlying_type == null || underlying_type.IsPublic || underlying_type.IsNestedPublic;
646 protected virtual bool LookupIsUnknown ()
648 return UnderlyingType == null;
651 protected virtual bool LookupIsWhitespaceSignificantCollection ()
653 // probably for unknown types, it should preserve whitespaces.
654 return IsUnknown || this.GetCustomAttribute<WhitespaceSignificantCollectionAttribute> () != null;
657 protected virtual bool LookupIsXData ()
659 return CanAssignTo (SchemaContext.GetXamlType (typeof (IXmlSerializable)));
662 protected virtual XamlType LookupItemType ()
664 if (IsArray)
665 return new XamlType (type.GetElementType (), SchemaContext);
666 if (IsDictionary) {
667 if (!IsGeneric)
668 return new XamlType (typeof (object), SchemaContext);
669 return new XamlType (type.GetGenericArguments () [1], SchemaContext);
671 if (!IsCollection)
672 return null;
673 if (!IsGeneric)
674 return new XamlType (typeof (object), SchemaContext);
675 return new XamlType (type.GetGenericArguments () [0], SchemaContext);
678 protected virtual XamlType LookupKeyType ()
680 if (!IsDictionary)
681 return null;
682 if (!IsGeneric)
683 return new XamlType (typeof (object), SchemaContext);
684 return new XamlType (type.GetGenericArguments () [0], SchemaContext);
687 protected virtual XamlType LookupMarkupExtensionReturnType ()
689 var a = this.GetCustomAttribute<MarkupExtensionReturnTypeAttribute> ();
690 return a != null ? new XamlType (a.ReturnType, SchemaContext) : null;
693 protected virtual XamlMember LookupMember (string name, bool skipReadOnlyCheck)
695 // FIXME: verify if this does not filter out events.
696 return GetAllMembers ().FirstOrDefault (m => m.Name == name && (skipReadOnlyCheck || !m.IsReadOnly || m.Type.IsCollection || m.Type.IsDictionary || m.Type.IsArray));
699 protected virtual IList<XamlType> LookupPositionalParameters (int parameterCount)
701 if (UnderlyingType == null/* || !IsMarkupExtension*/) // see nunit tests...
702 return null;
704 // check if there is applicable ConstructorArgumentAttribute.
705 // If there is, then return its type.
706 if (parameterCount == 1) {
707 foreach (var xm in GetAllMembers ()) {
708 var ca = xm.GetCustomAttributeProvider ().GetCustomAttribute<ConstructorArgumentAttribute> (false);
709 if (ca != null)
710 return new XamlType [] {xm.Type};
714 var methods = (from m in UnderlyingType.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) where m.GetParameters ().Length == parameterCount select m).ToArray ();
715 if (methods.Length == 1)
716 return (from p in methods [0].GetParameters () select SchemaContext.GetXamlType (p.ParameterType)).ToArray ();
718 if (SchemaContext.SupportMarkupExtensionsWithDuplicateArity)
719 throw new NotSupportedException ("The default LookupPositionalParameters implementation does not allow duplicate arity of markup extensions");
720 return null;
723 BindingFlags flags_get_static = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
725 protected virtual EventHandler<XamlSetMarkupExtensionEventArgs> LookupSetMarkupExtensionHandler ()
727 var a = this.GetCustomAttribute<XamlSetMarkupExtensionAttribute> ();
728 if (a == null)
729 return null;
730 var mi = type.GetMethod (a.XamlSetMarkupExtensionHandler, flags_get_static);
731 if (mi == null)
732 throw new ArgumentException ("Binding to XamlSetMarkupExtensionHandler failed");
733 return (EventHandler<XamlSetMarkupExtensionEventArgs>) Delegate.CreateDelegate (typeof (EventHandler<XamlSetMarkupExtensionEventArgs>), mi);
736 protected virtual EventHandler<XamlSetTypeConverterEventArgs> LookupSetTypeConverterHandler ()
738 var a = this.GetCustomAttribute<XamlSetTypeConverterAttribute> ();
739 if (a == null)
740 return null;
741 var mi = type.GetMethod (a.XamlSetTypeConverterHandler, flags_get_static);
742 if (mi == null)
743 throw new ArgumentException ("Binding to XamlSetTypeConverterHandler failed");
744 return (EventHandler<XamlSetTypeConverterEventArgs>) Delegate.CreateDelegate (typeof (EventHandler<XamlSetTypeConverterEventArgs>), mi);
747 protected virtual bool LookupTrimSurroundingWhitespace ()
749 return this.GetCustomAttribute<TrimSurroundingWhitespaceAttribute> () != null;
752 protected virtual XamlValueConverter<TypeConverter> LookupTypeConverter ()
754 var t = UnderlyingType;
755 if (t == null)
756 return null;
758 // equivalent to TypeExtension.
759 // FIXME: not sure if it should be specially handled here.
760 if (t == typeof (Type))
761 t = typeof (TypeExtension);
763 var a = GetCustomAttributeProvider ();
764 var ca = a != null ? a.GetCustomAttribute<TypeConverterAttribute> (false) : null;
765 if (ca != null)
766 return SchemaContext.GetValueConverter<TypeConverter> (Type.GetType (ca.ConverterTypeName), this);
768 if (t == typeof (object)) // This is a special case. ConverterType is null.
769 return SchemaContext.GetValueConverter<TypeConverter> (null, this);
771 // It's still not decent to check CollectionConverter.
772 var tct = t.GetTypeConverter ().GetType ();
773 #if MOONLIGHT
774 if (tct != typeof (TypeConverter) && tct.Name != "CollectionConverter" && tct.Name != "ReferenceConverter")
775 #else
776 if (tct != typeof (TypeConverter) && tct != typeof (CollectionConverter) && tct != typeof (ReferenceConverter))
777 #endif
778 return SchemaContext.GetValueConverter<TypeConverter> (tct, this);
779 return null;
782 protected virtual Type LookupUnderlyingType ()
784 return underlying_type;
787 protected virtual bool LookupUsableDuringInitialization ()
789 var a = this.GetCustomAttribute<UsableDuringInitializationAttribute> ();
790 return a != null && a.Usable;
793 static XamlValueConverter<ValueSerializer> string_value_serializer;
795 protected virtual XamlValueConverter<ValueSerializer> LookupValueSerializer ()
797 return LookupValueSerializer (this, GetCustomAttributeProvider ());
800 internal static XamlValueConverter<ValueSerializer> LookupValueSerializer (XamlType targetType, ICustomAttributeProvider provider)
802 if (provider == null)
803 return null;
805 var a = provider.GetCustomAttribute<ValueSerializerAttribute> (true);
806 if (a != null)
807 return new XamlValueConverter<ValueSerializer> (a.ValueSerializerType ?? Type.GetType (a.ValueSerializerTypeName), targetType);
809 if (targetType.BaseType != null) {
810 var ret = targetType.BaseType.LookupValueSerializer ();
811 if (ret != null)
812 return ret;
815 if (targetType.UnderlyingType == typeof (string)) {
816 if (string_value_serializer == null)
817 string_value_serializer = new XamlValueConverter<ValueSerializer> (typeof (StringValueSerializer), targetType);
818 return string_value_serializer;
821 return null;
824 static string GetXamlName (Type type)
826 string n;
827 if (!type.IsNestedPublic && !type.IsNestedAssembly && !type.IsNestedPrivate)
828 n = type.Name;
829 else
830 n = GetXamlName (type.DeclaringType) + "+" + type.Name;
831 if (type.IsGenericType && !type.ContainsGenericParameters) // the latter condition is to filter out "nested non-generic type within generic type".
832 return n.Substring (0, n.IndexOf ('`'));
833 else
834 return n;