Hemme's Blog

Stories from behind the keyboard

  • RSS
  • Twitter
  • Linkedin

If you want to add a simple type value value-type value to a ResourceDictionary or to the Resources property of a WPF/Silverlight control (or whatever)… you simply can’t. I tried writing something like the following code, but suddenly I had to admit there’s no way to set a value… and this is almost acceptable, since a simple type doesn’t have a property to set!

<System:Int32 x:Key="MyIntegerResource" NowWhat??/> 

In order to store something in your resource file or property, you have to store it as an object. So, as far as simple types are concerned. you have to wrap them into an utility class. The following is my utility Wrapper code definition:

public class Wrapper 
{ 
  public object Value { get; set; } 
}
So far so good… now I can store a simple value using such a XAML snippet:
<my:Wrapper x:Key="aSimpleValue" Value="123"/>

Wait… this isn’t what I expected… Value will be the String “123”, not the Int32 number 123. Moreover, this wrapper doesn’t look to me like a complete solution.

My next step is creating (yet another) MarkupExtension. As I told in my previous post, you can extend XAML creating a markup extension, which you will use like you do with {Binding}, {StaticResource} and so on… The extension I’m creating will let me instanciate any type, provided there is an IConverter from String to the type I need. The following code describe how I intend to use this extension:

<!-- using it as a wrapped resource -->
<my:Wrapper x:Key="aDateValue" 
Value="{my:InstanceOf Type=core:DateTime, Value='1/1/2010'}"/> 

<!-- using it in a standard property, redundant enough! -->
<TextBlock Width="{my:InstanceOf Type=core:Double, Value='12'}"/>

All in all, I have to declare a class called InstanceOfExtension, derive it from MarkupExtension, declare a Type property called Type, a String property called Value and override the method ProvideValue(). Here comes the code:

public class InstanceOfExtension:MarkupExtension 
{ 
  public Type Type { get; set; } 
  public String Value { get; set; } 
  public override object ProvideValue(
  IServiceProvider serviceProvider) 
  { 
    try 
    { 
      return Convert.ChangeType(Value, Type); 
    } 
    catch 
    { 
      return null;   
    } 
  }
}

The method Convert.ChangeType(value, type) invokes the implementation of the conversion method defined by the IConvertible interface of the String Value (e.g Value.ToInt16(), Value.ToSByte() and so on, read MSDN guide for the complete list).

Conclusion

The technique used here can be fine tuned. For instance, converting only to simple types is quite reductive if not futile, since you can simply use the standard conversion capabilities of XAML language. Anyway the extension described here gives you full control over the converted type and fits perfectly to the Wrapper class needs.

No comments: