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;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.Globalization;
29 using System.Reflection;
31 using System.Xaml.Schema;
33 namespace System.Windows.Markup
35 [System.Runtime.CompilerServices.TypeForwardedFrom (Consts.AssemblyWindowsBase)]
36 public abstract class ValueSerializer
38 public static ValueSerializer GetSerializerFor (PropertyDescriptor descriptor)
40 return GetSerializerFor (descriptor, null);
43 public static ValueSerializer GetSerializerFor (Type type)
45 return GetSerializerFor (type, null);
49 public static ValueSerializer GetSerializerFor (PropertyDescriptor descriptor, IValueSerializerContext context)
51 if (descriptor == null)
52 throw new ArgumentNullException ("descriptor");
54 return context.GetValueSerializerFor (descriptor);
56 var tc = descriptor.Converter;
57 if (tc != null && tc.GetType () != typeof (TypeConverter))
58 return new TypeConverterValueSerializer (tc);
62 public static ValueSerializer GetSerializerFor (Type type, IValueSerializerContext context)
65 throw new ArgumentNullException ("type");
67 return context.GetValueSerializerFor (type);
69 // Standard MarkupExtensions are serialized without ValueSerializer.
70 if (typeof (MarkupExtension).IsAssignableFrom (type) && XamlLanguage.AllTypes.Any (x => x.UnderlyingType == type))
73 // DateTime is documented as special.
74 if (type == typeof (DateTime))
75 return new DateTimeValueSerializer ();
77 if (type == typeof (string))
78 return new StringValueSerializer ();
80 // FIXME: this is hack. The complete condition is fully documented at http://msdn.microsoft.com/en-us/library/ms590363.aspx
81 if (type.GetCustomAttribute<TypeConverterAttribute> (true) != null) {
82 var tc = TypeDescriptor.GetConverter (type);
83 if (tc != null && tc.GetType () != typeof (TypeConverter))
84 return new TypeConverterValueSerializer (tc);
87 // Undocumented, but System.Type seems also special. While other MarkupExtension returned types are not handled specially, this method returns a valid instance for System.Type. Note that it doesn't for TypeExtension.
88 if (type == typeof (Type))
89 // Since System.Type does not have a valid TypeConverter, I use TypeExtensionConverter (may sound funny considering the above notes!) for this serializer.
90 return new TypeValueSerializer ();
92 // Undocumented, but several primitive types get a valid serializer while it does not have TypeConverter.
93 switch (Type.GetTypeCode (type)) {
98 return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
101 // There is still exceptional type! TimeSpan. Why aren't they documented?
102 if (type == typeof (TimeSpan))
103 return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
110 public virtual bool CanConvertFromString (string value, IValueSerializerContext context)
115 public virtual bool CanConvertToString (object value, IValueSerializerContext context)
120 public virtual object ConvertFromString (string value, IValueSerializerContext context)
122 throw GetConvertFromException (value);
125 public virtual string ConvertToString (object value, IValueSerializerContext context)
127 throw GetConvertToException (value, typeof (string));
130 protected Exception GetConvertFromException (object value)
132 return new NotSupportedException (String.Format ("Conversion from string '{0}' is not supported", value));
135 protected Exception GetConvertToException (object value, Type destinationType)
137 return new NotSupportedException (String.Format ("Conversion from '{0}' to {1} is not supported", value != null ? value.GetType ().Name : "(null)", destinationType));
140 public virtual IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
146 #region Internal implementations.
148 internal class StringValueSerializer : ValueSerializer
150 public override bool CanConvertFromString (string value, IValueSerializerContext context)
155 public override bool CanConvertToString (object value, IValueSerializerContext context)
160 public override object ConvertFromString (string value, IValueSerializerContext context)
165 public override string ConvertToString (object value, IValueSerializerContext context)
167 return (string) value;
170 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
172 throw new NotImplementedException ();
176 internal class TypeValueSerializer : ValueSerializer
178 TypeExtensionConverter txc = new TypeExtensionConverter ();
180 public override bool CanConvertFromString (string value, IValueSerializerContext context)
185 public override bool CanConvertToString (object value, IValueSerializerContext context)
190 public override object ConvertFromString (string value, IValueSerializerContext context)
193 return base.ConvertFromString (value, context);
194 var nsr = (IXamlNamespaceResolver) context.GetService (typeof (IXamlNamespaceResolver));
195 var scp = (IXamlSchemaContextProvider) context.GetService (typeof (IXamlSchemaContextProvider));
196 return scp.SchemaContext.GetXamlType (XamlTypeName.Parse (value, nsr)).UnderlyingType;
199 public override string ConvertToString (object value, IValueSerializerContext context)
201 return (string) txc.ConvertTo (context, CultureInfo.InvariantCulture, value, typeof (string));
204 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
206 throw new NotImplementedException ();
210 internal class TypeConverterValueSerializer : ValueSerializer
212 public TypeConverterValueSerializer (TypeConverter typeConverter)
219 public override bool CanConvertFromString (string value, IValueSerializerContext context)
221 return c.CanConvertFrom (context, typeof (string));
224 public override bool CanConvertToString (object value, IValueSerializerContext context)
226 return c.CanConvertTo (context, typeof (string));
229 public override object ConvertFromString (string value, IValueSerializerContext context)
231 return c.ConvertFromInvariantString (context, value);
234 public override string ConvertToString (object value, IValueSerializerContext context)
236 return value == null ? String.Empty : c.ConvertToInvariantString (context, value);
239 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
241 throw new NotImplementedException ();