Replicating TargetNullValue in Windows8

There are times in this world when using binding statements, that you want to specify a default value for a property if the result provided is null. In a post found here by Jesse Liberty, he details how developers can utilize the TargetNullValue option within the xaml binding statement to provide this option.

Recently I've been porting my SaintsFC WP7 app over to Windows 8 metro app & I've found that this option is no longer available. It's been confirmed that this will likely not be in the RTM version of Windows 8 either so here's a workaround using a converter as a substitute. It's a little more convoluted than a simple property within the binding but it will also be able to provide you with a more extensive feature set as a result.

So for wp7 my binding statement may have looked something like this:

<TextBlock Text={Binding Path='Salutation', TargetNullValue='Hello Sir'} />

However for Windows 8 it looks a little something like this:

<TextBlock Text={Binding Path='Salutation', Converter={StaticResource TargetNullValueConverter}, ConverterParameter='DefaultSalutation1'} />

Not quite at neat as the SL/WP7 implementation, but it does have a few benefits:

  • You can change the parameter to provide a different results
  • You can perform more complex actions.

How to implement:

  1. Create a blank application, and add a folder called Converters
  2. In Converters folder, create a new Class called TargetNullValueConverter.cs
  3. Then make the class public and implement the IValueConverter interface.
  4. From here we'll add the logic which will provide the basis of the TargetNullValue replacement. In the Convert() method enter the following code:
if (value != null) 
    return value; 
else 
{
    string returnValue = String.Empty; 
    switch ((string)parameter) 
    { 
        case "SelectedImage": 
            returnValue = "/Assets/SplashScreen.png"; 
            break; 
        default: 
            returnValue ="/Assets/SplashScreen.png"; 
            break; 
    } 
    return returnValue;
} 

Firstly the code checks to see if theres a value, if there is, then theres no heavy lifting involved and the converter can just return the original value. However, if the value is null the bulk of the logic kicks in. I find that adding a Switch statement is the easiest way of handling the return value as it means you can write the converter just once and for every circumstance where you need a different value to be returned, you just write a new case.

Demo

To demonstrate this method I'll talk through a quick demo. First, add a ImageItem class and implement INotifyPropertyChanged then add a property of type ImageSource named SelectedImage.

Next we'll go to the MainPage.xaml and create our interface. Add the following declaration:

xmlns:converters="using:TargetNullConverter.Converters"

Set the data context to the ImageItem that you created a minute ago

<Page.DataContext>
    <local:ImageItem />
</Page.DataContext>

Then add the converter to the Page Resources

<Page.Resources>
    <converters:TargetNullValueConverter x:Key="TargetNullValueConverter"/>
</Page.Resources>

Add the following markup to the main grid:

<Grid.RowDefinitions> 
    <RowDefinition Height="Auto" /> 
    <RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" 
                 HorizontalAlignment="Left" 
                 VerticalAlignment="Top" 
                 Margin="40,40,0,0" >
    <Button Content="Customize Picture" 
            Click="GetPicture" />
    <Button Content="Reset resource to null" 
            Click="ResetPicture" />
</StackPanel> 

<Image Grid.Row="1" 
       HorizontalAlignment="Stretch" 
       Height="550" 
       Stretch="Uniform" 
       Source="{Binding SelectedImage, Converter={StaticResource TargetNullValueConverter}, ConverterParameter=SelectedImage}" />

That’s the Markup done, now go to the code behind.
In the constructor, cast the DataContext to a static instance of the ImageItem object

imageItem = this.DataContext as ImageItem;

Then create an asynchronous method called which utilises the FileOpenPicker class to get an image and save it to an object with a property of ImageSource then hook up GetPicture() to call it.

FileOpenPicker openPicker = new FileOpenPicker(); 
openPicker.ViewMode = PickerViewMode.Thumbnail; 
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; 
openPicker.FileTypeFilter.Add(".jpg"); 
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png"); 
StorageFile file = await openPicker.PickSingleFileAsync(); 

if (file != null) 
{ 
    var stream = await file.OpenAsync(FileAccessMode.Read); 
    BitmapImage img = new BitmapImage(); 
    img.SetSource(stream); 
    imageItem.SelectedImage = img; 
}

For ResetPicture() just set the object's SelectedImage property to null

imageItem.SelectedImage = null;

And that's it, all that's left is to build & run the code and you'll be able to see this in action.