Work process: How to use and build type converters

7 ביולי 2008

[This blog was migrated. You will not be able to comment here.
The new URL of this post is http://khason.net/blog/work-process-how-to-use-and-build-type-converters/]


Today, I want to start new tag – “Work process”. Here I’m going to publish partial classes, fixes, small utilities, I’m building for myself or clients to help in work process. I’ll give an example: currently, I’m working on BiDi support for Silverlight 2.0 (beta 2 to RTM). During the work process, I need to write different classes, such as converters, string utilities, exception helpers etc.

ZK4Y7556 
© Imaginary copyright by  Noel Hendrickson

So, today I’ll public general type converter for generic classes.

What is type converter?

TypeConverter is a service attribute, used to help rendering engine to convert XAML string (usually it strings) to the type, you require in your class implementation. Here an example:

In your custom class you have dependency property of type TextAlignment

public TextAlignment TextAlignment
       {
           get { return (TextAlignment)GetValue(TextAlignmentProperty); }
           set { SetValue(TextAlignmentProperty, value); }
       }

In XAML code it will be used as:

<MyControl TextAlignment=”Left”/>

But, what you’re actually transfer to your class is string “Left”, when you need enum TextAlignment.Left, how to convert it? This for we’re using type converters

Attribute usage

In order to “tell” framework to use your type converter, you should mark target property with special attribute TypeConverterAttribute. Also, you can provide default value to your property by using another attribute DefaultValueAttribute. This will looks as following:

[TypeConverter(typeof(MyTextAlignmentTypeConverter))]
[DefaultValue(TextAlignment.Left)]
public TextAlignment TextAlignment
{
  get { return (TextAlignment)GetValue(TextAlignmentProperty); }
  set { SetValue(TextAlignmentProperty, value); }
}

How to build type converter

In order to build type converter, all you have to do is to build your own class, derived from TypeConverter. It also can be generic class. Then, implement necessary methods, that incorporate your business logic. Like this one, converter any enum value back and forward for TypeConverterAttribute

public class EnumValueConverter<T> : TypeConverter where T:struct
    {
        static EnumValueConverter()
        {
            if (!typeof(T).IsEnum) { Exceptions.ThrowInvalidOperationException("Cannot use this type for conversion"); }
        }

        public override bool CanConvertFrom(Type sourceType)
        {
            return Type.GetTypeCode(sourceType) == TypeCode.String;
        }

        public override object ConvertFrom(object value)
        {
            if (value == null)
            {
                typeof(T).ThrowConvertFromException(value);
            }
            if (value is string)
            {
                return ConvertFromString(value as string);
            }
            return (T)value;
        }

        public override object ConvertFromString(string text)
        {
            return (T)Enum.Parse(typeof(T), text, true);
        }

        public override string ConvertToString(object value)
        {
            return Enum.GetName(typeof(T), value);
        }
    }

Final result

Now, when we built converter and know how to use it, we can easily set it to any DependencyProperty requires conversion from / to enum

[TypeConverter(typeof(EnumValueConverter<LineStackingStrategy>))]
public LineStackingStrategy LineStackingStrategy
{
  get { return (LineStackingStrategy)GetValue(LineStackingStrategyProperty); }
  set { SetValue(LineStackingStrategyProperty, value); }
}

[TypeConverter(typeof(EnumValueConverter<TextAlignment>))]
[DefaultValue(TextAlignment.Right)]
public TextAlignment TextAlignment
  {
   get { return (TextAlignment)GetValue(TextAlignmentProperty); }
   set { SetValue(TextAlignmentProperty, value); }
  }

[TypeConverter(typeof(EnumValueConverter<TextWrapping>))]
public TextWrapping TextWrapping
{
  get { return (TextWrapping)GetValue(TextWrappingProperty); }
  set { SetValue(TextWrappingProperty, value); }
}

We done, have a nice day and be good people.

Stay tuned for release of BiDi support for Silverlight 2.0, sponsored by Development Platform Evangelism unit of Microsoft Israel

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

6 תגובות

  1. Tom7 ביולי 2008 ב 21:44

    It's great to hear about BiDi support for Silverlight 2.0. Will this be an official part of the Silverlight 2.0 release? And on a related note, will its public API be the same as in WPF (i.e. FrameworkElement.FlowDirection property)?

    להגיב
  2. Tamir Khason7 ביולי 2008 ב 21:56

    Tom, it is community project.
    Regarding the API, yes, I'm trying to keep it as closer as possible to WPF

    להגיב
  3. Tom7 ביולי 2008 ב 22:25

    Tamir, thank you for the answers! I'm looking forward to trying this out.

    להגיב
  4. slyi9 ביולי 2008 ב 0:14

    Excellent this is great news indeed.

    להגיב
  5. vamsi11 ביולי 2008 ב 16:34

    It's really good

    להגיב
  6. d-roc30 ביולי 2008 ב 0:43

    I'm under the impression that the DefaultValueAttribute does not work for Silverlight 2 beta 2 and gets ignored. I couldn't get it to work. Would love to hear if anyone ran into the same issues.

    [DefaultValue(TextAlignment.Left)] That shouldn't have worked. Are you sure it wasn't a fluke that it defaulted to 0?

    להגיב