Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Compiled DataBinding in Windows Universal Applications (UAP)

This question on stackoverflow which references the Windows 10 jumpstart videos (http://www.microsoftvirtualacademy.com/training-courses/a-developers-guide-to-windows-10-preview?prid=ch9courselink) raises the topic of compiled data bindings. Currently there is no documentation about this feature and I doubt that we’ll see much out of Microsoft prior to Build. However, the x:Bind syntax is available in the insiders preview of the Windows 10 SDK so I figured I’d explore it a little.

Let’s start with a simple expression:

<TextBlock Text="{x:Bind}" />

When you add this to a page and run it, you’ll see the Type name of the page displayed in the TextBlock (eg CompiledDataBindingSample.MainPage). In order to examine this further let’s create a simple custom control with a dependency property and corresponding change handler:

public class CustomControl : Control
{
    Windows.UI.Xaml.Markup.IComponentConnector x;

    public string Test
    {
        get { return (string)GetValue(TestProperty); }
        set { SetValue(TestProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Test.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TestProperty =
        DependencyProperty.Register("Test", typeof(string), typeof(CustomControl), new PropertyMetadata(null, TestChanged));

    private static void TestChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var newData = (d as CustomControl).Test;
        Debug.WriteLine(newData.GetType().Name);
    }
}

Now let’s add an instance of this control onto the page and data bind to the Test property:

<local:CustomControl Test="{x:Bind}" />

When this is run we can set a breakpoint on the Debug.WriteLine and we can examine the newData object. What’s interesting is that the newData object is the instance of the page that is hosting the control. In other words, the value being passed into the binding expression is the page itself (in this case an instance of MainPage) – this explains why in the TextBlock showed the type name, as this is the default ToString() value. This is interesting in itself as it means that the context for data binding with x:Bind is the page itself, in contrast to the default DataContext of null when using Binding.

The other thing that’s worth looking at is the Call Stack window. The first two frames make sense, being the set and change handler for the dependency property but then it gets interesting as it references a class called MainPage_obj1_Bindings with methods such as SetValue_obj3_Test, Update_, InitializeCore, Initialize etc.

image

At this point I think it’s time to go take a look at what’s been generated when the application was compiled. In this case we’ll use ILSpy to get a list of the classes that make up the application. As you can see from this screenshot MainPage has a couple of nested types, MainPage.IMainPage_Bindings and MainPAge.MainPage_obj1_Bindings, along with a field/property combination that exposes an instance of MainPage.IMainPage_Bindings. There is also an additional method, Connect, which has been injected into the MainPage during compilation.

image

A further examination of the base types collection shows that in addition to inheriting from Page, MainPage implements Windows.UI.Xaml.Markup.IComponentConnector, which no surprises defines a method, Connect(int, object). So, what does this method do? Using ILSpy to inspect the contents on the Connect method we can see that it generates an instance of the MainPage_obj1_Bindings class and associates it with the elements on the page (in this case the TextBlock and the CustomControl). Clearly this method is going to be invoked during the initialization phase of a page.

Now, let’s turn our attention to the MainPage_obj1_Bindings class. It would appear that this class has instance variables for each of the elements that has an x:Bind expression. In this case it has variables obj2 (TextBlock) and obj3 (CustomControl). It also has some generated methods such as SetValue_obj2_Text which explicitly sets the Text value on the TextBlock. This makes me think back to a time before data binding where properties had to be explicitly set in code. Whilst data binding has been an effective way for developers to declaratively wire up properties to underlying data, it did add a significant overhead and subsequent performance hit – for large data sets this can be quite significant and hard to work around. By the looks of these generated methods, it would appear that by converting the data binding expression into compiled code, some of the performance overhead of data binding can be overcome.

Ok, so now that we’ve taken a bit of a look at some of the aspects of compiled data binding, let’s go back to XAML and take a look at extending the binding expression to include a path. In most cases we’ll want to bind attributes on the visual elements to properties on a view model. The question is how to do this using x:Bind. Let’s see what happens when we add ViewModel to the binding expression:

<TextBlock Text="{x:Bind ViewModel}" />

Normally, if you add a path to a binding expression that isn’t valid it will compile and run without any issues. In this case, there is no ViewModel property on the MainPage, so when the application is compiled the following build error is generated:

Invalid binding expression 'MyProperty' : Unrecognized property 'MyProperty' at offset '0'

Let’s add a ViewModel property to the MainPage:

public MainViewModel ViewModel { get; set; }

public MainPage()
{
    ViewModel = new MainViewModel();
    this.InitializeComponent();

}

The MainViewModel class exposes a property, HelloText, and implements the INotifyPropertyChanged interface. Of course, normally this would be implemented in a base class with an OnPropertyChanged or RaisePropertyChanged helper method.

public class MainViewModel : INotifyPropertyChanged
{
    private string hello = “Hello World”;
    public string HelloText
    {
        get { return hello; }
        set
        {
            hello = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("HelloText"));
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

In order to reference the HelloText property, we’ll extend the binding expression:

<TextBlock Text="{x:Bind ViewModel.HelloText}" />

Running this appears to work with the text “Hello World” appearing in the TextBlock. Let’s try updating the HelloText. A simple Run method will update the HelloText property every second.

public async void Run()
{
    var i = 0;
    while (true)
    {
        await Task.Delay(1000);
        HelloText = "Hello " + i++;
    }
}

Unfortunately this doesn’t seem to do anything, with the TextBlock not updating. This behaviour is consistent of a OneTime data binding. Let’s add Mode=OneWay to the binding expression.

<TextBlock Text="{x:Bind ViewModel.HelloText, Mode=OneWay}" />

Now the TextBlock updates every second as we’d expect. So it appears that unlike a traditional Binding, the x:Bind expression defaults to a OneTime mode, instead of OneWay. ILSpy also indicates that the MainPage_obj_Bindings has a sub-class, MainPage_obj1_Listener, which is designed to hook up to the INotifyPropertyChanged.PropertyChanged event. This again will help ensure updates are passed to the appropriate elements without any need for Reflection based calls.

Pingbacks and trackbacks (2)+

Comments are closed
Getting to know the Identity of your Windows Phone 7 Application

Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Getting to know the Identity of your Windows Phone 7 Application

There are a number of reasons why you might want to know the identity of someone using your application. Most revolve around the need to store and track personalised information and to be able to uniquely identify any individual user. In your Windows Phone 7 application there are actually three different identities that you may be interested in:

User Id

In order to get the most out of their Windows Phone 7 device (including being able to access marketplace in order to download and install applications and games) a user will need to sign in with a Windows Live Id (or an XBox Live gamer tag). From your application you are able to retrieve a unique identifier that can be used to identify this user. If the same user uses the same Windows Live Id to sign into two different Windows Phone 7 devices and runs your application, the application will see the same identifier. If the same user uses two different Windows Live Ids, then your application will see two different identifiers.

Note that I use the word “identifier”, this is intentional as what you get back doesn’t include any profile information (not even their actual live id) about the user. The following code extracts the 32 character anonymous identifier (ANID) from the UserExtendedProperties class.

private const int IdentifierLength = 32;
private const int IdentifierOffset = 2;

public static string UserId()
{
    object anid;
    if (UserExtendedProperties.TryGetValue("ANID", out anid))
    {
        if (anid != null && anid.ToString().Length >= (IdentifierLength + IdentifierOffset))
        {
            return anid.ToString().Substring(IdentifierOffset, IdentifierLength);
        }
    }

    return null;
}

Note: To access properties in the UserExtendedProperties class you need to demand the ID_CAP_IDENTITY_USER capability in the WMAppManifest file for your application.

Device Id

Alternatively, you may want to identify each device that your application is being run on (this will help resolve the situation where a single user signs into two devices with the same Windows Live Id). This is done using the DeviceUniqueId property from the DeviceExtendedProperties class.

public static byte[] DeviceId()
{
    object uniqueId;
    if (DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueId)){
        return (byte[])uniqueId;
    }

    return null;
}

Note: To access the DeviceUniqueId property you need to demand the ID_CAP_IDENTITY_DEVICE capability in the WMAppManifest file for your application.

Application Id

There are certain cases where you will want to be able to uniquely identify the application (for example, if you write a user control, or a reusable library you might want to be able to identify applications where they are being used). The easiest way to uniquely identify the application is via the ProductID attribute in the WMAppManifest.xml file.  eg

<?xml version="1.0" encoding="utf-8"?>
  <Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.0">
    <App xmlns="" ProductID="{df09bbd2-efb5-4135-8a2e-355222ca8b44}" Title="WindowsPhoneApplication4" RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal"  Author="WindowsPhoneApplication4 author" Description="Sample description" Publisher="WindowsPhoneApplication4">

You can easily open this file in Visual Studio by expanding out the Properties node in Solution Explorer and double-clicking the WMAppManifest.xml file. However, simply copying the ProductID value out may result in the wrong value. This attribute can be modified by the marketplace certification process. Once you have started the submission process for your application, if you look at the details of the submission you will see that a new ProductID has been generated. eg

image

Having to manually extract the ProductID this way is somewhat tedious and from a user control/library developer perspective not very reliable (a developer could pass in the same ProductID for all their applications and thus only pay once). An alternative is to access the WMAppManifest.xml file that gets deployed with the application. When you compile your application it generates a .xap file. This is little more than a compressed file (try changing the extension to .zip and extract the contents) which is expanded into a folder on a Windows Phone 7 device when it is installed. To read the contents of the WMAppManifest.xml file all you need to do is open it the same way as you would any other content that has been packaged with your application.

public static Guid ApplicationId() {
                using(var strm = TitleContainer.OpenStream("WMAppManifest.xml"))
                {
                    var xml = XElement.Load(strm);
                    var prodId = (from app in xml.Descendants("App")
                                  select app.Attribute("ProductID").Value).FirstOrDefault();
                    if (string.IsNullOrEmpty(prodId)) return Guid.Empty;
                    return new Guid(prodId);
                }
        }

That was relatively straight forward…. oh, don’t forget to add a reference to the Microsoft.XNA.Framework assembly which includes the TitleContainer class.

 

The following screenshot shows the results for each of these identifiers. Note that because this is from the emulator where there is no signed in user, the User Id is null/empty.

image

Comments (1) -

  • Nick Harris

    1/6/2011 6:56:36 PM |

    Hi Nick,

    Great work on finding how to access the AppId through code this will be really handy.

    Many Thanks,
    Nick

Pingbacks and trackbacks (1)+

Comments are closed