.net 4.0 - Write a "partial" XAML TypeConverter that can convert to/from only a specific sub-type in a hierarchy -
given base class color
@ least 2 sub-types, rgbcolor
, cmykcolor
:
abstract partial class color { } sealed class rgbcolor : color { public byte r { get; set; } public byte g { get; set; } public byte b { get; set; } } sealed class cmykcolor : color { public byte c { get; set; } public byte m { get; set; } public byte y { get; set; } public byte k { get; set; } }
and type going (de-) serialize to/from xaml .net 4's system.xaml.xamlservices
:
class { public color color { get; set; } }
i able abbreviate rgb colors on xaml side this:
<something color="#010203" />
instead of having type out:
<something> <something.color> <rgbcolor r="1" g="2" b="3" /> </something.color> </something>
this done typeconverter
. (find current implementation @ end of question.) problem don't need, nor want, special abbreviation syntax other sub-types of color
, such cmykcolor
.
how can write typeconverter
color
works 1 of sub-types, rgbcolor
?
(i have tried write typeconverter
rgbcolor
instead of color
, xaml serializer doesn't appear use when encounters color
property.)
// using system; // using system.componentmodel; // using system.globalization; [typeconverter(typeof(colorconverter))] partial class color { } sealed class colorconverter : typeconverter { public override bool canconvertfrom(itypedescriptorcontext context, type sourcetype) { return sourcetype == typeof(string) || base.canconvertfrom(context, sourcetype); } public override bool canconvertto(itypedescriptorcontext context, type destinationtype) { return destinationtype == typeof(string) || base.canconvertto(context, destinationtype); } public override object convertfrom(itypedescriptorcontext context, cultureinfo culture, object value) { // omitted brevity's sake } public override object convertto(itypedescriptorcontext context, cultureinfo culture, object value, type destinationtype) { debug.assert(value color); if (destinationtype == typeof(string)) { if (value rgbcolor) { var color = (rgbcolor)value; return string.format("#{0:x2}{1:x2}{2:x2}", color.r, color.g, color.b); } else { throw new notsupportedexception(); // ? } } else { return base.convertto(context, culture, value, destinationtype); } } }
it turns out there different type of converter can used that: valueserializer
. value serializers differ type converters in 2 key ways:
- they can convert to/from strings. (other types aren't relevant xaml, anyway.)
- they receive object converted in
canconvert...
stage. (that important bit.)
the main problem i've had value serializers having them invoked xamlservices
.
here's solution:
first, must apply not value serializer, type converter base class:
// both types of converters must applied! [typeconverter(typeof(colorconverter))] [valueserializer(typeof(colorvalueserializer))] partial class color { }
without type converter attribute, value serializer never invoked!
next, type converter must written converts strings (what msdn calls "the load path"):
sealed class colorconverter : typeconverter { public override bool canconvertfrom(..., type sourcetype) { return sourcetype == typeof(string) || base.canconvertfrom(...); } public override bool canconvertto(..., type destinationtype) { return destinationtype != typeof(string) && base.canconvertto(...); // above != not typo! must not let // type converter conversion string. } public override object convertfrom(...) { // parse #rrggbb string , return corresponding rgbcolor } }
finally, let value serializer deal conversions string (the "save path"):
sealed class colorvalueserializer : valueserializer { public override bool canconverttostring(object value, ...) { return value rgbcolor; } public override string converttostring(object value, ...) { // convert rgbcolor "#{r}{g}{b}" string } }
Comments
Post a Comment