27 October 2013

An MVVM friendly tap+send and Bluetooth connection helper for Windows Phone 8

Why?
Early this year I blogged about TtcSocketHelper, an MVVM friendly helper object that allowed you connect two Windows Phone 8 devices to each other using a socket.I made two games with it– Pull the Rope and 2 Phone Pong, head-to-head style games that are played over two phones, exchanging JSON data to keep things in sync. A lot of things happened the last 10 months: super cheap devices entered the market – most notably the Nokia Lumia 520. It is a full fledged Windows Phone 8, but it’s super cheap and as a consequence it does not support NFC (and thus no tap+send). That apparently is of no concern to buyers, as according to AdDuplex stats, it took off like a bat out of hell. In just six months it grabbed what is now almost 33% of the Windows Phone 8 market. In other words, by limiting my app to NFC enabled phones I cut myself off from a significant – and growing – part of the market.

PhonePairConnectionHelper – supporting Bluetooth browsing
So I rewrote TtcSocketHelper into PhonePairConnectionHelper – basically the same class, but it now supports connecting phones using tap+send as well as by using the tried and tested way of Bluetooth pairing. Since October 21st 2 Phone Pong  1.3.0 is in the store, proudly powered by this component, now enabling my game to be played by 50% more people!
In this article I am going to concentrate on connecting via Bluetooth, as connecting via tap+send is already described in my article from January 2013.
The start of the object is simple enough again, and actually looks a lot like the previous incarnation:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using GalaSoft.MvvmLight.Messaging;
using Windows.Foundation;
using Windows.Networking.Proximity;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;

namespace Wp7nl.Devices
{
  public class PhonePairConnectionHelper
  {
    private ConnectMethod connectMode;

    public PhonePairConnectionHelper()
    {
      Messenger.Default.Register<NavigationMessage>(this, ProcessNavigationMessage);
      PeerFinder.TriggeredConnectionStateChanged +=
        PeerFinderTriggeredConnectionStateChanged;
      PeerFinder.ConnectionRequested += PeerFinderConnectionRequested;
    }
  
    private void ProcessNavigationMessage(NavigationMessage message)
    {
      Debug.WriteLine("PhonePairConnectionHelper.ProcessNavigationMessage " + 
                       message.NavigationEvent.Uri);

      if (message.IsStartedByNfcRequest)
      {
        Start();
      }
    }
  }
}
The most notable is now that the setup is being done in the constructor. The class still listens to the NavigationMessage and if so, it still calls the start method (this is for the tap+send route, that still works). The PeerFinder is set up to listen to TriggeredConnecState events (i.e. events that happen after a tap+send) but also -  and this is important – to plain ole Bluetooth requests (ConnectionRequested event). The start method now, is pretty much changed:
public void Start(ConnectMethod connectMethod = ConnectMethod.Tap, 
  string displayAdvertiseName = null)
{
  PeerFinder.Stop();
  connectMode = connectMethod;
  if (!string.IsNullOrEmpty(displayAdvertiseName))
  {
    PeerFinder.DisplayName = displayAdvertiseName;
  }
  PeerFinder.AllowBluetooth = true;
  PeerFinder.Start();

  // Enable browse
  if (connectMode == ConnectMethod.Browse)
  {
    PeerFinder.FindAllPeersAsync().AsTask().
      ContinueWith(p => FirePeersFound(p.Result));
  }
}
The ConnectMethod enumeration, as you can already see from the code, enables you to indicate which method you want to use:
namespace Wp7nl.Devices
{
  public enum ConnectMethod
  {
    Tap,
    Browse
  }
}
The Start method has an optional parameter that gives you the ability to choose a connection method, and if necessary add a display name. The display name only applicable for the Bluetooth method. The interesting thing is – if you don’t provide a name, like I did in the sample, it will just use the phone’s name as you have provided it (by giving it a name via Explorer if you connect if via a USB cable to your computer)  - abbreviated to 15 characters. Why this is only 15 characters – your guess is as good as mine.
If you call this method without any parameters, it uses default values and will try to connect using tap+send, just like before.
Before selecting a method, you might want to check what connection methods the device support by using the two helper properties in the object:
public bool SupportsTap
{
  get
  {
    return (PeerFinder.SupportedDiscoveryTypes &
       PeerDiscoveryTypes.Triggered) == PeerDiscoveryTypes.Triggered;
  }
}

public bool SupportsBrowse
{
  get
  {
    return (PeerFinder.SupportedDiscoveryTypes &
      PeerDiscoveryTypes.Browse) == PeerDiscoveryTypes.Browse;
  }
}
Mind you – the helper is not so intelligent that it refuses to connect in a non-supported mode. And I don’t check for it in the sample app either. That is up to your app. But anyway – back up a little. If you try to connect via Bluetooth, the component tries to find all peers – that is, other phones running the same app, using FindAllPeersAsync, and fires the PeersFound event when it is done:
private void FirePeersFound(IEnumerable<PeerInformation> args)
{
  if (PeersFound != null)
  {
    PeersFound(this, args);
  }
}

public event TypedEventHandler<object, IEnumerable<PeerInformation>> PeersFound;
Your app has to subscribe to this event, and it then gets a list of “PeerInformation” objects. And PeerEvent has a number of properties, but the only one you will need to concern yourself is the “DisplayName” property. You display that in a list, a dropdown or whatever in your app, and after the user has made a selection, you call the Connect method:
public void Connect(PeerInformation peerInformation)
{
  DoConnect(peerInformation);
}

private void DoConnect(PeerInformation peerInformation)
{
  PeerFinder.ConnectAsync(peerInformation).AsTask().ContinueWith(p =>
  {
    socket = p.Result;
    StartListeningForMessages();
    PeerFinder.Stop();
    FireConnectionStatusChanged(TriggeredConnectState.Completed);
  });
}
And boom. You have a connection to the phone you have selected. The only thing that’s now missing is that the phone you have connected to, does not have a connection to you yet. But as you made the connection, the PeerFinder fired the ConnectionRequested event. Remember we set up a listener “PeerFinderConnectionRequested” to that in the constructor? Well guess what, part of the payload of the arguments of that event method gets is a PeerInformation object as well, containing the information to connect back to the phone that just connected to you :-). Which makes connecting back pretty easy:
private void PeerFinderConnectionRequested(object sender, 
                                           ConnectionRequestedEventArgs args)
{
  if (connectMode == ConnectMethod.Browse)
  {
    DoConnect(args.PeerInformation);
  }
}
And done. We know have a two-way socket connection using Bluetooth and we can call the SendMessage method just like before, and listen to result by subscribing to MessageReceived event. The only thing I did break in this helpers’ interface with regard to it predecessor is the ConnectionStatusChanged event type. This used to be

public event TypedEventHandler<object, 
             TriggeredConnectionStateChangedEventArgs>
             ConnectionStatusChanged; 
and now is
public event TypedEventHandler<object, TriggeredConnectState>
             ConnectionStatusChanged;
So if you subscribe to this event, you don’t have to check for args.State, but just for args itself. This was necessary to be able to fire connect events from DoConnect.
The rest of the class is nearly identical to the old TtcSocketHelper, and I won’t repeat myself here.

To use this class

First, decide if you are going to for for the tap+send route or the Bluetooth route. My apps check the SupportsTap and SupportsBrowse properties. If NFC (thus tap+send) is supported, I offer both options and give the users a choice to select a connect method. If is not supported, I offer only Bluetooth.
For the NFC route, the way to go still is:
  • Make sure you app does fire a NavigationMessage as described here
  • Make a new PhonePairConnectionHelper .
  • Subscribe to its ConnectionStatusChanged event
  • Subscribe to its MessageReceived event
  • Call Start
  • Wait until a TriggeredConnectState.Completed comes by
  • Call SendMessage – and see them appear in the method subscribed to MessageReceived on the other phone.
The way to go for Bluetooth is:
  • Make a new PhonePairConnectionHelper .
  • Subscribe to its ConnectionStatusChanged event
  • Subscribe to its MessageReceived event
  • Subscribe to its PeersFoundevent
  • Call Start with ConnectMethod.Browse and a display name
  • Wait until a PeersFound event comes by
  • Select a peer to connect to in your app
  • Call the Connect method with the selected peer
  • Wait until a TriggeredConnectState.Completed comes by
  • Call SendMessage – and see them appear in the method subscribed to MessageReceived on the other phone.

So basically, there isn’t that much difference ;-)

Changes in original sample
The fun thing is, you don’t even have to change that much to the existing demo solution. I added to the viewmodel the following code:

#region Bluetooth stuff

private bool useBlueTooth;
public bool UseBlueTooth
{
  get { return useBlueTooth; }
  set
  {
    if (useBlueTooth != value)
    {
      useBlueTooth = value;
      RaisePropertyChanged(() => UseBlueTooth);
    }
  }
}

private PeerInformation selectedPeer;

public PeerInformation SelectedPeer
{
  get { return selectedPeer; }
  set
  {
    if (selectedPeer != value)
    {
      selectedPeer = value;
      RaisePropertyChanged(() => SelectedPeer);
    }
  }
}

public ObservableCollection<PeerInformation> Peers { get; private set; }

private void PeersFound(object sender, IEnumerable<PeerInformation> args)
{
  Deployment.Current.Dispatcher.BeginInvoke(() =>
  {
    Peers.Clear();
    args.ForEach(Peers.Add);
    if (Peers.Count > 0)
    {
      SelectedPeer = Peers.First();
    }
    else
    {
      ConnectMessages.Add("No contacts found");
    }
  });
}

public ICommand ConnectBluetoothContactCommand
{
  get
  {
    return new RelayCommand(() =>
    {
      connectHelper.Connect(SelectedPeer);
      Peers.Clear();

    });
  }
}

#endregion
Basically:
  • A property to determine whether you are using Bluetooth or not (not = tap+send)
  • A property holding the selected Peer
  • A list of available peers
  • The callback for the helper’s PeersFound event. Not that everything here happens within a Dispatcher. As the PeersFound event comes back from a background thread, it has no access to the UI – but since it updates several bound properties, it needs that access – hence the Dispatcher.
  • and a command to allow the user to select a certain peer. Notice the Peers.Clear after the Peer is selected. That is because I use my HideWhenCollectionEmptyBehavior to display the UI for showing and selecting peers. This behavior is in the sample solution as code as I kind of forgot to add this to the last edition of my wp7nl library on codeplex.*ahem*
Two minor additions to the rest of the viewmodel: in the Init method, where I set up all the connectHelper, it now says:
connectHelper = new PhonePairConnectionHelper();
connectHelper.ConnectionStatusChanged += ConnectionStatusChanged;
connectHelper.MessageReceived += TtsHelperMessageReceived;
connectHelper.PeersFound += PeersFound;  // Added for Bluetooth support
And there’s also a little change in the StartCommand to accommodate the fact that if the user selects Bluetooth, the connectHelper should be called in a slightly different way.
public ICommand StartCommmand
{
  get
  {
    return new RelayCommand(
        () =>
        {
          ConnectMessages.Add("Connect started...");
          CanSend = false;
          CanInitiateConnect = false;
          // Changed for Bluetooth.
          if(UseBlueTooth)
          {
            connectHelper.Start(ConnectMethod.Browse);
          }
          else
          {
            connectHelper.Start();
          }
        });
  }
}
wp_ss_20131027_0001To enable the user to actually select a connection method, the start screen has changed a little and now sports two radio buttons. Bluetooth is selected by default.
<RadioButton Content="tap+send" 
IsChecked="{Binding UseBlueTooth, Converter={StaticResource BooleanInvertConvertor}, Mode=TwoWay}"  
  IsEnabled="{Binding CanInitiateConnect, Mode=OneWay}" />
<RadioButton Content="bluetooth" IsChecked="{Binding UseBlueTooth, Mode=TwoWay}" 
  HorizontalAlignment="Right" Margin="0" 
  IsEnabled="{Binding CanInitiateConnect, Mode=OneWay}" />
which is not quite rocket science, and some more code to give a user a simple UI to view and select found peers:
<Grid x:Name="bluetoothconnectgrid" VerticalAlignment="Bottom">
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <i:Interaction.Behaviors>
    <behaviors:HideWhenCollectionEmptyBehavior Collection="{Binding Peers}"/>
  </i:Interaction.Behaviors>
  <toolkit:ListPicker x:Name="OpponentsListPicker" Margin="12,0" VerticalAlignment="Top" 
      ExpansionMode="FullScreenOnly" 
      ItemsSource="{Binding Peers}" SelectedItem="{Binding SelectedPeer, Mode=TwoWay}" />
  <Button Content="select contact" Height="72" Grid.Row="1" 
      Command="{Binding ConnectBluetoothContactCommand, Mode=OneWay}"/>
</Grid>
wp_ss_20131027_0002Also not very complicated – a listpicker displays the peers and selects a peer, and the button fires the command to do the actual connecting. I rather like the use of HideWhenCollectionEmptyBehavior here – this automatically shows this piece of UI as there are peers in the list, and hides it when they are not. It’s rather elegant, if I may say so myself. On the picture right you can see it shows the name of my 920 – abbreviated to 15 characters.
After the connection has been made – either by Bluetooth or by tap+send – you can use this app to chat just like the previous version.

Important things to know
  • If you are a developer who wants protect your customers from disappointments, you have checked the “NFC” as requirement in the WMAppManifest.xml when you built an app on top of my previous TtcSocketHelper. Remove that checkmark now. Or else your app still won’t be available for phones like the 520 that don’t have NFC. And that quite defies the point of this whole new class.
  • I have found out Bluetooth browsing on Windows Phone 8 has some peculiar things to take into account
    • You still have to be quite close together – somewhere within the meter range – to find peers. Once the connection is made, you can move further apart
    • The first phone to start searching for a peer, usually finds nothing. The second one finds one opponent, the third one two. The search process usually doesn’t last very long – in most cases just a few seconds – before the PeerFinder either gives up or comes back with a peer. It’s advisable not to call Connect automatically if you find only one peer – that might not be the one the user was looking for. Always keep the user in control.
  • If you connect via tap+send, you will only need to start the app on one of the phones and press the connect button – the other phone will automatically fire up the app (or even download it if it is not there) when the devices are tapped together.
  • For the Bluetooth route, the app needs to be started on both phones and on both phones you will need to press the connect button.

Conclusion

The app market is always in flux, that’s true for all platforms but that sure goes for Windows Phone. It’s important to stay in touch with those developments. There’s a lot of growth in the Windows Phone market – especially on the low end of the phones. Walking the extra mile for those groups is important – cater for as much users as you can. I hope I helped you a little with that, both by general example and actual code. Demo solution, as always, can be downloaded here.

17 October 2013

Introducing Win8nl for Windows 8.1–kissing WinRtBehaviors goodbye

Updated November 11, 2013
It was at my very first MVP Summit in February 2012 that I learned that Windows 8 XAML was not to have any behaviors. I remember distinctly being very angry first, telling the presenter I would be “dead in the water”, then upon reflection, calming down, and deciding to find out if I could plug the hole myself. And so I did, with the help of (in order of appearance) Geert van Horrik, Filip Skakun, and András Velvárt.

WinRtBehaviors saw the light in Spring 2012, shortly after said Summit. With 4,634 downloads, it being used in well-known top apps like Shazam, and being specifically mentioned at the 2013 edition of TechDays in both Belgium and The Netherlands (much to the surprise of colleagues and friends visiting there, not to mention myself) – I think I quite made my mark in the Windows XAML stack.

I also learned the downsides of having such a successful library, i.e. a lot of support requests. But today Visual Studio 2013 was released, and along with it the final version of the Behaviors SDK, so I released a version of Win8nl – the library with ported Windows Phone code that I built on top of WinRtBehaviors – and I made a yet-to-release version of Catch’em Birds for Windows on it, that totally works (since very recently) on that new version of Win8nl. So the days of the old WinRtBehaviors warhorse are over.

Win8nl 1.0.9 still supports Windows 8.0 and still downloads WinRtBehaviors, but if you target your app for Windows 8.1 you will see that there’s not longer a reference made to it when you download the Nuget Package.

Part of the library are the classes Behavior and Behavior<T>. These have the following implementations:
using Windows.UI.Xaml;
using Microsoft.Xaml.Interactivity;

namespace Win8nl.Behaviors
{
  /// <summary>
  /// A base class for behaviors, can be used in native environments too
  /// </summary>
  /// <typeparam name="T"></typeparam>
  public abstract class Behavior : DependencyObject, IBehavior
  {
    public DependencyObject AssociatedObject { get; set; }

    public virtual void Attach(DependencyObject associatedObject)
    {
      AssociatedObject = associatedObject;
    }

    public virtual void Detach()
    {
    }
  }
}
This is a base class for environments where generics cannot be used - and the implementation for C# behaviors is then simple:
using Windows.UI.Xaml;

namespace Win8nl.Behaviors
{
  /// <summary>
  /// A base class for behaviors, to appear them to be identical to older frameworks
  /// </summary>
  /// <typeparam name="T"></typeparam>
  public abstract class Behavior<T> : Behavior where T: DependencyObject
  {
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    public new T AssociatedObject { get; set; }

    public override void Attach(DependencyObject associatedObject)
    {
      base.Attach(associatedObject);
      this.AssociatedObject = (T)associatedObject;
      OnAttached();
    }

    public override  void Detach()
    {
      base.Detach();
      OnDetaching();
    }


    protected virtual void OnAttached()
    {
    }

    protected virtual void OnDetaching()
    {
    }

  }
}
Based upon this class, you can port your existing behaviors from WinRtBehaviors (or from any other XAML framework, for what matters, virtually without any code change. I wrote this code in the early days of August 2013, but kind of sat on it as I wanted it to be part of the new Win8nl library. I sat a bit on it too long, as Fons Sonnemans published a very similar solution in September, so I can’t really claim prior art, but let just say it’s a logical thing to do and great minds apparently think alike. I took the EditorBrowsable thing from him, never thought of that.

What you will also notice is that the ‘hero’ behaviors EventToCommandBehavior and EventToBoundCommandBehavior, although still present, are now marked as Obsolete.This is for a very simple reason: the framework now has a standard way of doing such things. Would you use something like this in Windows 8.0 XAML:
<WinRtBehaviors:Interaction.Behaviors>
  <Win8nl_Behavior:EventToBoundCommandBehavior Event="Loaded" 
    Command="{Binding StartGame}"/>
  <Win8nl_Behavior:EventToBoundCommandBehavior Event="Unloaded" 
    Command="{Binding SuspendGame}"/>
</WinRtBehaviors:Interaction.Behaviors>
Now you can achieve the same thing an EventTriggerBehavior combined with an InvokeCommandAction.
<interactivity:Interaction.Behaviors>
  <Core:EventTriggerBehavior EventName="Loaded">
    <Core:InvokeCommandAction Command="{Binding StartGame}"/>
</Core:EventTriggerBehavior>

<Core:EventTriggerBehavior EventName="Unloaded"> <Core:InvokeCommandAction Command="{Binding SuspendGame}"/> </Core:EventTriggerBehavior> </interactivity:Interaction.Behaviors>

Update November 11, 2013
InvokeCommandAction has a CommandParameter too that you can bind to and refer to in the usual way. An interesting and useful feature of InvokeCommandAction was pointed out to me by fellow MVP Morten Nielsen – if don’t specify a CommandParameter, it defaults to passing the event arguments of the trapped event to the command. So if you have for instance this

<interactivity:Interaction.Behaviors>
  <core:EventTriggerBehavior EventName="Tapped">
    <core:InvokeCommandAction Command="{Binding TappedCommand}"/>
  </core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>

Then this is still a valid command to intercept it – you just ignore the arguments

public ICommand TappedCommand
{
  get
  {
    return new RelayCommand(
        () =>
        {
          Debug.WriteLine ("Command tapped");
        });
  }
}

But this as well!

public ICommand TappedCommand
{
  get
  {
    return new RelayCommand<TappedRoutedEventArgs>(
        (p) =>
        {
          Debug.WriteLine ("Command tapped:" + p!=null);
        });
  }
}

And thus you can do something with the event arguments. So with InvokeCommandAction you can do everything you wanted to do with EventToBoundCommandBehavior.
(Update ends)
I would urge you to the utmost to no longer using EventToCommandBehavior and/or EventToBoundCommandBehavior from this day forward. Any support requests will simply be directed to this blog post ;).

Something I have been sitting on for very long – part of Catch’em Birds for Windows was a DataStateBehavior, which I basically cobbled together by reflecting into a Windows Phone 7 assembly, butchering stuff I didn’t need, understand or that did not compile, and finally arriving at something that kind of worked. For my goals. For obvious reasons I could not publish what was basically stolen and butchered Microsoft code and I am therefore very happy the Behavior SDK now has something to do the trick. If you now use DataStateBehavior in for instance a Windows Phone project like this:

<behaviors:Interaction.Behaviors>
  <behaviors_ic:DataStateBehavior Binding="{Binding IsGameOver}" 
     FalseState="GameNotOver" TrueState="GameOver" Value="true"/>
</behaviors:Interaction.Behaviors>
You can achieve the same effect by using this code:
<interactivity:Interaction.Behaviors>
  <Core:DataTriggerBehavior Binding="{Binding IsGameOver}" Value="True">
    <Core:GoToStateAction StateName="GameOver"/>
  </Core:DataTriggerBehavior>
  <Core:DataTriggerBehavior Binding="{Binding IsGameOver}" Value="False">
    <Core:GoToStateAction StateName="GameNotOver"/>
  </Core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
Thus ends the story of WinRtBehaviors on October 17, 2013. I hope you have enjoyed it, and I also hope to have given you a clear migration path.

I wish the development team lots of luck with the support requests from especially my Belgian friends, who were quite ingenious in finding scenarios in which the EventToCommand behaviors did not work properly. The best one was something like “the behavior does not work if it’s in a data template from a resource file located in another assembly”. ;)