How to Send Data Through Bluetooth in a WPF Application Using 32feet.Net

Scope

The solution in this article will implement the MVVM pattern and will use the MVVMLight Toolkit.

Introduction

Bluetooth is an industry-standard protocol that enables wireless connectivity for computers, handheld devices, mobile phones and other devices.

Bluetooth is designed for use by C/C++ programmers. Some Bluetooth features are available with Windows Sockets. Familiarity with Microsoft Windows networking and Windows Sockets programming is required. The article Bluetooth Programming with Windows Sockets describes how to use Windows Sockets functions and structures to program a Bluetooth application and provide the Bluetooth connection sample. But in a first attempt it does not look so nice when our goal is to create a WPF application.

In Codeplex, there is a project called 32feet.NET. This project is a shared-source project to make personal area networking technologies such as Bluetooth, Infrared (IrDA) and more, easily accessible from .NET code. It supports desktop, mobile or embedded systems.

32feet.NET is available on Nuget and for desktop apps the reference is 32feet.NET 3.5.0 Nuget Package. That is the version we will use in the sample we will create.

Description

The WPF application will have two "modes": Sender and Receiver. Where the "Sender" has the responsibility to send messages and the "Receiver" will get the messages sent by "Sender".

Let's start!

Creating the project

First create the WPF application in Visual Studio.

wpf application

Then install the nugget packages: MVVMLight and 32feet.Net, as in the following:

manage NuGet Packages

Installing the MVVM Light Toolkit:

MVVM Light

Installing 32feet.Net:

32feet net

At the end our solution will have the base structure to implement MVVM, that MVVM Light installed using Nuget.

Now we need to define the model for the device that is required when we get the list of the devices around us with Bluetooth on.

The Model

The model is defined by the Device class that represents the structure for the device around us. The implementation is:

  1. public sealed class Device  
  2. {  
  3.     /// <summary>  
  4.     /// Gets or sets the device name.  
  5.     /// </summary>  
  6.     /// <value>  
  7.     /// The device name.  
  8.     /// </value>  
  9.     public string DeviceName { getset; }  
  10.   
  11.     /// <summary>  
  12.     /// Gets or sets a value indicating whether authenticated.  
  13.     /// </summary>  
  14.     /// <value>  
  15.     /// The authenticated.  
  16.     /// </value>  
  17.     public bool IsAuthenticated { getset; }  
  18.   
  19.     /// <summary>  
  20.     /// Gets or sets a value indicating whether is connected.  
  21.     /// </summary>  
  22.     /// <value>  
  23.     /// The is connected.  
  24.     /// </value>  
  25.     public bool IsConnected { getset; }  
  26.   
  27.     /// <summary>  
  28.     /// Gets or sets the nap.  
  29.     /// </summary>  
  30.     /// <value>  
  31.     /// The nap.  
  32.     /// </value>  
  33.     public ushort Nap { getset; }  
  34.   
  35.     /// <summary>  
  36.     /// Gets or sets the sap.  
  37.     /// </summary>  
  38.     /// <value>  
  39.     /// The sap.  
  40.     /// </value>  
  41.     public uint Sap { getset; }  
  42.   
  43.     /// <summary>  
  44.     /// Gets or sets the last seen.  
  45.     /// </summary>  
  46.     /// <value>  
  47.     /// The last seen.  
  48.     /// </value>  
  49.     public DateTime LastSeen { getset; }  
  50.   
  51.     /// <summary>  
  52.     /// Gets or sets the last used.  
  53.     /// </summary>  
  54.     /// <value>  
  55.     /// The last used.  
  56.     /// </value>  
  57.     public DateTime LastUsed { getset; }  
  58.   
  59.     /// <summary>  
  60.     /// Gets or sets a value indicating whether remembered.  
  61.     /// </summary>  
  62.     /// <value>  
  63.     /// The remembered.  
  64.     /// </value>  
  65.     public bool Remembered { getset; }  
  66.       
  67.     /// <summary>  
  68.     /// Gets or sets the device info.  
  69.     /// </summary>  
  70.     /// <value>  
  71.     /// The device info.  
  72.     /// </value>  
  73.     public BluetoothDeviceInfo DeviceInfo { getset; }  
  74.   
  75.     /// <summary>  
  76.     /// Initializes a new instance of the <see cref="Device"/> class.  
  77.     /// </summary>  
  78.     /// <param name="device_info">  
  79.     /// The device_info.  
  80.     /// </param>  
  81.     public Device(BluetoothDeviceInfo device_info)  
  82.     {  
  83.         if (device_info != null)  
  84.         {  
  85.             DeviceInfo = device_info;  
  86.             IsAuthenticated = device_info.Authenticated;  
  87.             IsConnected = device_info.Connected;  
  88.             DeviceName = device_info.DeviceName;  
  89.             LastSeen = device_info.LastSeen;  
  90.             LastUsed = device_info.LastUsed;  
  91.             Nap = device_info.DeviceAddress.Nap;  
  92.             Sap = device_info.DeviceAddress.Sap;  
  93.             Remembered = device_info.Remembered;  
  94.         }  
  95.     }  
  96.   
  97.     /// <summary>  
  98.     /// The to string.  
  99.     /// </summary>  
  100.     /// <returns>  
  101.     /// The <see cref="string"/>.  
  102.     /// </returns>  
  103.     public override string ToString()  
  104.     {  
  105.         return DeviceName;  
  106.     }  
  107. }  
In a class diagram we will have:

divice

The Services

The services in the application will define the features for the "Sender" and for the "Receiver". These classes will be injected into the view model using the ServiceLocator and the setup is defined in the ViewModelLocator constructor.

To connect the "Sender" and the "Receiver", we need to define a Guid that is set to the ServiceClassId and it is the key for the communication. When the "Sender" sends a message using the ServiceClassID X only the "Receiver" that knows the ServiceClassID X will get the data, any other "Receiver" that only knows the ServiceClassID Y, for example, will not receive the data.

The ReceiverBluetoothService

The ReceiverBluetoothService defines how the "Receiver" will receive the data from the "Sender". Since it is used for a thread that will run and will be listening for data.

The implementation of this class is something like:
  1. public class ReceiverBluetoothService : ObservableObject, IDisposable, IReceiverBluetoothService  
  2.  {  
  3.      private readonly Guid _serviceClassId;  
  4.      private Action<string> _responseAction;  
  5.      private BluetoothListener _listener;  
  6.      private CancellationTokenSource _cancelSource;  
  7.      private bool _wasStarted;  
  8.      private string _status;  
  9.   
  10.      /// <summary>  
  11.      /// Initializes a new instance of the <see cref="ReceiverBluetoothService" /> class.  
  12.      /// </summary>  
  13.      public ReceiverBluetoothService()  
  14.      {  
  15.         _serviceClassId = new Guid("0e6114d0-8a2e-477a-8502-298d1ff4b4ba");  
  16.      }  
  17.   
  18.      /// <summary>  
  19.      /// Gets or sets a value indicating whether was started.  
  20.      /// </summary>  
  21.      /// <value>  
  22.      /// The was started.  
  23.      /// </value>  
  24.      public bool WasStarted  
  25.      {  
  26.          get { return _wasStarted; }  
  27.          set { Set(() => WasStarted, ref _wasStarted, value); }  
  28.      }  
  29.        
  30.      /// <summary>  
  31.      /// Starts the listening from Senders.  
  32.      /// </summary>  
  33.      /// <param name="reportAction">  
  34.      /// The report Action.  
  35.      /// </param>  
  36.      public void Start(Action<string> reportAction)  
  37.      {  
  38.          WasStarted = true;  
  39.          _responseAction = reportAction;  
  40.          if (_cancelSource != null && _listener != null)  
  41.          {  
  42.              Dispose(true);  
  43.          }  
  44.          _listener = new BluetoothListener(_serviceClassId)  
  45.          {  
  46.              ServiceName = "MyService"  
  47.          };  
  48.          _listener.Start();  
  49.   
  50.          _cancelSource = new CancellationTokenSource();  
  51.   
  52.          Task.Run(() => Listener(_cancelSource));  
  53.      }  
  54.   
  55.      /// <summary>  
  56.      /// Stops the listening from Senders.  
  57.      /// </summary>  
  58.      public void Stop()  
  59.      {  
  60.          WasStarted = false;  
  61.          _cancelSource.Cancel();  
  62.      }  
  63.   
  64.      /// <summary>  
  65.      /// Listeners the accept bluetooth client.  
  66.      /// </summary>  
  67.      /// <param name="token">  
  68.      /// The token.  
  69.      /// </param>  
  70.      private void Listener(CancellationTokenSource token)  
  71.      {  
  72.          try  
  73.          {  
  74.              while (true)  
  75.              {  
  76.                  using (var client = _listener.AcceptBluetoothClient())  
  77.                  {  
  78.                      if (token.IsCancellationRequested)  
  79.                      {  
  80.                          return;  
  81.                      }  
  82.   
  83.                      using (var streamReader = new StreamReader(client.GetStream()))  
  84.                      {  
  85.                          try  
  86.                          {  
  87.                              var content = streamReader.ReadToEnd();  
  88.                              if (!string.IsNullOrEmpty(content))  
  89.                              {  
  90.                                  _responseAction(content);  
  91.                              }  
  92.                          }  
  93.                          catch (IOException)  
  94.                          {  
  95.                              client.Close();  
  96.                              break;  
  97.                          }  
  98.                      }  
  99.                  }  
  100.              }  
  101.          }  
  102.          catch (Exception exception)  
  103.          {  
  104.             // todo handle the exception  
  105.             // for the sample it will be ignored  
  106.          }  
  107.      }  
  108.   
  109.      /// <summary>  
  110.      /// The dispose.  
  111.      /// </summary>  
  112.      public void Dispose()  
  113.      {  
  114.          Dispose(true);  
  115.          GC.SuppressFinalize(this);  
  116.      }  
  117.   
  118.      /// <summary>  
  119.      /// The dispose.  
  120.      /// </summary>  
  121.      /// <param name="disposing">  
  122.      /// The disposing.  
  123.      /// </param>  
  124.      protected virtual void Dispose(bool disposing)  
  125.      {  
  126.          if (disposing)  
  127.          {  
  128.              if (_cancelSource != null)  
  129.              {  
  130.                  _listener.Stop();  
  131.                  _listener = null;  
  132.                  _cancelSource.Dispose();  
  133.                  _cancelSource = null;  
  134.              }  
  135.          }  
  136.      }  
  137.  }  
In the Start method we need to define an action that will be used to report the data received in ViewModel. We could use an event or the Message feature from MVVMLight.

In the Listener method that is running in another thread, we defined a CancellationTokenSource that will be used to stop the process listening for data.

Note: The "Receiver" allows the starting or stopping of the process listening for data. If a "Sender" sends data but the "Receiver" does not allow for listening, the "Sender" will send the data but the "Receiver" will not get it.

The SenderBluetoothService

The SenderBluetoothService defines how the "Sender" will send the data, but it is required to select a device that is available. It is not possible to filter for devices that know the ServiceClassId and the name of the device for where the "Sender" wants to send the data should be known.

The implementation of this class is something like:
  1. public sealed class SenderBluetoothService : ISenderBluetoothService  
  2. {  
  3.      private readonly Guid _serviceClassId;  
  4.   
  5.     /// <summary>  
  6.     /// Initializes a new instance of the <see cref="SenderBluetoothService"/> class.   
  7.     /// </summary>  
  8.     public SenderBluetoothService()  
  9.     {  
  10.         // this guid is random, only need to match in Sender & Receiver  
  11.         // this is like a "key" for the connection!  
  12.         _serviceClassId = new Guid("0e6114d0-8a2e-477a-8502-298d1ff4b4ba");  
  13.     }  
  14.   
  15.     /// <summary>  
  16.     /// Gets the devices.  
  17.     /// </summary>  
  18.     /// <returns>The list of the devices.</returns>  
  19.     public async Task<IList<Device>> GetDevices()  
  20.     {  
  21.         // for not block the UI it will run in a different threat  
  22.         var task = Task.Run(() =>  
  23.         {  
  24.             var devices = new List<Device>();  
  25.             using (var bluetoothClient = new BluetoothClient())  
  26.             {  
  27.                 var array = bluetoothClient.DiscoverDevices();  
  28.                 var count = array.Length;  
  29.                 for (var i = 0; i < count; i++)  
  30.                 {  
  31.                     devices.Add(new Device(array[i]));  
  32.                 }  
  33.             }  
  34.             return devices;  
  35.         });  
  36.         return await task;  
  37.     }  
  38.   
  39.     /// <summary>  
  40.     /// Sends the data to the Receiver.  
  41.     /// </summary>  
  42.     /// <param name="device">The device.</param>  
  43.     /// <param name="content">The content.</param>  
  44.     /// <returns>If was sent or not.</returns>  
  45.     public async Task<bool> Send(Device device, string content)  
  46.     {  
  47.         if (device == null)  
  48.         {  
  49.             throw new ArgumentNullException("device");  
  50.         }  
  51.   
  52.         if (string.IsNullOrEmpty(content))  
  53.         {  
  54.             throw new ArgumentNullException("content");  
  55.         }  
  56.   
  57.         // for not block the UI it will run in a different threat  
  58.         var task = Task.Run(() =>  
  59.         {  
  60.             using (var bluetoothClient = new BluetoothClient())  
  61.             {  
  62.                 try  
  63.                 {  
  64.                     var ep = new BluetoothEndPoint(device.DeviceInfo.DeviceAddress, _serviceClassId);  
  65.                      
  66.                     // connecting  
  67.                     bluetoothClient.Connect(ep);  
  68.   
  69.                     // get stream for send the data  
  70.                     var bluetoothStream = bluetoothClient.GetStream();  
  71.   
  72.                     // if all is ok to send  
  73.                     if (bluetoothClient.Connected && bluetoothStream != null)  
  74.                     {  
  75.                         // write the data in the stream  
  76.                         var buffer = System.Text.Encoding.UTF8.GetBytes(content);  
  77.                         bluetoothStream.Write(buffer, 0, buffer.Length);  
  78.                         bluetoothStream.Flush();  
  79.                         bluetoothStream.Close();  
  80.                         return true;  
  81.                     }  
  82.                     return false;  
  83.                 }  
  84.                 catch  
  85.                 {  
  86.                     // the error will be ignored and the send data will report as not sent  
  87.                     // for understood the type of the error, handle the exception  
  88.                 }  
  89.             }  
  90.             return false;  
  91.         });  
  92.         return await task;  
  93.     }  
  94. }  
In the Send method, when we are connected to the selected device, we will be able to write in a stream that is received by "Receiver".

The ViewModel

We will define the following view models: ReceiverViewModel, SenderViewModel and MainViewModel that will be binding to the DataContext in ReceiverView, SenderView and MainWindow respectively.

The ReceiverViewModel
  1. public sealed class ReceiverViewModel : ViewModelBase  
  2. {  
  3.     private readonly IReceiverBluetoothService _receiverBluetoothService;  
  4.     private string _data;  
  5.     private bool _isStarEnabled;  
  6.     private string _status;  
  7.   
  8.     /// <summary>  
  9.     /// Initializes a new instance of the <see cref="ReceiverViewModel" /> class.  
  10.     /// </summary>  
  11.     /// <param name="receiverBluetoothService">The Receiver bluetooth service.</param>  
  12.     public ReceiverViewModel(IReceiverBluetoothService receiverBluetoothService)  
  13.     {  
  14.         _receiverBluetoothService = receiverBluetoothService;  
  15.         _receiverBluetoothService.PropertyChanged += ReceiverBluetoothService_PropertyChanged;  
  16.         IsStarEnabled = true;  
  17.         Data = "N/D";  
  18.         Status = "N/D";  
  19.         StartCommand = new RelayCommand(() =>  
  20.         {  
  21.             _receiverBluetoothService.Start(SetData);  
  22.             IsStarEnabled = false;  
  23.             Data = "Can receive data.";  
  24.         });  
  25.   
  26.         StopCommand = new RelayCommand(() =>  
  27.         {  
  28.             _receiverBluetoothService.Stop();  
  29.             IsStarEnabled = true;  
  30.             Data = "Cannot receive data.";  
  31.         });  
  32.   
  33.         Messenger.Default.Register<Message>(this, ResetAll);  
  34.     }  
  35.   
  36.     /// <summary>  
  37.     /// Resets all.  
  38.     /// </summary>  
  39.     /// <param name="message">The message.</param>  
  40.     private void ResetAll(Message message)  
  41.     {  
  42.         if (!message.IsToShowDevices)  
  43.         {  
  44.             if (_receiverBluetoothService.WasStarted)  
  45.             {  
  46.                 _receiverBluetoothService.Stop();  
  47.             }  
  48.             IsStarEnabled = true;  
  49.             Data = "N/D";  
  50.             Status = "N/D";  
  51.         }  
  52.     }  
  53.   
  54.     /// <summary>  
  55.     /// The set data received.  
  56.     /// </summary>  
  57.     /// <param name="data">  
  58.     /// The data.  
  59.     /// </param>  
  60.     public void SetData(string data)  
  61.     {  
  62.         Data = data;  
  63.     }  
  64.   
  65.     /// <summary>  
  66.     /// Gets or sets the data.  
  67.     /// </summary>  
  68.     /// <value>  
  69.     /// The data received.  
  70.     /// </value>  
  71.     public string Data  
  72.     {  
  73.         get { return _data; }  
  74.         set { Set(() => Data, ref _data, value); }  
  75.     }  
  76.   
  77.     /// <summary>  
  78.     /// Gets the start command.  
  79.     /// </summary>  
  80.     /// <value>  
  81.     /// The start command.  
  82.     /// </value>  
  83.     public ICommand StartCommand { getprivate set; }  
  84.   
  85.     /// <summary>  
  86.     /// Gets the stop command.  
  87.     /// </summary>  
  88.     /// <value>  
  89.     /// The stop command.  
  90.     /// </value>  
  91.     public ICommand StopCommand { getprivate set; }  
  92.   
  93.     /// <summary>  
  94.     /// Gets or sets a value indicating whether is star enabled.  
  95.     /// </summary>  
  96.     /// <value>  
  97.     /// The is star enabled.  
  98.     /// </value>  
  99.     public bool IsStarEnabled  
  100.     {  
  101.         get  
  102.         {  
  103.             return _isStarEnabled;  
  104.         }  
  105.         set  
  106.         {  
  107.             Set(() => IsStarEnabled, ref _isStarEnabled, value);  
  108.             RaisePropertyChanged(() => IsStopEnabled);  
  109.         }  
  110.     }  
  111.   
  112.     /// <summary>  
  113.     /// Gets or sets a value indicating whether is stop enabled.  
  114.     /// </summary>  
  115.     /// <value>  
  116.     /// The is stop enabled.  
  117.     /// </value>  
  118.     public bool IsStopEnabled  
  119.     {  
  120.         get  
  121.         {  
  122.             return !_isStarEnabled;  
  123.         }  
  124.         set  
  125.         {  
  126.             Set(() => IsStopEnabled, ref _isStarEnabled, !value);  
  127.             RaisePropertyChanged(() => IsStarEnabled);  
  128.         }  
  129.     }  
  130.   
  131.     /// <summary>  
  132.     /// Gets or sets the status.  
  133.     /// </summary>  
  134.     /// <value>The status.</value>  
  135.     public string Status  
  136.     {  
  137.         get { return _status; }  
  138.         set { Set(() => Status, ref _status, value); }  
  139.     }  
  140.   
  141.     /// <summary>  
  142.     /// Handles the PropertyChanged event of the ReceiverBluetoothService control.  
  143.     /// </summary>  
  144.     /// <param name="sender">The source of the event.</param>  
  145.     /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>  
  146.     private void ReceiverBluetoothService_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)  
  147.     {  
  148.         if (e.PropertyName == "WasStarted")  
  149.         {  
  150.             IsStarEnabled = true;  
  151.         }  
  152.     }  
  153. }  
The SenderViewModel
  1. public sealed class SenderViewModel : ViewModelBase  
  2. {  
  3.     private readonly ISenderBluetoothService _senderBluetoothService;  
  4.     private string _data;  
  5.     private Device _selectDevice;  
  6.     private string _resultValue;  
  7.   
  8.     /// <summary>  
  9.     /// Initializes a new instance of the <see cref="SenderViewModel"/> class.  
  10.     /// </summary>  
  11.     /// <param name="senderBluetoothService">  
  12.     /// The Sender bluetooth service.  
  13.     /// </param>  
  14.     public SenderViewModel(ISenderBluetoothService senderBluetoothService)  
  15.     {  
  16.         _senderBluetoothService = senderBluetoothService;  
  17.         ResultValue = "N/D";  
  18.         SendCommand = new RelayCommand(  
  19.             SendData,  
  20.             () => !string.IsNullOrEmpty(Data) && SelectDevice != null && SelectDevice.DeviceInfo != null);  
  21.         Devices = new ObservableCollection<Device>  
  22.         {  
  23.             new Device(null) { DeviceName = "Searching..." }  
  24.         };  
  25.         Messenger.Default.Register<Message>(this, ShowDevice);  
  26.     }  
  27.   
  28.     /// <summary>  
  29.     /// Gets or sets the devices.  
  30.     /// </summary>  
  31.     /// <value>  
  32.     /// The devices.  
  33.     /// </value>  
  34.     public ObservableCollection<Device> Devices  
  35.     {  
  36.         getset;  
  37.     }  
  38.   
  39.     /// <summary>  
  40.     /// Gets or sets the select device.  
  41.     /// </summary>  
  42.     /// <value>  
  43.     /// The select device.  
  44.     /// </value>  
  45.     public Device SelectDevice  
  46.     {  
  47.         get { return _selectDevice; }  
  48.         set { Set(() => SelectDevice, ref _selectDevice, value); }  
  49.     }  
  50.   
  51.     /// <summary>  
  52.     /// Gets or sets the data.  
  53.     /// </summary>  
  54.     /// <value>  
  55.     /// The data.  
  56.     /// </value>  
  57.     public string Data  
  58.     {  
  59.         get { return _data; }  
  60.         set { Set(() => Data, ref _data, value); }  
  61.     }  
  62.   
  63.     /// <summary>  
  64.     /// Gets or sets the result value.  
  65.     /// </summary>  
  66.     /// <value>  
  67.     /// The result value.  
  68.     /// </value>  
  69.     public string ResultValue  
  70.     {  
  71.         get { return _resultValue; }  
  72.         set { Set(() => ResultValue, ref _resultValue, value); }  
  73.     }  
  74.   
  75.     /// <summary>  
  76.     /// Gets the send command.  
  77.     /// </summary>  
  78.     /// <value>  
  79.     /// The send command.  
  80.     /// </value>  
  81.     public ICommand SendCommand { getprivate set; }  
  82.   
  83.     private async void SendData()  
  84.     {  
  85.         ResultValue = "N/D";  
  86.         var wasSent = await _senderBluetoothService.Send(SelectDevice, Data);  
  87.         if (wasSent)  
  88.         {  
  89.             ResultValue = "The data was sent.";  
  90.         }  
  91.         else  
  92.         {  
  93.             ResultValue = "The data was not sent.";  
  94.         }  
  95.     }  
  96.   
  97.     /// <summary>  
  98.     /// Shows the device.  
  99.     /// </summary>  
  100.     /// <param name="deviceMessage">The device message.</param>  
  101.     private async void ShowDevice(Message deviceMessage)  
  102.     {  
  103.         if (deviceMessage.IsToShowDevices)  
  104.         {  
  105.             var items = await _senderBluetoothService.GetDevices();  
  106.             Devices.Clear();  
  107.             Devices.Add(items);  
  108.             Data = string.Empty;  
  109.         }  
  110.     }  
  111. }  
The MainViewModel
  1. public sealed class MainViewModel : ViewModelBase  
  2. {  
  3.     private bool _isReceiver;  
  4.   
  5.     /// <summary>  
  6.     /// Initializes a new instance of the <see cref="MainViewModel"/> class.  
  7.     /// </summary>  
  8.     public MainViewModel()  
  9.     {  
  10.         PropertyChanged += MainViewModelPropertyChanged;  
  11.         IsSender = false;  
  12.     }  
  13.   
  14.     /// <summary>  
  15.     /// Gets or sets a value indicating whether is Receiver.  
  16.     /// </summary>  
  17.     /// <value>  
  18.     /// The is Receiver.  
  19.     /// </value>  
  20.     public bool IsReceiver  
  21.     {  
  22.         get  
  23.         {  
  24.             return _isReceiver;  
  25.         }  
  26.         set  
  27.         {  
  28.             Set(() => IsReceiver, ref _isReceiver, value);  
  29.             RaisePropertyChanged(() => IsSender);  
  30.         }  
  31.     }  
  32.   
  33.     /// <summary>  
  34.     /// Gets or sets a value indicating whether is Sender.  
  35.     /// </summary>  
  36.     /// <value>  
  37.     /// The is Sender.  
  38.     /// </value>  
  39.     public bool IsSender  
  40.     {  
  41.         get  
  42.         {  
  43.             return !_isReceiver;  
  44.         }  
  45.         set  
  46.         {  
  47.             Set(() => IsSender, ref _isReceiver, !value);  
  48.             RaisePropertyChanged(() => IsReceiver);  
  49.         }  
  50.     }  
  51.   
  52.     /// <summary>  
  53.     /// Gets or sets the Receiver visibility.  
  54.     /// </summary>  
  55.     /// <value>  
  56.     /// The Receiver visibility.  
  57.     /// </value>  
  58.     public Visibility ReceiverVisibility  
  59.     {  
  60.         get  
  61.         {  
  62.             return _isReceiver ? Visibility.Visible : Visibility.Collapsed;  
  63.         }  
  64.         set  
  65.         {  
  66.             _isReceiver = value == Visibility.Visible;  
  67.         }  
  68.     }  
  69.   
  70.     /// <summary>  
  71.     /// Gets or sets the Sender visibility.  
  72.     /// </summary>  
  73.     /// <value>  
  74.     /// The Sender visibility.  
  75.     /// </value>  
  76.     public Visibility SenderVisibility  
  77.     {  
  78.         get  
  79.         {  
  80.             return !_isReceiver ? Visibility.Visible : Visibility.Collapsed;  
  81.         }  
  82.         set   
  83.         {  
  84.             _isReceiver = value != Visibility.Visible;  
  85.         }  
  86.     }  
  87.   
  88.     /// <summary>  
  89.     /// Mains the view model property changed.  
  90.     /// </summary>  
  91.     /// <param name="sender">The sender.</param>  
  92.     /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>  
  93.     private void MainViewModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)  
  94.     {  
  95.         if (e.PropertyName == "IsReceiver" || e.PropertyName == "IsSender")  
  96.         {  
  97.             RaisePropertyChanged(() => ReceiverVisibility);              
  98.             RaisePropertyChanged(() => SenderVisibility);  
  99.   
  100.             if (e.PropertyName == "IsReceiver")  
  101.             {  
  102.                 Messenger.Default.Send(IsSender ? new Message(true) : new Message(false));  
  103.             }  
  104.         }  
  105.     }  
  106. }  
The UI

The MainWindow will be the starting point for the application and will contain the two user controls: ReceiverView and SenderView that will be shown if the user wants to be a "Sender" or a "Receiver".

The ReceiverView.xaml

The implementation will be something like:
  1. <UserControl x:Class="BluetoothSample.Views.ReceiverView"  
  2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
  5.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
  6.              DataContext="{Binding ReceiverViewModel, Source={StaticResource Locator}}"  
  7.              mc:Ignorable="d"   
  8.              d:DesignHeight="300" d:DesignWidth="400">  
  9.     <StackPanel Margin="20"  Orientation="Vertical">  
  10.         <TextBlock>I am the Receiver</TextBlock>  
  11.         <StackPanel Orientation="Horizontal">  
  12.             <Button Margin="0,10,0,0" Width="80"  Command="{Binding StartCommand}" IsEnabled="{Binding IsStarEnabled}" Content="Start"/>  
  13.             <Button Margin="20,10,0,0" Width="80" Command="{Binding StopCommand}" IsEnabled="{Binding IsStopEnabled}" Content="Stop"/>  
  14.         </StackPanel>  
  15.         <TextBlock Margin="00,20,0,0" Text="Data:"/>  
  16.         <TextBlock Margin="00,20,0,0" Text="{Binding Data}"/>  
  17.     </StackPanel>  
  18. </UserControl>  
The SenderView.xaml

The implementation will be something like:
  1. <UserControl x:Class="BluetoothSample.Views.SenderView"  
  2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
  5.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  6.              DataContext="{Binding SenderViewModel,  
  7.                                    Source={StaticResource Locator}}"  
  8.              d:DesignHeight="400"  
  9.              d:DesignWidth="400"  
  10.              mc:Ignorable="d">  
  11.     <StackPanel Margin="20" Orientation="Vertical">  
  12.         <TextBlock>I am the Sender.</TextBlock>  
  13.         <TextBlock Margin="0,20,0,0">Select one device:</TextBlock>  
  14.         <ListBox Width="200"  
  15.                  Height="100"  
  16.                  MaxWidth="200"  
  17.                  MaxHeight="100"  
  18.                  Margin="0,20,0,0"  
  19.                  HorizontalAlignment="Left"  
  20.                  ItemsSource="{Binding Devices}"  
  21.                  SelectedItem="{Binding SelectDevice}" />  
  22.         <TextBlock Margin="0,20,0,0" Text="Write the data to send:" />  
  23.         <TextBox Margin="0,20,20,0" Text="{Binding Data, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />  
  24.         <Button Width="80"  
  25.                 Margin="0,20,20,0"  
  26.                 HorizontalAlignment="Right"  
  27.                 Command="{Binding SendCommand}"  
  28.                 Content="Send" />  
  29.         <TextBlock Margin="0,20,0,0" TextWrapping="Wrap">  
  30.             Result:<Run Text="{Binding ResultValue}" />  
  31.         </TextBlock>  
  32.     </StackPanel>  
  33. </UserControl>  
The MainWindow.xaml

The MainWindow will show/hide the user controls defined. The implementation is defined by:
  1. <Window x:Class="BluetoothSample.MainWindow"  
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.         xmlns:views="clr-namespace:BluetoothSample.Views"  
  5.         DataContext="{Binding Main, Source={StaticResource Locator}}"  
  6.         Title="Bluetooth Sample"   
  7.         MinWidth="600" MinHeight="560"  
  8.         MaxWidth="600" MaxHeight="560">  
  9.     <StackPanel Orientation="Vertical">  
  10.         <GroupBox Margin="10,10,10,0"  Header="Choose the type:">  
  11.             <StackPanel Orientation="Horizontal">  
  12.                 <RadioButton Margin="20" IsChecked="{Binding IsReceiver, Mode=TwoWay}">Receiver - will receive data from Sender</RadioButton>  
  13.                 <RadioButton Margin="20" IsChecked="{Binding IsSender, Mode=TwoWay}">Sender - will send data for the Receiver</RadioButton>  
  14.             </StackPanel>  
  15.         </GroupBox>  
  16.         <GroupBox Margin="10,10,10,0" Header="Dashboard">  
  17.             <StackPanel Orientation="Vertical">  
  18.                 <!-- visibility binding not worked in user control and   
  19.                 for this reason was added the stackpanel for each usercontrol-->  
  20.                 <StackPanel Visibility="{Binding ReceiverVisibility}">  
  21.                     <views:ReceiverView Height="390" x:Name="ReceiverView"/>  
  22.                 </StackPanel>  
  23.                 <StackPanel Visibility="{Binding SenderVisibility}">  
  24.                     <views:SenderView Height="390"  x:Name="SenderView" />  
  25.                 </StackPanel>  
  26.             </StackPanel>  
  27.         </GroupBox>  
  28.     </StackPanel>  
  29. </Window>  
Note: To have a nice look, we will add the Modern UI nugget package. To see more about it, please read the following article: Modern UI for WPF application by example (Blank Window).

The ViewModelLocator

The ViewModelLocator will be a static resource for the application and is defined in App.xaml, as in the following;
  1. <vm:ViewModelLocator xmlns:vm="clr-namespace:BluetoothSample.ViewModel"  
  2.                                  x:Key="Locator"  
  3.                                  d:IsDataSource="True" />  
This class is where the setup for the view model and service are made and the implementation is something like:
  1. public class ViewModelLocator  
  2. {  
  3.     /// <summary>  
  4.     /// Initializes a new instance of the ViewModelLocator class.  
  5.     /// </summary>  
  6.     public ViewModelLocator()  
  7.     {  
  8.         ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);  
  9.   
  10.         SimpleIoc.Default.Register<IReceiverBluetoothService, ReceiverBluetoothService>();  
  11.         SimpleIoc.Default.Register<ISenderBluetoothService, SenderBluetoothService>();  
  12.         SimpleIoc.Default.Register<MainViewModel>();  
  13.         SimpleIoc.Default.Register<ReceiverViewModel>();  
  14.         SimpleIoc.Default.Register<SenderViewModel>();  
  15.     }  
  16.   
  17.     /// <summary>  
  18.     /// Gets the main.  
  19.     /// </summary>  
  20.     /// <value>The main.</value>  
  21.     public MainViewModel Main  
  22.     {  
  23.         get  
  24.         {  
  25.             return ServiceLocator.Current.GetInstance<MainViewModel>();  
  26.         }  
  27.     }  
  28.   
  29.     /// <summary>  
  30.     /// Gets the Receiver view model.  
  31.     /// </summary>  
  32.     /// <value>The Receiver view model.</value>  
  33.     public ReceiverViewModel ReceiverViewModel  
  34.     {  
  35.         get  
  36.         {  
  37.             return ServiceLocator.Current.GetInstance<ReceiverViewModel>();  
  38.         }  
  39.     }  
  40.   
  41.     /// <summary>  
  42.     /// Gets the Sender view model.  
  43.     /// </summary>  
  44.     /// <value>The Sender view model.</value>  
  45.     public SenderViewModel SenderViewModel  
  46.     {  
  47.         get  
  48.         {  
  49.             return ServiceLocator.Current.GetInstance<SenderViewModel>();  
  50.         }  
  51.     }  
  52.   
  53.     /// <summary>  
  54.     /// Cleanups this instance.  
  55.     /// </summary>  
  56.     public static void Cleanup()  
  57.     {  
  58.         // TODO Clear the ViewModels  
  59.     }  
  60. }  
Running the application

To test the application we need two devices, where in the first device we will run as "Sender" and in the second device we will run as "Receiver".

The "Receiver" can start listening as in the following:

bluetooth sample

The "Sender" is searching for available devices as in the following:

choose the type

The "Receiver" begins to listen as in the following:

Receiver

The "Sender" can select a device for sending the message as in the following:

select a device for send the message

The "Sender" will send a message for the selected device as in the following:

send a message for the selected device

The "Receiver" received the data sent by "Sender" as in the following:

received data sent by Sender

Conclusion

In conclusion, we can conclude the 32feet.Net is a great library to get all the devices around with Bluetooth on and to send data using Bluetooth. The library has a great documentation but could have more samples that we could run to test the features provided.

Another point that the developer should be aware of is the fact the project hasn´t been updated since 2012 but everyone can use the source code if needed, to fix any issue.

Source Code

The complete source code can be found in: Bluetooth Sample using 32feet.Net.

Credits

Thanks to Pedro Lamas and Peter Foot for helping me to make it work!

 

Up Next
    Ebook Download
    View all
    Learn
    View all