Daniel Vaughan

free range code

Using MVVM to create Tabbed Interfaces with Calcium for Xamarin Forms

clock September 17, 2014 16:27 by author Daniel Vaughan

In this second part of my Calcium for Xamarin Forms series you look you see how to extend beyond current Xamarin Forms API capabilities to create a tabbed page or carousel page by binding to a collection of ViewModels. You see how to implement a quasi-data-template selector to materialize viewmodels using MVVM.

Read on...



Introducing Calcium for Xamarin.Forms

clock September 15, 2014 16:45 by author Daniel Vaughan

 

Over the last few weeks I've been busy porting Calcium to Xamarin.Forms. Today I've released the first of 6 articles demonstrating some of its key features. In this series you learn how to do things with Xamarin Forms that you’ll not find anywhere else.

For example, you see how to create a cross-platform Application Bar component using the Xamarin Forms native rendering API with Menu Item support that works on iOS, Android, and Windows Phone; and which offers more features than the built-in Windows Phone Application Bar.

You learn how it is possible to place images anywhere in a shared project as Content resources like in Windows Phone, and consume them in the same way across all three platforms.

You learn how to use T4 templates to enable localizability for your Android app. You also see how to create static bindings to your .resx files using T4 generated designer classes; allowing you to localize your app in the same manner for all three platforms.

You see how to extend beyond current Xamarin Forms API capabilities to implement a quasi-data-template selector to materialize viewmodels in an MVVM compatible way.

You learn how to assemble your Visual Studio projects to decrease friction when you are sharing code using the new Shared Project type.

In addition, in this series of articles you are guided through the basics of developing apps using Xamarin.Forms. You learn how to use the Calcium MVVM framework to build multifaceted cross-platform apps with Xamarin Forms.

Read on...



Encoding Azure Notification Tags

clock June 10, 2014 18:38 by author Daniel Vaughan

I’m in process of enabling some cloud services for Surfy, the web browser app for Windows Phone. Part of this process has involved leveraging Azure Notification hubs. A notification hub allows you to send notifications to a host of different devices, including Windows Phone, Windows, and even Android and iOS devices. Also, notification hubs are rather flexible. They use a tag system, whereby a client app can send a list of strings along during channel registration that allows the server to selectively include or exclude the client when dispatching notifications. You can find out more about the tag system here.

One thing to be mindful of when implementing your notification subsystem around Azure Notification hubs is that tags can only contain alphanumeric and the following non-alphanumeric characters: ‘_’, ‘@’, ‘#’, ‘.’, ‘:’, ‘-’. That’s fine and easy to manage if you are working with a simple set of strings, but an extra encoding step is required if you wish to pass e.g. identifiers that contain illegal characters. My first inclination was to simply encode tags that may contain illegal characters using Base64 encoding. Base64, however, doesn’t quite fit the bill. It uses ‘+’, ‘-’, and ‘=’. So, here’s a quick and simple approach that encodes to Base64 while removing those pesky illegal characters from the mix:

static string EncodeAsNotificationTag(string plainText)
{
    byte[] plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
    string base64Encoded = Convert.ToBase64String(plainTextBytes);
    string result = base64Encoded.Replace('/', '_').Replace('+', '-').Replace('=', ':');
    return result;
}

static string DecodeNotificationTag(string tag)
{
    string base64Encoded = tag.Replace('_', '/').Replace('-', '+').Replace(':', '=');
    byte[] base64EncodedBytes = Convert.FromBase64String(base64Encoded);
    return System.Text.Encoding.UTF8.GetString(base64EncodedBytes, 0, base64EncodedBytes.Length);
}

Good luck with your Azure cloud enabled apps!



Work-Around for a Windows Phone Voice Command Region Localizability Issue

clock October 23, 2013 00:22 by author Daniel Vaughan

With the latest release of Surfy for Windows Phone 8 I’ve been getting more deeply acquainted with the intricacies of Windows Phone Voice Command localizability. In the process I have uncovered some issues that may snag an unsuspecting dev or two.

If you are not familiar with Voice Commands then this post is probably not for you. If you’re still interested, there’s a primer on Voice Commands on MSDN

The Windows Phone OS Voice Command system is rather particular when it comes to selecting a command set. If Windows Phone is unable to find a language code for your command set matching the speech language of the device, your app’s voice commands are ignored. And the OS exhibits some unexpected behaviour when matching a command set with the phone’s speech language. If you’ve tried implementing Voice Commands on Windows Phone for English speakers, you may be unaware that your voice commands are enabled for either US or UK English speakers, but not both!

In this post I’ll quickly detail the problem and provide a work around at the end.

The xml:lang attribute of CommandSet elements in the voice command definition file doesn’t behave as you might expect. The speech recognition system selects command sets corresponding to the speech language setting on the phone, but the VoiceCommandService.InstalledCommandSets API returns the command set corresponding to something else. (which, BTW is not the current thread culture. Perhaps it’s the app’s neutral language, but I haven’t tested that. Yes, I got lazy.)

In my testing, if I used xml:lang=”en” in the definition file, at runtime this is changed to the more specific en-US in the CommandSet object. This is essentially broken for phones with a speech language set to ‘en-GB’

Initially I attempted to work around this by explicitly using two CommandSets (both in the same file): one with xml:lang=”en-GB” and the other with xml:lang=”en-US”

The speech language on my phone is set to en-GB. When I call VoiceCommandService.InstalledCommandSets, a single CommandSet is returned with the language en-US.

It’s the wrong one.

The voice command system only recognizes phrases in the en-GB CommandSet, but it’s impossible to update the phrase list of the CommandSet.

The work around is to load a different definition file that matches the language of the speech voice. You may end up duplicating much of the content, but at least you’ll be satisfying users on both sides of the pond.



Replacing get_ and set_ methods in Exported Reflector Code

clock September 10, 2013 17:25 by author Daniel Vaughan

Reflector is a terrific tool, no doubt. If you’ve ever used its export code feature, however, you’ll notice it has a tough time interpreting calls to property accessors. Code is intermingled with get_Foo() and set_Bah(…).

Well, you can quickly replace those method calls with the following set of regular expressions.

Starting from Visual Studio 2012, Visual Studio uses the .NET frameworks regular expression API. So, gone are the days of having to learn VS’s old idiocentric regular expressions syntax.

To replace the set_X(Y) code use the following expression in Visual Studio’s Find and Replace dialog (remember to enable regular expression in the dialog):

set_([a-zA-Z_]+)\((.+)\)

Replace:

$1 = $2

 

To replace the get_X() code use the following expression in Visual Studio’s Find and Replace dialog:

get_([a-zA-Z_]+)\(\)

Replace:

$1

 

To replace the add_X(Y) event handler hookups in Visual Studio's Find and Replace dialog:

add_([a-zA-Z_]+)\((.+)\)

Replace:

$1 += $2

 

Have a great day!



Farlight Brings a Captivating Drawing Experience to Your Device

clock August 22, 2013 13:04 by author Daniel Vaughan

Farlight

Today we at Outcoder are pleased to announce the release of our brand new app: Farlight! Farlight lets you paint onto a moving canvas while creating stunning translucent animated abstract art.

We’ve gone cross-platform and we’ve targeted all the major app platforms! Farlight is available for iPad, iPhone, iPod Touch, Android, Windows Phone 7 & 8, and for Windows 8 on the Windows Store.

We targeted multiple-platforms using the great tools from our friends at Xamarin. We also leveraged the OS Monogame framework, which allowed us to reuse 95% of our code. Thanks go out to the Monogame team, you guys are doing a terrific job.

We’ve had a lot of fun building this app over the summer. We hope you like it. Here’s a video of the app running on an iPad 4 with a Retina display.

 

Download the app for your device:

You can also give us some love by liking Farlight on Facebook.


Intellicam Released to Windows Phone Marketplace

clock May 17, 2013 10:59 by author Daniel Vaughan

Intellicam

Katka has done a short and sweet write-up of our new app, Intellicam, which was just released to the Windows Phone Marketplace.

There's a lot of buzz around Intellicam:

AAWP, Windows Phone News, WMPowerUser, Mobile & AppsMaxiCepWPXBOX, appbb, WPForum, xataka, WPMania, comunica, ...

The app comes in two flavors: a free version and a paid version. The free version leaves a small watermark on the image.

 



Generating Localized Resources in Mono for Android Using T4

clock April 14, 2013 08:17 by author Daniel Vaughan

Introduction

Recently I have been using the Xamarin products: Mono for iOS and Mono for Android, to port some of our Windows Phone apps to iOS and Android. I like the Xamarin products a lot. Being able to contain most of my development activities to the familiar environment of Visual Studio has made getting up to speed easier.

One key facet of the Xamarin products, in particular Mono for Android, is that they do not attempt to overly abstract the APIs of the underlying platform. When you are working with Mono for Android, the class hierarchy, in the most part, mirrors that of the Java Android SDK. This means that you don’t miss out on learning how ‘native’ development is done, and that you aren’t introducing an undue dependency on a third party API.

There isn’t a built-in unified UI framework for Xamarin’s mono products. You still have to define your views separately for each platform. Obviously this adds to development time, yet it makes sense. Each platform has a different look and feel, and users prefer apps that conform to the UI conventions of their particular mobile platform. There are open source projects out there that attempt to bridge the gap. If though, you wish to leverage the UI visual development tools provided by Xcode and Visual Studio, there is no getting away from providing a separate UI implementation for each platform. If you are new to iOS development like I am, then using Xcode’s Interface Builder also allows you to explore and improve your understanding of the UI framework.

Aside from the absence of a unified UI framework, there is also a major difference in the localization model in Mono for Android. Mono for Android uses the same localization model as that of apps built in Java using the Android SDK. This creates an incompatibility with Windows Phone and Mono for iOS projects, which both normally use Resx files for localization.

This article looks at creating a T4 template to generate a Mono for Android localization files from Resx files. You see how to reuse the template with the import directive. You see how to generate a designer class with statically typed properties using T4. Finally the article demonstrates how to dynamically change the UI language at run-time.

Localization Model Differences Between .NET and Mono for Android

Although Mono for Android's localizability model is markedly different to the Resx model, they do have similarities. Android’s string localization model uses XML files, containing key value pairs that declare localized strings in your app. Unlike .NET, however, these files are placed in a Resources directory within your Mono for Android project and compilation to satellite assemblies does not occur.

In Android, you add support for additional languages by creating additional XML files; placing them in folders within the Resources directory that are suffixed with language and region codes. Android chooses the appropriate set of resources depending on the locale that the app is running under. This is much like the .NET hub and spoke localization model, where a default Resx file is complimented by other localized Resx files. If a string cannot be located in a specific language, fall back occurs to the default resource file.

In .NET, Resx files are accompanied by a generated designer class that allows you to reference localized strings using statically typed properties, which gives you compile time assurance that the resource names have been correctly specified in your code. Although Mono for Android also generates a designer class, it surfaces the resources as an integer identifier, which introduces an extra step to retrieving a localized resource. If you link files into your Mono for Android project that make use of the .NET designer class then your project will not compile. The designer class in the .NET project makes use of a ResourceManager object and retrieves localized resources in a manner that does not work in Android. Thus, in addition to needing a way to convert each Resx file to an Android localized string file, you need a way to generate a Mono for Android-friendly designer class.

Converting a Resx File to a Mono for Android Localized XML File

Resx files are XML files comprised of, among other things, data elements, which specify the name of the resource and its localized value (see Listing 1).

Listing 1. Resx File (Excerpt)

<?xml version="1.0" encoding="utf-8"?>
<root>
  ...
  <data name="Greeting" xml:space="preserve">
    <value>Hello</value>
  </data>
</root>

The downloadable sample code includes a T4 template named ResxToAndroidXml.txt (see Listing 2). The file contains a single method named Process that accepts a path to a Resx file and converts the Resx to an Android compatible localized resource file. It does this by loading the Resx file into an XDocument object. Each data node within the Resx is written as a string element in the resulting Android resource file.

Listing 2. ResxToAndroidXml.txt

<#@ output extension=".xml" #>
<#@ template language="C#" hostSpecific="true" #>
<#@ assembly name="System.Core" #>
...
<#@ import namespace="System.Globalization" #><#+

public void Process(string resxRelativePath)
{
    WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
    WriteLine("<resources>");

    XDocument document;
    try
    {
        document = XDocument.Load(resxRelativePath);
    }
    catch (FileNotFoundException)
    {
        WriteLine("<!-- File not found: " + resxRelativePath + " -->");
        WriteLine("</resources>");
        return;
    }

    IEnumerable<XElement> dataElements = document.XPathSelectElements("//root/data");

    foreach (XElement element in dataElements)
    {
        string elementName = element.Attribute("name").Value;
        string elementValue;

        XElement valueElement = element.Element("value");

        if (valueElement != null)
        {
            elementValue = valueElement.Value;
        }
        else
        {
            continue;
        }

        string cleanedValue = elementValue.Replace("'", "\\'");

        WriteLine(string.Format("    <string name=\"{0}\">{1}</string>", elementName, cleanedValue));
    }

    WriteLine("</resources>");    
}
#>

Android requires that localized files be placed in directories named according to the culture and region codes (see Figure 1). The default string resources are placed in a Values directory. Localized resources are placed in directories suffixed with the culture and optionally a region code.

Figure 1. The Sample Android Project Structure

To create a T4 template in your Mono for Android project, add a new text file to the project using the Add New Item dialog, and then rename the file, giving it a .tt file extension.

A String.tt template, which references the ResxToAndroidXml.txt include, is placed in each Values directory. Each specifies a different Resx file in the .NET project, as demonstrated in Listing 3.

Listing 3. Strings.tt

<#@ include file="..\..\..\..\ResxToAndroidXml.txt" #>
<#@ output extension=".xml" #>
<#@ template language="C#" hostSpecific="true" #>
<#
	Process(Path.GetDirectoryName(Host.TemplateFile) 
             + "../../../../AndroidResxT4/Resources/AppResources.resx");
#>

Resulting String.xml files must have their Build Action set to AndroidResource (see Listing 4). You can see that the name attribute of the data element in the Resx file maps to the name attribute of the string element in the Android resource, and that the value element in the Resx file maps to the content of the string element in the Android resource.

Listing 4. Strings.xml

<?xml version="1.0" encoding="utf-8" ?>
<resources>
    <string name="Greeting">Hello</string>
</resources>

Generating Statically Typed Properties for Resource Values

The generated Mono for Android localized string files can be consumed in Mono for Android layout files or in code. Recall, however, that the generated Resx designer class in the .NET project cannot be reused in your Android project. What you need is an independent designer class just for the Mono for Android project that contains the same properties as the .NET Resx designer class. For this we turn to T4 once again.

The ResxToAndroidAccessorClass.txt file in the downloadable sample is a T4 template with a single method named Process. Process accepts the path to your Resx file and the namespace you wish the resulting designer class to reside in (see Listing 5). The method attempts to load the Resx file into an XDocument object and then generates a property element for each data element in the Resx file. The class is placed into the specified namespace. This allows you to align the code with that of your .NET project.

Listing 5. ResxToAndroidAccessorClass.txt Process Method

<#@ output extension=".cs" #>
<#@ template language="C#" hostSpecific="true" #>
<#@ assembly name="System.Core" #>
...
<#@ import namespace="System.Globalization" #><#+

public void Process(string resxRelativePath, string namespaceName)
{
    WriteLine("using Android.App;");
    WriteLine("namespace " + namespaceName);
    WriteLine("{");
    WriteLine("    public class AppResources {");
    //throw new Exception(Directory.GetCurrentDirectory());
    XDocument document;
    try
    {
        document = XDocument.Load(resxRelativePath);
    }
    catch (FileNotFoundException)
    {
        WriteLine("<!-- File not found: " + resxRelativePath + " -->");
        WriteLine("}}");
        return;
    }

    IEnumerable<XElement> dataElements = document.XPathSelectElements("//root/data");

    foreach (XElement element in dataElements)
    {
        string elementName = element.Attribute("name").Value;
        string elementValue;

        XElement valueElement = element.Element("value");

        if (valueElement != null)
        {
            elementValue = valueElement.Value;
        }
        else
        {
            continue;
        }

        string cleanedValue = elementValue.Replace("'", "\\'");

        WriteLine(string.Format("public static string {0} {{ get {{ return Application.Context.GetString(Resource.String.{0}); }}}}", elementName));
    }

    WriteLine("}}");
}
#>

To leverage the ResxToAndroidAccessorClass.txt file, create a T4 file named AppResources.tt in your Mono for Android project. Use the include directive to import the template and call the Process method with the path of the Resx file and the desired namespace (see Listing 6).

Listing 6. AppResources.tt

 <#@ include file="..\..\ResxToAndroidAccessorClass.txt" #>
<#@ output extension=".cs" #>
<#@ template language="C#" hostSpecific="true" #>
<#
	Process(Path.GetDirectoryName(Host.TemplateFile) 
                  + "../../AndroidResxT4/Resources/AppResources.resx", "AndroidResxT4");
#>
 

The template produces a class with properties for all of the localized string in your default resource file (see Listing 7)

Listing 7. AppResources.cs in Mono for Android Project

using Android.App;
namespace AndroidResxT4
{
	public class AppResources {
		public static string Greeting { get { return Application.Context.GetString(Resource.String.Greeting); }}
}}

The AppResources class in your Mono for Android project should mirror your designer class in your .NET project, allowing you to seamlessly link to classes in your .NET project without breaking compilation.

Sample Project Overview

In addition to converting Resx to Android resources and generating a resource designer class, the downloadable sample code demonstrates how to change the UI language of your Mono for Android app at runtime.

The MainActivity class contains a SetLocale method that creates a new Locale object and updated the app’s configuration (see Listing 8). The AttachView and DetachView methods subscribe and unsubscribe to the button’s Click event.

Listing 8. SetLocale Method

void SetLocale(string languageCode)
{
    Resources resources = Resources;
    Configuration configuration = resources.Configuration;
    configuration.Locale = new Java.Util.Locale(languageCode);
    DisplayMetrics displayMetrics = resources.DisplayMetrics;
    resources.UpdateConfiguration(configuration, displayMetrics);

    DetachView();

    SetContentView(Resource.Layout.Main);

    AttachView();
}

Updating the configuration with a French Locale, specified using the ‘fr’ language code, causes the text of a TextView to change from Hello to Bonjour, as shown in Figure 2.

Figure 2. Tapping the Change Locale Button Switches the Language

The AppResources class can be used as it would in a .NET app. Notice that tapping the button writes the localized Greeting message to the console (see Listing 9).

Listing 9. Button.Click Handler

void HandleButtonClick(object sender, EventArgs e)
{
    SetLocale(!localeToggled ? "fr" : "en");
    localeToggled = !localeToggled;

    Console.WriteLine(AppResources.Greeting);
}

Summary

This article looked at creating a T4 template to generate a Mono for Android localization file. You saw how to reuse T4 templates using the import directive. You saw how to generate a designer class with statically typed properties using T4. Finally the article demonstrated how to dynamically change the UI language of an Android app at run-time.

If you apply the principles of SoC and avoid mixing platform specific API calls in your app logic, you can maximize code reuse across platforms. I have almost completed porting the entirety of the Calcium SDK base library to Mono for Android and Mono for iOS. Calcium includes numerous features that make building multifaceted maintainable apps easier, including an IoC and DI system and a user preference API. Anyway, more on that later.

Sample: AndroidResxT4_01.zip (52.71 kb)



Resolving the Issue: Windows Phone Emulator wasn't able to connect to the Windows Phone operating system

clock October 31, 2012 05:40 by author Daniel Vaughan

The Windows Phone 8.0 SDK is out, and while most sink their teeth into its cavalcade of new features, a few may encounter a small road bump when moving to the RTW version; as I did.

After moving from a pre-release version of the Windows Phone 8 SDK to the RTW, I found that I was unable to launch the Windows Phone emulator because of a networking issue. The emulator would pop up the following error message at the beginning of a debugging session:

The Windows Phone Emulator wasn't able to connect to the Windows Phone operating system: The emulator couldn't determine the host IP address, which is used to communicate with the guest virtual machine. Some functionality may be disabled.

This turned out to be a hair pulling exercise. The cause was related to the Hyper-v virtual switch configuration.

I resolved the issue by performing the following steps:

  1. Uninstall the Windows Phone 8.0 SDK.
  2. Uninstall and reinstall the virtual switches using:
     C:> netcfg –u vms_pp
     C:> netcfg –c p –i vms_pp 
  3. Reboot 
  4. Reinstall the SDK. 

 If you encounter the same issue, here's hoping this post sorts you out.

 



Knockout Style Observables in XAML

clock July 15, 2012 11:22 by author Daniel Vaughan

This week there was a short discussion on the WPF Disciples about Knockout observables and the implications of field level and owner level data bindings. The discussion can be found in the guts of this post.

I wanted to explore the topic further, and I decided to take a stab at implementing something analogous to Knockout Observables and Computed Observables in WPF.

In this article we look at implementing field level change notification in WPF, and how a Lambda Expression can be used to specify a composite property that raises change notifications automatically whenever an associated property changes.

To get started, let’s first take a look at a class that illustrates how composite binding are ordinarily done in a viewmodel designed for XAML (see Listing 1). It’s a simple viewmodel that contains three properties. Two properties have backing fields, while the third (FullName) is a composite property; combining the FirstName and LastName properties. When either of the non-composite properties change, change notification has to occur for the composite as well as non-composite properties.

The downside of this approach is that as the complexity of the viewmodel increases and dependencies creep in, you end up having to raise PropertyChanged events for multiple dependent properties. While this example may seem dead simple (it is), over time potential faults may creep in because of this kind of interdependence.

Listing 1. MainWindowViewModelTraditional Class

class MainWindowViewModelTraditional : INotifyPropertyChanged
{
    string firstName;
        
    public string FirstName
    {
        get
        {
            return firstName;
        }
        set
        {
            if (firstName != value)
            {
                firstName = value;
                OnPropertyChanged("FirstName");
                OnPropertyChanged("FullName");
            }
        }
    }

    string lastName;

    public string LastName
    {
        get
        {
            return lastName;
        }
        set
        {
            if (lastName != value)
            {
                lastName = value;
                OnPropertyChanged("LastName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return firstName + " " + lastName;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Taking the Knockout JS Approach

I’ve been using Knockout quite a bit lately and I like the flexibility and versatility that the binding expression interpreter offers. Knockout allows you to combine observable values in a way that allows you to forego the kind of artificial dependence seen earlier. For example, on a web page you can produce the same string as the FullName property seen in the last example using something like the following:

<span data-bind="text: firstName() + ' ' + lastName()"></span>

You can also achieve the same result using computed values in your viewmodel if you so desire.

In this article I’ve set out to see whether I could come up with something that emulates Knockout's field level notifications in observables and computed observables. I’m quite happy with the result and I believe it has potential. Stay tuned, because at the end of this article you will see how to create a computed property in C# like the following, which raises change notifications automatically:

readonly ComputedValue<string> fullName;

public ComputedValue<string> FullName
{
    get
    {
        return fullName;
    }
}

public MainWindowViewModel()
{
    fullName = new ComputedValue<string>(() => FirstName.Value + " " + ToUpper(LastName.Value));
}

Bridging the HTML-XAML Ravine

In WPF, when using the INotifyPropertyChanged approach to data binding, change notification occurs at the owner object level. The owner is the source property in a data binding, which is ordinarily the DataContext of your control. If you’re using the MVVM pattern this is likely your viewmodel or a nested property. It is the owner object of the property that has the responsibility of raising a PropertyChanged event whenever the property changes.

Conversely, field level notification is where the source of the notification is the field itself (or in XAML, a property). The main advantage of field level notification is that your viewmodel does not need to contain any plumbing code for change notification. Field level notification isn’t achievable in XAML without defining an event for each property in your viewmodel. (Thanks to Bill Kemph for reminding me of field level notifications using dedicated events). This approach is usually avoided because it adds an undue amount of plumbing code to your viewmodel. A wrapper layer is presented in this article, which takes care of raising property changed events for you.

Two classes exist in the downloadable code that emulate the behaviour of Knockout’s observable and computed observable types: ObservableValue and ComputedValue. Both implement INotifyPropertyChanged and automatically raise the PropertyChanged event when an associated value has changed.

The ObservableValue implementation is rudimentary. Things get more interesting when we look at the ComputedValue implementation that allows you to specify a LINQ expression, which is parsed by the ComputedValue object to locate objects that implement INotifyPropertyChanged. When any such object changes, the computed value is recalculated. This allows you to create arbitrary composite properties in your viewmodel that respond to change notifications of any other associated object.

Understanding the ObservableValue Class

An ObservableValue property is defined much like a property using the traditional approach to INPC. The difference is that an ObservableValue instance wraps the value, as shown in the following excerpt:

class MainWindowViewModel
{
    readonly ObservableValue<string> firstName = new ObservableValue<string>("Alan");

    public ObservableValue<string> FirstName
    {
        get
        {
            return firstName;
        }
    }
…
}

To set the value, the ObservableValue.Value property is used. When the setter is used the PropertyChanged event is raised (see Listing 2).

Listing 2. ObservableValue Class

public class ObservableValue<T> : INotifyPropertyChanged
{
    T valueField;

    public T Value
    {
        get
        {
            return valueField;
        }
        set
        {
            if (!EqualityComparer<T>.Default.Equals(valueField, value))
            {
                valueField = value;
                OnPropertyChanged("Value");
            }
        }
    }

    public ObservableValue(T value = default(T))
    {
        Value = value;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Creating Composite Properties with the ComputedValue Class

Unlike ObservableValue, ComputedValue accepts a Lambda Expression that, when compiled, returns a value for the property. Listing 3 shows how the ComputedValue's constructor uses a specified Lamdba Expression.

Listing 3. ComputedValue Class (Excerpt)

public class ComputedValue<T> : INotifyPropertyChanged, IDisposable
{
…
    readonly Func<T> valueFunc;

    public T Value
    {
        get
        {
            T result = valueFunc();
            return result;
        }
    }

    public ComputedValue(Expression<Func<T>> expression)
    {
        if (expression == null)
        {
            throw new ArgumentNullException("expression");
        }

        Expression body = expression.Body;

        ProcessDependents(body);

        valueFunc = expression.Compile();
    }
…
}

When an instance of ComputedValue is created, the specified expression is parsed recursively. Nested MemberExpressions that refer to objects implementing INotifyPropertyChanged are identified (see Listing 4).

Listing 4. ProcessDependents (Excerpt)

void ProcessDependents(Expression expression)
{
    switch (expression.NodeType)
    {
        case ExpressionType.MemberAccess:
            ProcessMemberAccessExpression((MemberExpression)expression);
            break;
        case ExpressionType.Call:
            ProcessMethodCallExpression((MethodCallExpression)expression);
            break;
...
        default:
            return;
    }
}

When a member expression is discovered, its owner is resolved using the ComputedValue.GetValue method. The class subscribes to the PropertyChanged event of the owner object. A PropertyChangedEventHandler is created and placed in a collection along with a WeakReference to the owner object (see Listing 5). When a change notification is received, the ComputedValue object raises its own PropertyChanged event.

Listing 5. ProcessMemberAccessExpression Method

void ProcessMemberAccessExpression(MemberExpression expression)
{
    Expression ownerExpression = expression.Expression;
    Type ownerExpressionType = ownerExpression.Type;
                                            
    if (typeof(INotifyPropertyChanged).IsAssignableFrom(ownerExpressionType))
    {
        try
        {
            string memberName = expression.Member.Name;
            PropertyChangedEventHandler handler = delegate(object sender, PropertyChangedEventArgs args)
                {
                    if (args.PropertyName == memberName)
                    {
                        OnValueChanged();
                    }
                };

            var owner = (INotifyPropertyChanged)GetValue(ownerExpression);
            owner.PropertyChanged += handler;

            handlers[handler] = new WeakReference(owner);
        }
        catch (Exception ex)
        {
            Console.WriteLine("ComputedValue failed to resolve INotifyPropertyChanged value for property {0} {1}", 
                                expression.Member, ex);
        }
    }
}

Retrieving the property value from the Lambda expression is done via expression compilation (see Listing 6). However, the expression is not able to be compiled directly as it is just a fragment. A Lambda expression is constructed by converting the specified expression into a UnaryExpression. When compiled, the resulting func is called and the result returned. In most cases the result is your viewmodel. Though, it does not have to be.

Listing 6. GetValue Method

object GetValue(Expression expression)
{
    UnaryExpression unaryExpression = Expression.Convert(expression, typeof(object));
    Expression<Func<object>> getterLambda = Expression.Lambda<Func<object>>(unaryExpression);
    Func<object> getter = getterLambda.Compile();

    return getter();
}

In .NET the target of an event may be ineligible for garbage collection while the event source remains alive. Therefore if we do not unsubscribe from owner objects’ PropertyChanged events, a memory leak may ensue. The ComputedValue class implements IDisposable and when disposed the ComputedValue instance unsubscribes from all change events.

The ComputedValue IDisposable implementation loops over the items in the handlers dictionary (see Listing 7). If KeyValuePair.Value property holds a WeakReference to the owner of the property, where the owner has not been disposed, the PropertyChanged event is unsubscribed using the handler stored as the KeyValuePair.Key property.

Listing 7. ComputedValue IDisposable Implementation

bool disposed;

protected virtual void Dispose(bool disposing)
{
    if (!disposed)
    {
        if (disposing)
        {
            foreach (KeyValuePair<PropertyChangedEventHandler, WeakReference> pair in handlers)
            {
                INotifyPropertyChanged target = pair.Value.Target as INotifyPropertyChanged;
                if (target != null)
                {
                    target.PropertyChanged -= pair.Key;
                }
            }

            handlers.Clear();
        }

        disposed = true;
    }
}

public void Dispose()
{
    Dispose(true);
}

The downloadable code contains a simple single window application that displays two TextBox controls. Each TextBox is bound to a viewmodel property of type ObservableValue. There is a TextBlock that is bound to a ComputedValue property, which combines the result of the two ObservableValue properties (see Figure 1). When the text in either of the TextBoxes is changed, the TextBlock containing the full name is updated.

Note how the LastName property is converted to upper case. This is performed despite the fact that the call is embedded within the Lambda expression of the ComputedValue.

Figure 1.Sample App.

Just to prove no funny business is taking place in the Window XAML, Listing 8 shows how the text properties are bound to the Value property of the ObservableValue properties and the ComputedValue property.

Listing 8. MainWindows.xaml (Excerpt)

<StackPanel Orientation="Horizontal" Margin="40">
    <StackPanel>
        <Label>First Name</Label>
        <TextBox Text="{Binding Path=FirstName.Value, UpdateSourceTrigger=PropertyChanged}" />
        <Label>Last Name</Label>
        <TextBox Text="{Binding Path=LastName.Value, UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>
    <StackPanel Margin="20,0">
        <Label>Full Name</Label>
        <TextBlock Text="{Binding Path=FullName.Value}" 
                    Style="{StaticResource FullNameStyle}" />
                
        <TextBlock>fullName = new ComputedValue&lt;string&gt;(<LineBreak />
            () => FirstName.Value + " " + ToUpper(LastName.Value));</TextBlock>
    </StackPanel>
</StackPanel>

The MainWindowViewModel code is shown in its entirety in Listing 9. The FirstName and LastName properties are combined in the ComputedValue, along with an arbitrary call to a ToUpper method.

Listing 9. MainWindowViewModel Class

class MainWindowViewModel
{
    readonly ObservableValue<string> firstName = new ObservableValue<string>("Alan");

    public ObservableValue<string> FirstName
    {
        get
        {
            return firstName;
        }
    }

    readonly ObservableValue<string> lastName = new ObservableValue<string>("Turing");

    public ObservableValue<string> LastName
    {
        get
        {
            return lastName;
        }
    }

    readonly ComputedValue<string> fullName;

    public ComputedValue<string> FullName
    {
        get
        {
            return fullName;
        }
    }

    public MainWindowViewModel()
    {
        fullName = new ComputedValue<string>(() => FirstName.Value + " " + ToUpper(LastName.Value));
    }

    string ToUpper(string s)
    {
        return s.ToUpper();
    }
}

Knockout JS has some elegant features that leverage the versatility of JavaScript and help to bridge the gap between XAML and HTML. In this article we looked at implementing field level change notification in WPF, and how a Lambda Expression can be used to specify a composite property that raises change notifications automatically whenever an associated property changes.

Vaughan.ObservablePrototype_2012_07_15.rar (250.68 kb)

Follow me on twitter



Order the Book

Ready to take your Windows Phone development skills to the next level? My book is the first comprehensive, start-to-finish developer's guide to Microsoft's Windows Phone 8. In it I teach through complete sample apps that illuminate each key concept with fully explained code and real-world context. Windows Phone 8 Unleashed

Windows Phone Experts Windows Phone Experts
LinkedIn Group

 

Bio

Daniel VaughanDaniel Vaughan is co-founder and president of Outcoder, a Swiss software and consulting company dedicated to creating best-of-breed user experiences and leading-edge back-end solutions, using the Microsoft stack of technologiesin particular WPF, WinRT, and Windows Phone. 

Daniel is a four-time Microsoft MVP for Client Application Development, with experience across a wide range of industries including finance, e-commerce, and digital media. 
Daniel is the author of Windows Phone 7.5 Unleashed and Windows Phone 8 Unleashed, published by SAMS.

Daniel is a Silverlight and WPF Insider, a member of the WPF Disciples, and a member of the Microsoft Developer Guidance Advisory Council.
Daniel also sits on the advisory board of PebbleAge, a Swiss Financial Software company.

While originally from Australia and the UK, Daniel is currently based in Zurich Switzerland. 

Daniel is the developer behind several acclaimed Windows Phone apps including Intellicam and Splashbox; and is the creator of a number of popular open-source projects including the Calcium and Clog.

Daniel also manages the Windows Phone Experts group on LinkedIn; a group that has over 3000 independent developers, Microsoft employees, and Windows Phone enthusiasts.


E-mail Send mail

 

Microsoft MVP logo Disciple
WPF and Silverlight Insiders
 

 

 

Sign in