Windows/Phone 8.1–Roaming Settings Values Across Windows/Phones

Windows 8.0/8.1 have the ability to roam an app’s data for a user across their devices in the form of settings values (i.e. simple types stored in dictionaries) and files.

This is written up on MSDN here;

with one of the the key things being that the OS limits the amount of data that it’s prepared to roam for an app (see RoamingStorageQuota) and simply turns off roaming if that limit is exceeded.

The other key things are that the roaming system is a simple “last write wins” type system rather than a complicated sync engine and that the settings are dictionaries of simple types that can be nested (to 32 levels deep) with each setting being a maximum of 8KB and each dictionary being a maximum of 64KB. 

Synchronisation is done in a fairly non-deterministic way but there’s one bunch of settings called “HighPriority” which is sync’d within 1 minute if possible but that’s restricted to 8KB of data.

The “simple types” part of settings feels quite restrictive but you can always serialize an object graph into a string if that helps in getting it into a settings value (subject to the size limits).

I thought I’d experiment with making a simple universal app with one setting value which roamed across Windows/Phone. Here’s the steps I went through;

Step 1 – Make an App

Clearly, I’m going to have to make an app so I made a new, blank universal app project in Visual Studio 2013 Update 2 RC;

image

I’m not going to need much in the way of UI that differs on Windows/Phone so I deleted the MainPage.xaml/.cs from the Windows project and then moved the one from the Windows Phone project into the Shared project such that my UI and the “code behind” is all in the shared project;

image

I’m going to display some image so I reached into PowerPoint, searched for “animals” and found some royalty free images I can use;

image

I saved each of these into a new Images folder within my Shared project naming them Pic0 to Pic4.png.

image

Then I wrote a “ViewModel” which could be used to present these images and handle their selection changing;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Windows.ApplicationModel;

namespace SyncIt
{
  class BindableBase : INotifyPropertyChanged
  {
    protected bool SetProperty<T>(ref T storage, T value,
      [CallerMemberName] String propertyName = null)
    {
      if (object.Equals(storage, value)) return false;

      storage = value;
      this.OnPropertyChanged(propertyName);
      return true;
    }

    protected void OnPropertyChanged(
      [CallerMemberName] string propertyName = null)
    {
      var eventHandler = this.PropertyChanged;
      if (eventHandler != null)
      {
        eventHandler(this, new PropertyChangedEventArgs(propertyName));
      }
    }
    public event PropertyChangedEventHandler PropertyChanged;
  }
  class PictureViewModel : BindableBase
  {
    public string SelectedValue
    {
      get
      {
        return (this._selectedValue);
      }
      set
      {
        base.SetProperty(ref this._selectedValue, value);
      }
    }
    string _selectedValue;

    public IEnumerable<string> Images
    {
      get
      {
        if (this.images == null)
        {
          GetImagesAsync();
        }
        return (images);
      }
    }
    async Task GetImagesAsync()
    {
      // might want to cache this list perhaps.
      var folder = await Package.Current.InstalledLocation.GetFolderAsync("Images");

      var files = await folder.GetFilesAsync();
      this.images = files
        .Where(f => System.IO.Path.GetExtension(f.Path) == @".png") 
        .Select(f => f.Path)
        .ToList();
      
      this.OnPropertyChanged("Images");
    }
    IEnumerable<string> images;
  }
}

and then wrote a little XAML to display that;

<Page x:Class="SyncIt.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:SyncIt"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d"
      Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  <Page.DataContext>
    <local:PictureViewModel />
  </Page.DataContext>

  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition  Height="Auto"/>
    </Grid.RowDefinitions>
    <Image Source="{Binding SelectedValue}"
           Stretch="Uniform" 
           Margin="5,5,5,15"/>
    <ListView Grid.Row="1" ItemsSource="{Binding Images}"
              SelectedValue="{Binding SelectedValue,Mode=TwoWay}"
              Margin="5,0,5,5"
              HorizontalAlignment="Center">
      <ListView.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
      </ListView.ItemsPanel>
      <ListView.ItemTemplate>
        <DataTemplate>
          <Image Width="48"
                 Height="48"
                 Stretch="Uniform"
                 Source="{Binding}" />
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </Grid>
</Page>

and ran it up on Windows/Phone at the same time and that works “fine”;

image

but, clearly, there’s no link between the two applications because that “SelectedValue” isn’t being stored anywhere other than in memory.

It’s not persisted anywhere across invocations of the app and it certainly isn’t shared between Windows & phone.

I need to persist it and in a way that’s shared between the two apps.

As it turns out, the 2 systems produce different values for the file paths that I’m binding to here which will also cause me a minor hiccup in a moment…

Step 2 – Associate the Apps with the Stores & Link Them

In order for the cloud infrastructure to be able to handle roaming settings between the two applications, I think they need to be associated with the Stores. This doesn’t mean that you have to ship the apps, you can always experiment and then delete the applications afterwards.

If I take the Windows Store application and associate it with the Store;

image

and then register an application name for it (not sure where this emulator picture came from below);

image

image

then on the packaging page of the Windows 8.1 manifest I see;

image

if I then repeat the process with the Windows Phone 8.1 application and pick the same mtaultySyncIt application name from the list as I’m running through the dialog and I then look in the Windows Phone 8.1 manifest I see;

image

the two applications have the same “Package family name” at the Store which (I think) links them. I now need to write some code to test that out.

Step 3 – A Common Microsoft Account Across Windows/Phone

If you’re logging in to your Windows 8.1 device and your Windows Phone 8.1 device with the same Microsoft Account then you’re in business from the point of view of synchronising roaming settings/files.

In my case, I’m debugging on my laptop which has an associated Microsoft Account but I’m also debugging on the Phone emulator which means that things won’t work unless I go into the emulator’s settings and tell it to use the same Microsoft Account. If I do that, things seem to work ok but this might be an argument for simply debugging on my Phone as that shares the same Microsoft Account so things would be simpler to set up.

Step 4 – Using Roaming Settings Rather than a Local Value

The first thing I realised while experimenting with this was that I am trying to persist a path to an image as a shared setting. The problem was that the path that I was building up on Windows 8.1 wasn’t a path that Windows Phone 8.1 was happy with so I needed to change my ViewModel such that the paths were going to be consistent (and, as it happens, just shorter and nicer) so I changed my ViewModel so that it returned image paths more of the form Images/pic0.png;

class PictureViewModel : SettingsBindableBase
  {
    public string SelectedValue
    {
      get
      {
        return (base.GetSettingsProperty<string>(
          "UsersImage", SettingsScope.Roaming));
      }
      set
      {
        base.SetSettingsProperty<string>(
          "UsersImage", value, SettingsScope.Roaming);
      }
    }
    public IEnumerable<string> Images
    {
      get
      {
        if (this.images == null)
        {
          GetImagesAsync();
        }
        return (images);
      }
    }
    async Task GetImagesAsync()
    {
      // might want to cache this list perhaps.
      var folder = await Package.Current.InstalledLocation.GetFolderAsync("Images");

      var files = await folder.GetFilesAsync();
      this.images = files
        .Where(f => System.IO.Path.GetExtension(f.Path) == @".png")
        .Select(f => string.Format("Images/{0}", f.Name))
        .ToList();

      this.OnPropertyChanged("Images");
    }
    IEnumerable<string> images;
  }

I also changed the base class of the ViewModel to a new class I experimented with called SettingsBindableBase. I’m not so sure whether I like what I’ve done here but I added a GetSettingsProperty and SetSettingsProperty to that class and you can see them being used from the SelectedValue property above and what that usage is meant to mean is that these values are now stored in RoamingSettings under a key of “UsersImage”.

Those Get/SetSettingProperty methods will also support a “dotted notation” – e.g. “Preferences.Colours.Foreground” as a way of navigating into a particular container of application settings. They also support using Local/Roaming settings for the containers.

The code for that base class is as below;

 class SettingsBindableBase : BindableBase
  {
    public enum SettingsScope
    {
      Local,
      Roaming
    }
    static SettingsBindableBase()
    {
      globalTrackedObjects = new ConcurrentQueue<WeakReference<SettingsBindableBase>>();
      ApplicationData.Current.DataChanged += OnRoamingSettingsChanged;
    }
    static void OnRoamingSettingsChanged(ApplicationData sender, object args)
    {
      List<SettingsBindableBase> liveObjects = new List<SettingsBindableBase>();
      WeakReference<SettingsBindableBase> reference;

      while (globalTrackedObjects.TryDequeue(out reference))
      {
        SettingsBindableBase entry;

        if (reference.TryGetTarget(out entry))
        {
          liveObjects.Add(entry);
        }
      }
      foreach (var entry in liveObjects)
      {
        globalTrackedObjects.Enqueue(new WeakReference<SettingsBindableBase>(entry));
      }
      foreach (var entry in liveObjects)
      {
        entry.NotifyAllRoamedPropertiesChanged();
      }
    }
    static ApplicationDataContainer ContainerFromName(string settingName,
      out string key, SettingsScope scope, bool create = false)
    {
      string[] pieces = settingName.Split('.');
      key = pieces[pieces.Length - 1];

      ApplicationDataContainer container =
        scope == SettingsScope.Local ?
          ApplicationData.Current.LocalSettings : ApplicationData.Current.RoamingSettings;

      for (int i = 0; i < pieces.Length - 1; i++)
      {
        if (container.Containers.ContainsKey(pieces[i]))
        {
          container = container.Containers[pieces[i]];
        }
        else if (create)
        {
          container =
            container.CreateContainer(pieces[i], ApplicationDataCreateDisposition.Always);
        }
        else
        {
          container = null;
          break;
        }
      }
      return (container);
    }
    protected T GetSettingsProperty<T>(
      string settingName,
      SettingsScope scope = SettingsScope.Local,
      [CallerMemberName] string propertyName = null)
    {
      T t = default(T);
      string key;

      ApplicationDataContainer container = ContainerFromName(settingName, out key, scope);

      if (container != null)
      {
        object o;

        if (container.Values.TryGetValue(key, out o))
        {
          // might blow up here...
          t = (T)o;

          if (scope == SettingsScope.Roaming)
          {
            this.TrackRoamedPropertyAccess(propertyName);
          }
        }
      }
      return (t);
    }
    protected void SetSettingsProperty<T>(string settingName, T value,
      SettingsScope scope = SettingsScope.Local,
      [CallerMemberName] string propertyName = null)
    {
      string key;

      ApplicationDataContainer container = 
        ContainerFromName(settingName, out key, scope, true);

      container.Values[key] = value;

      this.OnPropertyChanged(propertyName);
    }
    void TrackRoamedPropertyAccess(string propertyName)
    {
      if (this.syncContext == null)
      {
        this.syncContext = SynchronizationContext.Current;
      }
      if (this.trackedRoamedProperties == null)
      {
        this.TrackRoamedObject();
        this.trackedRoamedProperties = new List<string>();
      }
      if (!this.trackedRoamedProperties.Contains(propertyName))
      {
        this.trackedRoamedProperties.Add(propertyName);
      }
    }
    void TrackRoamedObject()
    {
      globalTrackedObjects.Enqueue(new WeakReference<SettingsBindableBase>(this));
    }
    void NotifyAllRoamedPropertiesChanged()
    {
      this.syncContext.Post(
        _ =>
        {
          if (this.trackedRoamedProperties != null)
          {
            foreach (var property in this.trackedRoamedProperties)
            {
              base.OnPropertyChanged(property);
            }
          }
        }, 
        null);
    }
    static ConcurrentQueue<WeakReference<SettingsBindableBase>> globalTrackedObjects;
    List<string> trackedRoamedProperties;
    SynchronizationContext syncContext;
  }

and I was kind of feeling ok about this class until it came to the point where I wanted to see if I could make sure that whenever the ApplicationData.Current.DataChanged event fired (i.e. when roaming settings have been updated by a synchronisation event) any properties that were “backed” by those settings values correctly reported via INotifyPropertyChanged that their value had changed.

I have something kind of working right now but I’m not sure I feel so good about it just yet.

What the code above is trying to do is to ensure that if an object it has been asked for a value for a property called Foo which is backed by a roaming application setting then whenever all the settings are changed by a sync event then that object will fire a PropertyChanged for that property Foo.

The problem in doing that is that the ApplicationData.Current.DataChanged event is just a global event. There’s no notion (as far as I know) of being aware of what has changed.

So, the code above is trying to do its own lazy book-keeping in the sense that it keeps a weak-reference to any object that has “handed out” a property value backed by a roamed property setting and also a reference to the name of the property that was backed by that setting. Then, whenever the roaming data changes, it attempts to find any of those objects that are still “alive” and asks them to fire property changed notifications for any of those properties.

Because the “DataChanged” event comes in on a background thread and because it’s possible that the static list of weak references that I maintain here could (at least on Windows 8.1) be used by multiple UI threads I get into having to think a little about thread-safety and SynchronizationContexts and it all gets a bit out of hand and that’s why I’m not sure that I’m pleased with where it ended up.

But, for the purposes of seeing if I can synchronize a simple setting value across Windows/Phone 8.1 apps it more than serves its purpose and I can try things out using these classes to debug on my local device (Windows 8.1) and on the emulator (Windows Phone 8.1).

Step 5 – Trying it Out

With all that setup, I can run the 2 apps side-by-side on my PC – one on the emulator, one locally;

image

and then if I change the Windows 8.1 value (on the left) to be the chicken;

image

and then lock/unlock my PC (to kick the sync engine into life) then after a few seconds I see chickens!

image

and if I change the Windows Phone value to be the monkey;

image

then I seem to wait an awfully long time before the Windows 8.1 app displays any change.

I’m not sure how to “kick start” the sync process from the emulator here so I tried debugging on my Phone rather than the emulator and I still didn’t manage to see a situation where a change made on the Phone showed up on Windows 8.1 (but, again, the reverse situation worked fine on the Phone just like it did on the emulator).

I’ll work on this one a little more and will update the post when I figure why changes aren’t seeming to be sync’d in both directions.

HP8540W–Installing Windows 7 from USB Key (USB3?)

I got an HP8540W laptop a couple of months ago and at the time I had a bit of fun and games installing it. The machine has a main drive in it (SSD) and a secondary bay that can take a DVD-drive or another hard-drive and I have another hard-drive in there.

I’m a bit “manual” when it comes to installing operating systems and so when it came around to doing this I thought that there’d be no problem in that I’d just put the OS onto a USB key, boot from that and then install.

this walk-through takes you through using a USB key to install Windows 7

Suffice to say that, at the time, I got so fed up with trying to make this work that I ended up taking out my 2nd hard-drive, dropping in a DVD drive (having made a DVD Smile) and installing from that DVD.

Why? Because I would find that I had no problem whatsoever getting the laptop to boot from the USB key but then whenever I got to the stage of being about to install the OS I would get the dreaded;

“Required CD/DVD drive device driver is missing”.

This is always a bit puzzling and especially when you’re in a situation where you don’t have any kind of CD/DVD drive at all and you’re wondering what Windows might be looking for.

In my case, I suspected that I knew what Windows was looking for – despite the laptop having booted from the USB key the installation process is looking for a driver that lets it talk to the USB key and I’m not sure whether this is because the laptop has USB 3 ports or not.

At the time, I downloaded the driver from HP (it seems to be an NEC USB 3 and that link is to the 64-bit download) and I know that I couldn’t get it to work but, having revisited it, I’m not 100% sure whether that was because;

  1. I couldn’t get the OS install process to then accept that driver off a USB key or maybe an SD card ( I know I tried both ).
  2. I didn’t quite follow the right steps.

I’ve just been around the installation loop again on this machine except this time I was installing a new Windows 7 into a bootable VHD file.

 Hanselman has a good article on this here.

I hit the exact same problem except this time around I know that when I reach the “give me a CD/DVD driver” stage I already have filesystems available from the existing OS and so I can put the driver on one of my existing partitions to feed to the installation process and so I;

  1. Downloaded the NEC 3.0 USB drivers.
  2. Stuck them on my C: drive.
  3. Made a bootable USB key.
  4. Made a blank VHD to install the OS into.
  5. Rebooted and booted off the USB key.
  6. Attached the VHD file so that I could install into it (via SHIFT+F10 and diskpart – see Hanselman).
  7. Got to the point where my laptop said “Required CD/DVD device driver is missing”
  8. Fed it the NEC 3 USB driver off my C: drive which HP unpacks to some Files\x64 folder.
    1. Important point – I had to untick the “hide incompatible drivers” option which then reveals 3 drivers that I installed.
    2. Important point – I had to unplug and replug the USB key at that point.
  9. Installed into the VHD file.
  10. All is good. I think.

So if that helps anyone out there installing to an HP8540W or maybe installing Windows 7 generally with USB 3 ports then that’s great and apologies that it’s not a 100% guaranteed set of instructions because I’d have to flatten my laptop to be 100% sure of what the process might be when starting again from scratch.

If anyone spots the specifics of what’s going on here and wants to add better guidance via comments then feel (as always) very free Smile

Mosaic by Tribune

I was very impressed by the Mosaic application that you can read more about on the Windows Azure blog or by hopping over to the Mosaic site;

image

I’ve only tried the Windows version so far but I’m keen to get the Windows Phone 7 version too and try that out – in functionality, it feels a little like FlipBoard to me but what I liked about this Silverlight application in playing with it were;

  1. the quality of the touch experience on my Windows 7 box
  2. the metro aspects of the UI – there’s a pivot in there that works really nicely
  3. the seamless integration of the WebBrowser control into the application
  4. and also the search experience – I searched for UK RSS feeds and didn’t expect to find them but it all seemed to work quite nicely

Cool application! Give it a whirl if you’ve got a touch monitor and/or a WP7 Smile