using System.Reflection;
using System.Windows.Markup;
using System.Xaml.Schema;
+using System.Xml.Serialization;
namespace System.Xaml
{
{
}
- static readonly Type [] predefined_types = {
- typeof (XData), typeof (Uri), typeof (TimeSpan), typeof (PropertyDefinition), typeof (MemberDefinition), typeof (Reference)
- };
+// static readonly Type [] predefined_types = {
+// typeof (XData), typeof (Uri), typeof (TimeSpan), typeof (PropertyDefinition), typeof (MemberDefinition), typeof (Reference)
+// };
public XamlType (Type underlyingType, XamlSchemaContext schemaContext, XamlTypeInvoker invoker)
: this (schemaContext, invoker)
XamlType xt;
if (XamlLanguage.InitializingTypes) {
- Name = type.GetXamlName ();
+ // These are special. Only XamlLanguage members are with shorthand name.
+ if (type == typeof (PropertyDefinition))
+ Name = "Property";
+ else if (type == typeof (MemberDefinition))
+ Name = "Member";
+ else
+ Name = GetXamlName (type);
PreferredXamlNamespace = XamlLanguage.Xaml2006Namespace;
} else if ((xt = XamlLanguage.AllTypes.FirstOrDefault (t => t.UnderlyingType == type)) != null) {
Name = xt.Name;
PreferredXamlNamespace = XamlLanguage.Xaml2006Namespace;
} else {
- Name = type.GetXamlName ();
- PreferredXamlNamespace = String.Format ("clr-namespace:{0};assembly={1}", type.Namespace, type.Assembly.GetName ().Name);
+ Name = GetXamlName (type);
+ PreferredXamlNamespace = schemaContext.GetXamlNamespace (type.Namespace) ?? String.Format ("clr-namespace:{0};assembly={1}", type.Namespace, type.Assembly.GetName ().Name);
+ }
+ if (type.IsGenericType) {
+ TypeArguments = new List<XamlType> ();
+ foreach (var gta in type.GetGenericArguments ())
+ TypeArguments.Add (schemaContext.GetXamlType (gta));
}
}
Name = unknownTypeName;
PreferredXamlNamespace = unknownTypeNamespace;
TypeArguments = typeArguments != null && typeArguments.Count == 0 ? null : typeArguments;
- explicit_ns = unknownTypeNamespace;
+// explicit_ns = unknownTypeNamespace;
}
protected XamlType (string typeName, IList<XamlType> typeArguments, XamlSchemaContext schemaContext)
Type type, underlying_type;
- string explicit_ns;
+// string explicit_ns;
// populated properties
XamlType base_type;
get { return LookupValueSerializer (); }
}
+ internal string GetInternalXmlName ()
+ {
+ if (IsMarkupExtension && Name.EndsWith ("Extension", StringComparison.Ordinal))
+ return Name.Substring (0, Name.Length - 9);
+ var stn = XamlLanguage.SpecialNames.FirstOrDefault (s => s.Type == this);
+ return stn != null ? stn.Name : Name;
+ }
+
public static bool operator == (XamlType left, XamlType right)
{
return IsNull (left) ? IsNull (right) : left.Equals (right);
public bool Equals (XamlType other)
{
+ // It does not compare XamlSchemaContext.
return !IsNull (other) &&
UnderlyingType == other.UnderlyingType &&
Name == other.Name &&
public override string ToString ()
{
- return String.IsNullOrEmpty (PreferredXamlNamespace) ? Name : String.Concat ("{", PreferredXamlNamespace, "}", Name);
+ return new XamlTypeName (this).ToString ();
+ //return String.IsNullOrEmpty (PreferredXamlNamespace) ? Name : String.Concat ("{", PreferredXamlNamespace, "}", Name);
}
public virtual bool CanAssignTo (XamlType xamlType)
{
- throw new NotImplementedException ();
+ if (this.UnderlyingType == null)
+ return xamlType == XamlLanguage.Object;
+ var ut = xamlType.UnderlyingType ?? typeof (object);
+ return ut.IsAssignableFrom (UnderlyingType);
}
public XamlMember GetAliasedProperty (XamlDirective directive)
public XamlMember GetMember (string name)
{
- return LookupMember (name, false);
+ return LookupMember (name, true);
}
public IList<XamlType> GetPositionalParameters (int parameterCount)
protected virtual IEnumerable<XamlMember> LookupAllAttachableMembers ()
{
if (UnderlyingType == null)
- return BaseType != null ? BaseType.GetAllMembers () : null;
- return DoLookupAllAttachableMembers ();
+ return BaseType != null ? BaseType.GetAllAttachableMembers () : empty_array;
+ if (all_attachable_members_cache == null) {
+ all_attachable_members_cache = new List<XamlMember> (DoLookupAllAttachableMembers ());
+ all_attachable_members_cache.Sort (TypeExtensionMethods.CompareMembers);
+ }
+ return all_attachable_members_cache;
}
IEnumerable<XamlMember> DoLookupAllAttachableMembers ()
{
- yield break; // FIXME: what to return here?
+ // based on http://msdn.microsoft.com/en-us/library/ff184560.aspx
+ var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
+
+ var gl = new Dictionary<string,MethodInfo> ();
+ var sl = new Dictionary<string,MethodInfo> ();
+ var al = new Dictionary<string,MethodInfo> ();
+ //var rl = new Dictionary<string,MethodInfo> ();
+ var nl = new List<string> ();
+ foreach (var mi in UnderlyingType.GetMethods (bf)) {
+ string name = null;
+ if (mi.Name.StartsWith ("Get", StringComparison.Ordinal)) {
+ if (mi.ReturnType == typeof (void))
+ continue;
+ var args = mi.GetParameters ();
+ if (args.Length != 1)
+ continue;
+ name = mi.Name.Substring (3);
+ gl.Add (name, mi);
+ } else if (mi.Name.StartsWith ("Set", StringComparison.Ordinal)) {
+ // looks like the return type is *ignored*
+ //if (mi.ReturnType != typeof (void))
+ // continue;
+ var args = mi.GetParameters ();
+ if (args.Length != 2)
+ continue;
+ name = mi.Name.Substring (3);
+ sl.Add (name, mi);
+ } else if (mi.Name.EndsWith ("Handler", StringComparison.Ordinal)) {
+ var args = mi.GetParameters ();
+ if (args.Length != 2)
+ continue;
+ if (mi.Name.StartsWith ("Add", StringComparison.Ordinal)) {
+ name = mi.Name.Substring (3, mi.Name.Length - 3 - 7);
+ al.Add (name, mi);
+ }/* else if (mi.Name.StartsWith ("Remove", StringComparison.Ordinal)) {
+ name = mi.Name.Substring (6, mi.Name.Length - 6 - 7);
+ rl.Add (name, mi);
+ }*/
+ }
+ if (name != null && !nl.Contains (name))
+ nl.Add (name);
+ }
+
+ foreach (var name in nl) {
+ MethodInfo m;
+ var g = gl.TryGetValue (name, out m) ? m : null;
+ var s = sl.TryGetValue (name, out m) ? m : null;
+ if (g != null || s != null)
+ yield return new XamlMember (name, g, s, SchemaContext);
+ var a = al.TryGetValue (name, out m) ? m : null;
+ //var r = rl.TryGetValue (name, out m) ? m : null;
+ if (a != null)
+ yield return new XamlMember (name, a, SchemaContext);
+ }
}
+ static readonly XamlMember [] empty_array = new XamlMember [0];
+
protected virtual IEnumerable<XamlMember> LookupAllMembers ()
{
if (UnderlyingType == null)
- return BaseType != null ? BaseType.GetAllMembers () : null;
- return DoLookupAllMembers ();
+ return BaseType != null ? BaseType.GetAllMembers () : empty_array;
+ if (all_members_cache == null) {
+ all_members_cache = new List<XamlMember> (DoLookupAllMembers ());
+ all_members_cache.Sort (TypeExtensionMethods.CompareMembers);
+ }
+ return all_members_cache;
}
+
+ List<XamlMember> all_members_cache;
+ List<XamlMember> all_attachable_members_cache;
IEnumerable<XamlMember> DoLookupAllMembers ()
{
- foreach (var pi in UnderlyingType.GetProperties ())
- if (pi.CanRead && pi.CanWrite)
+ // This is a hack that is likely required due to internal implementation difference in System.Uri. Our Uri has two readonly collection properties
+ if (this == XamlLanguage.Uri)
+ yield break;
+
+ var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+
+ foreach (var pi in UnderlyingType.GetProperties (bf)) {
+ if (pi.Name.Contains ('.')) // exclude explicit interface implementations.
+ continue;
+ if (pi.CanRead && (pi.CanWrite || IsCollectionType (pi.PropertyType) || typeof (IXmlSerializable).IsAssignableFrom (pi.PropertyType)) && pi.GetIndexParameters ().Length == 0)
yield return new XamlMember (pi, SchemaContext);
+ }
+ foreach (var ei in UnderlyingType.GetEvents (bf))
+ yield return new XamlMember (ei, SchemaContext);
+ }
+
+ static bool IsPublicAccessor (MethodInfo mi)
+ {
+ return mi != null && mi.IsPublic;
+ }
+
+ bool IsCollectionType (Type type)
+ {
+ if (type == null)
+ return false;
+ var xt = SchemaContext.GetXamlType (type);
+ return xt.LookupCollectionKind () != XamlCollectionKind.None;
}
protected virtual IList<XamlType> LookupAllowedContentTypes ()
{
- throw new NotImplementedException ();
+ // the actual implementation is very different from what is documented :(
+ return null;
+
+ /*
+ var l = new List<XamlType> ();
+ if (ContentWrappers != null)
+ l.AddRange (ContentWrappers);
+ if (ContentProperty != null)
+ l.Add (ContentProperty.Type);
+ if (ItemType != null)
+ l.Add (ItemType);
+ return l.Count > 0 ? l : null;
+ */
}
+
protected virtual XamlMember LookupAttachableMember (string name)
{
- throw new NotImplementedException ();
+ return GetAllAttachableMembers ().FirstOrDefault (m => m.Name == name);
}
- [MonoTODO]
protected virtual XamlType LookupBaseType ()
{
if (base_type == null) {
if (UnderlyingType == null)
- // FIXME: probably something advanced is needed here.
- base_type = new XamlType (typeof (object), SchemaContext, Invoker);
+ base_type = SchemaContext.GetXamlType (typeof (object));
else
- base_type = type.BaseType == null || type.BaseType == typeof (object) ? null : new XamlType (type.BaseType, SchemaContext, Invoker);
+ base_type = type.BaseType == null || type.BaseType == typeof (object) ? null : SchemaContext.GetXamlType (type.BaseType);
}
return base_type;
}
// This implementation is not verified. (No place to use.)
- protected virtual XamlCollectionKind LookupCollectionKind ()
+ protected internal virtual XamlCollectionKind LookupCollectionKind ()
{
if (UnderlyingType == null)
return BaseType != null ? BaseType.LookupCollectionKind () : XamlCollectionKind.None;
if (type.ImplementsAnyInterfacesOf (typeof (IDictionary), typeof (IDictionary<,>)))
return XamlCollectionKind.Dictionary;
- if (type.ImplementsAnyInterfacesOf (typeof (ICollection), typeof (ICollection<>)))
+ if (type.ImplementsAnyInterfacesOf (typeof (IList), typeof (ICollection<>)))
return XamlCollectionKind.Collection;
return XamlCollectionKind.None;
protected virtual IList<XamlType> LookupContentWrappers ()
{
- var l = new List<XamlType> ();
- foreach (ContentWrapperAttribute a in CustomAttributeProvider.GetCustomAttributes (typeof (ContentWrapperAttribute), false))
- l.Add (SchemaContext.GetXamlType (a.ContentWrapper));
+ if (GetCustomAttributeProvider () == null)
+ return null;
+
+ var arr = GetCustomAttributeProvider ().GetCustomAttributes (typeof (ContentWrapperAttribute), false);
+ if (arr == null || arr.Length == 0)
+ return null;
+ var l = new XamlType [arr.Length];
+ for (int i = 0; i < l.Length; i++)
+ l [i] = SchemaContext.GetXamlType (((ContentWrapperAttribute) arr [i]).ContentWrapper);
return l;
}
- internal ICustomAttributeProvider CustomAttributeProvider {
- get { return LookupCustomAttributeProvider (); }
+ internal ICustomAttributeProvider GetCustomAttributeProvider ()
+ {
+ return LookupCustomAttributeProvider ();
}
- protected virtual ICustomAttributeProvider LookupCustomAttributeProvider ()
+ protected internal virtual ICustomAttributeProvider LookupCustomAttributeProvider ()
{
return UnderlyingType;
}
+
protected virtual XamlValueConverter<XamlDeferringLoader> LookupDeferringLoader ()
{
throw new NotImplementedException ();
protected virtual bool LookupIsNullable ()
{
- return !type.IsValueType || type.ImplementsInterface (typeof (Nullable<>));
+ return !type.IsValueType || type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
}
protected virtual bool LookupIsPublic ()
protected virtual bool LookupIsXData ()
{
- // huh? XamlLanguage.XData.IsXData returns false(!)
- // return typeof (XData).IsAssignableFrom (UnderlyingType);
- return false;
+ return CanAssignTo (SchemaContext.GetXamlType (typeof (IXmlSerializable)));
}
protected virtual XamlType LookupItemType ()
{
if (IsArray)
return new XamlType (type.GetElementType (), SchemaContext);
+ if (IsDictionary) {
+ if (!IsGeneric)
+ return new XamlType (typeof (object), SchemaContext);
+ return new XamlType (type.GetGenericArguments () [1], SchemaContext);
+ }
if (!IsCollection)
return null;
if (!IsGeneric)
protected virtual XamlMember LookupMember (string name, bool skipReadOnlyCheck)
{
- var pi = UnderlyingType.GetProperty (name);
- if (pi != null && (skipReadOnlyCheck || pi.CanWrite))
- return new XamlMember (pi, SchemaContext);
- var ei = UnderlyingType.GetEvent (name);
- if (ei != null)
- return new XamlMember (ei, SchemaContext);
- return null;
+ // FIXME: verify if this does not filter out events.
+ return GetAllMembers ().FirstOrDefault (m => m.Name == name && (skipReadOnlyCheck || !m.IsReadOnly || m.Type.IsCollection || m.Type.IsDictionary || m.Type.IsArray));
}
protected virtual IList<XamlType> LookupPositionalParameters (int parameterCount)
{
- throw new NotImplementedException ();
+ if (UnderlyingType == null/* || !IsMarkupExtension*/) // see nunit tests...
+ return null;
+
+ // check if there is applicable ConstructorArgumentAttribute.
+ // If there is, then return its type.
+ if (parameterCount == 1) {
+ foreach (var xm in GetAllMembers ()) {
+ var ca = xm.GetCustomAttributeProvider ().GetCustomAttribute<ConstructorArgumentAttribute> (false);
+ if (ca != null)
+ return new XamlType [] {xm.Type};
+ }
+ }
+
+ var methods = (from m in UnderlyingType.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) where m.GetParameters ().Length == parameterCount select m).ToArray ();
+ if (methods.Length == 1)
+ return (from p in methods [0].GetParameters () select SchemaContext.GetXamlType (p.ParameterType)).ToArray ();
+
+ if (SchemaContext.SupportMarkupExtensionsWithDuplicateArity)
+ throw new NotSupportedException ("The default LookupPositionalParameters implementation does not allow duplicate arity of markup extensions");
+ return null;
}
BindingFlags flags_get_static = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
if (t == null)
return null;
- var a = CustomAttributeProvider.GetCustomAttribute<TypeConverterAttribute> (false);
- if (a != null)
- return SchemaContext.GetValueConverter<TypeConverter> (Type.GetType (a.ConverterTypeName), this);
-
- if (t == typeof (object))
- return SchemaContext.GetValueConverter<TypeConverter> (typeof (TypeConverter), this);
// equivalent to TypeExtension.
// FIXME: not sure if it should be specially handled here.
if (t == typeof (Type))
- return SchemaContext.GetValueConverter<TypeConverter> (typeof (TypeExtensionConverter), this);
+ t = typeof (TypeExtension);
+
+ var a = GetCustomAttributeProvider ();
+ var ca = a != null ? a.GetCustomAttribute<TypeConverterAttribute> (false) : null;
+ if (ca != null)
+ return SchemaContext.GetValueConverter<TypeConverter> (Type.GetType (ca.ConverterTypeName), this);
+
+ if (t == typeof (object)) // This is a special case. ConverterType is null.
+ return SchemaContext.GetValueConverter<TypeConverter> (null, this);
// It's still not decent to check CollectionConverter.
- var tct = TypeDescriptor.GetConverter (t).GetType ();
- if (tct != typeof (TypeConverter) && tct != typeof (CollectionConverter))
+ var tct = t.GetTypeConverter ().GetType ();
+ if (tct != typeof (TypeConverter) && tct != typeof (CollectionConverter) && tct != typeof (ReferenceConverter))
return SchemaContext.GetValueConverter<TypeConverter> (tct, this);
return null;
}
protected virtual XamlValueConverter<ValueSerializer> LookupValueSerializer ()
{
- return LookupValueSerializer (this, CustomAttributeProvider);
+ return LookupValueSerializer (this, GetCustomAttributeProvider ());
}
internal static XamlValueConverter<ValueSerializer> LookupValueSerializer (XamlType targetType, ICustomAttributeProvider provider)
return null;
}
+
+ static string GetXamlName (Type type)
+ {
+ string n;
+ if (!type.IsNestedPublic && !type.IsNestedAssembly && !type.IsNestedPrivate)
+ n = type.Name;
+ else
+ n = GetXamlName (type.DeclaringType) + "+" + type.Name;
+ if (type.IsGenericType && !type.ContainsGenericParameters) // the latter condition is to filter out "nested non-generic type within generic type".
+ return n.Substring (0, n.IndexOf ('`'));
+ else
+ return n;
+ }
}
}