Thursday, November 25, 2010

WPF – Declaratively binding a ViewModel

The MVVM pattern is widely adopted within WPF and Silverlight. The very flexible binding mechanism introduced with WPF allows for a loose coupling between the view and its model. The only thing you have to do is to set the view model as DataContext for the view. All further communication can then be done by binding the properties of the model to the view. Frameworks like Prism attempt to decouple the view model as far as possible from the view so that there are no unnecessary dependencies. But even in the best case the view has to know the type of the model in order to get it as its DataContext:

<UserControl.DataContext>
  <mv:ViewModel />
</UserControl.DataContext>

I’ll show you in this blog post how to achieve even more decoupling by declaratively specifying the view model using attributes. The concept depends on an attribute which marks a view model and a container that contains references to all found view model types within an assembly. So first we define the following attribute to mark all our view models:

[AttributeUsage(AttributeTargets.Class)]
public class DataContextAttribute : Attribute
{
    public DataContextAttribute(string key)
    {
        Key = key;
    }

    public string Key
    {
        get;       
    }
}

The attribute can be applied to any class and needs a unique key so that it can be identified later on. We can now use this new attribute to decorate our view model class. For the key I chose to use a GUID. You may use any other string value as well:

[DataContext("1C052C7C-E346-4CD9-A20C-D0617FA6F73D")]
public class WpfUserControlViewModel
{
   
}

That was pretty easy so far. Now we need a component that searches all types in our application for the data context attribute and stores that information accordingly. We do this by using reflection to look for the attribute. A separate class will store the found information in a dictionary:

public static class ViewModelContainerReference
{
    private static readonly ViewModelContainer Container = new ViewModelContainer();

    public static object Items
    {
        get { return Container; }
    }

    public static void Initialize()
    {
        Type[] types = Assembly.GetEntryAssembly().GetTypes();
        foreach (var type in types)
        {
            object[] attr = type.GetCustomAttributes(
  typeof(Utilities.DataContextAttribute), false);
            if (attr.Length == 1)
            {
                Container.Add(
                  ((DataContextAttribute)attr[0]).Key, type);
            }
        }
    }
}

The container which is of type ViewModelContainer stores the key and the according type in a dictionary. More precisely the container inherits the generic dictionary class and has only one indexer method that returns a new instance of a type to a given key:

public class ViewModelContainer : Dictionary<string, Type>
{
    public new object this[string name]
    {
        get
        {
            Type type;
            if (TryGetValue(name, out type))
            {
                return Activator.CreateInstance(type);
            }
            return null;
        }

    }
}

So examining the code you’ll probably notice that we expect every view model to have a parameterless constructor in order to create it vith the Activator. Another condition that arises from the whole concept is that the initialization code runs before any view which uses the concept is displayed. Otherwise no according view model will be found.
With the ViewModelContainerReference and the ViewModelContainer we can now specify the data context for a view like so:

DataContext="{Binding Source={x:Static Utilities:ViewModelContainerReference.Items}, Path=[1C052C7C-E346-4CD9-A20C-D0617FA6F73D]}"

The concrete view model is now given by a string in the Path of the Binding property. The string corresponds to the key defined in the data context attribute. When the view gets initialized it accesses the Items collection of the ViewModelContainerReference and passes the string in the Path property as parameter. Therefore the view no longer needs a reference to the type of the model. So now, you have to possibility to change the view model type without changing the view as long as you provide the correct key.

Friday, November 12, 2010

Converting 16 bit gray-scale TIFF images for use in WPF

When you try to open a 16 bit gray-scale TIFF image with WPF components you will only see a black screen. The image cannot be displayed by the Bitmap Decoder, because 16 bit gray-scale TIFFs are not supported. But this image format is widely used in scientific visualization (especially microscopy). So, if you want to display such images you first have to normalize them to 8 bit, which is the format, the decoder can read.
To use the image in WPF, we’ll be working with BitmapSource objects. Therefore we create the following method, which takes a BitmapSource representing the 16 bit gray-scale TIFF and returns an 8 bit BitmapSource:

public static BitmapSource NormalizeTiffTo8BitImage(BitmapSource source)

The following high level steps have to be taken to convert the image:
1.       Copy the pixels from the source to a byte array
2.       Get the max values of the first and the second byte per pixel
3.       Normalize each source pixel and copy it to a destination array
4.       Create a new BitmapSource out of the destination array

Let’s take a detailed look at the several steps:

1.    Copy pixels from source to byte array
This step is rather easy. To determine the length of the array, we first need the stride of the image. The stride specifies the number of bytes per image line. In the case of a 16 bit image that value is simply two times the image width (see the code below, were BitsPerPixel is in our case 16), because two bytes are used for each pixel. With the stride, we can initialize a new array and copy the pixels from the BitmapSource:

int rawStride = source.PixelWidth * source.Format.BitsPerPixel / 8;
var rawImage = new byte[rawStride * source.PixelHeight];

source.CopyPixels(rawImage, rawStride, 0);

2. Get the max values of the first and the second byte per pixel
To get our factors for normalizing, we need to determine the max values within the image of both byte values per pixel. In a 16 bit gray-scale TIFF each pixel is represented by two byte values, each between 0 and 255. The first value will always be greater or at least the same as the second one. So we can use an extension method to get the maximum of the first byte value:

ushort maxValue = rawImage.Max();

For the second value, we have to iterate through the array:

int max = 0;
for (int i = 0; i < rawImage.Length; i++)
{
    if (rawImage[i + 1] > max)
    {
        max = rawImage[i + 1];
    }
    i++;
}
if (max == 0) max = 1;

With these two values, we can now define the two needed normalizing factors as follows:

int normFaktor = max == 1 ? 1 : 128 / max;
int faktor = 255 / maxValue;

3. Normalize each source pixel and copy it to a destination array
This step is where the real work is done. Again we need to iterate through the array, take both byte values per pixel, normalize them to one byte value and store the new value in a separate array. What we do here is a projection from the range of 0 to 65536 to a range from 0 to 255:

var buffer8Bit = new byte[rawImage.Length / 2];

for (int src = 0, dst = 0; src < rawImage.Length; dst++)
{
    int value16 = rawImage[src++];
    int value8 = ((value16 * faktor) / max) - normFaktor;

    if (rawImage[src] > 0)
    {
        int b = rawImage[src] << 8;
        value8 = ((value16 + b) / max) - normFaktor;
    }

    buffer8Bit[dst] = (byte)Math.Max(value8, 0);
    src++;
}

4. Create a new BitmapSource out of the destination array
This is again an easy step, because BitmapSource provides a static create method that takes a source array beneath other parameters to create a new BitmapSource:

return BitmapSource.Create(source.PixelWidth, source.PixelHeight,
    source.DpiX, source.DpiY, PixelFormats.Gray8, BitmapPalettes.Gray256,
    buffer8Bit, rawStride / 2);

The newly created BitmapSource can now be displayed within a WPF application.

Some additional words about the sample code:
It took some time and search to find out that algorithm (thanks to all people in forums and web sites who helped me on this) and even after converting lot of sample images I’m not completely sure if it works for all 16 bit gray-scale TIFF images, because TIFF is a very variable and extensible format. But I think it gives a very good starting point.

Thursday, November 4, 2010

Binding Enum values to WPF Item Collection Controls

There are several ways to bind an enumeration to an item collection control (like Listbox or Combobox) in WPF. Because we’re using XAML I will show you the declarative way. Let’s assume we have an enumeration that represents different ways of transmission:

public enum Transmission
{       
    None = 0,       
    Phone = 2,
    Mail = 4,
    Letter = 8,
    Chat = 16
}

This enumeration needs to be bound to a combo box in our WPF window. So the easiest way is to use an ObjectDataProvider which returns an array of the enum values. In XAML that would look like the following code snippet:

<ObjectDataProvider
    MethodName="GetValues"
    ObjectType="{x:Type System:Enum}"
    x:Key="TransmissionTypeEnum">
  <ObjectDataProvider.MethodParameters>
    <x:Type TypeName="App:Transmission"></x:Type>
  </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

We define an ObjectDataProvider and tell it to use the GetValues method on the Enum object. Enum provides this static method which takes the type argument that represents the current enum type. So we add a method parameter and give it the type of our transmission enumeration. After defining the provider, you can use it right away as a binding source for an item collection control like so:

<ComboBox ItemsSource="{Binding Source={StaticResource TransmissionTypeEnum}}"

That’s it. Now, the combo box should display the values of the enum.
But what do we do, if we want to display user friendly text instead of the possibly technical enum definitions? Again, there are several ways to achieve this. The only thing you always need is a place to store the description for each enum field. Here we use the DescriptionAttribute class that is defined in the System.ComponentModel namespace. It allows us, to write the description right above each field:

public enum Transmission
{
    [DescriptionAttribute("None")]
    None = 0,

    [DescriptionAttribute("Telephone")]
    Phone = 2,

    [DescriptionAttribute("E-Mail Attachment")]
    Mail = 4,

    [DescriptionAttribute("Letter")]
    Letter = 8,

    [DescriptionAttribute("Chat (Text, Voice or Video)")]
    Chat = 16
}

Now we need a component to read out the descriptions and provide some kind of item source to bind to our combo box. Let’s create a static class that contains a method which gets the enum type and returns a Dictionary with the description for each field in the enumeration:

public static IDictionary<string, object> GetDict(Type enumType)
{
    var typeList = new Dictionary<string, object>();

    //get the description attribute of each enum field
    DescriptionAttribute descriptionAttribute;
    foreach (var value in Enum.GetValues(enumType))
    {
        FieldInfo fieldInfo = enumType.GetField((value.ToString()));
        descriptionAttribute =
(DescriptionAttribute)Attribute.GetCustomAttribute(fieldInfo,
typeof(DescriptionAttribute));
        if (descriptionAttribute != null)
        {
            typeList.Add(descriptionAttribute.Description, value);
        }
    }

    return typeList;
}

This code is really straight forward. It gets the description attribute for each field in the enumeration by using reflection. The description and the enum value itself are added to a dictionary which can be used as binding source for our combo box:

<ObjectDataProvider
    MethodName="GetDict"
    ObjectType="{x:Type App:EnumDescriptionValueDict}"
    x:Key="EnumDescriptionDict">
  <ObjectDataProvider.MethodParameters>
    <x:Type TypeName="App:Transmission"></x:Type>
  </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

<ComboBox
      ItemsSource="{Binding Source={StaticResource EnumDescriptionDict}}"
      DisplayMemberPath="Key"
      SelectedValuePath="Value"/>

Because we are using a dictionary now, we have to tell the combo box the appropriate display and value path. Those are simply the properties of a single KeyValuePair within the dictionary. When you run the code, you will see the descriptions within the combo box, instead of the enumeration values.

Just one last thing for this post I want you to show is the binding of the selected value in the combo box to a view model property. Let’s assume we have a view model with a property of type Transmission. We want this property bound to the currently selected value of the combo box. All we need is a Converter that converts the enum value to string and also converts a string to an enum value. Therefore I’ll name this converter EnumToStringConverter:

[ValueConversion(typeof(Enum), typeof(String))]
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value.ToString();
    }

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value == null ? null : Enum.Parse(targetType,
                                         value.ToString(), true);
    }
}

With the value converter defined and the according property on the view model, we can now add the following line to our combo box:

SelectedValue="{Binding Transmission, Converter={StaticResource EnumConverter}, Mode=TwoWay}"

Here you go. With an enum bound to a combo box that shows custom descriptions and promotes its selected value right to the underlying view model. Enjoy it!