Development: Windows 10 UWP Wireless Label/Receipt printer demo

As I already wrote the small demo apps for wireless printing of Label and Receipts for Android and Windows Phone 8, I now wrote such demo now for Windows UWP. The applciation was tested on a Windows 10 Phone running Windows 10 Iot Enterprise Edition.

The code is based on the Windows Universal Sample app BTRFCommChat, but uses a different, single page layout.

layout_designer     wp_ss_20160811_0001   wp_ss_20160811_0003   wp_ss_20160811_0005

The layout is based on a grid with a defined number of columns and rows. All rows are set to auto-adjust there height.

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
 <Grid.ColumnDefinitions>
 <ColumnDefinition Width="*" />
 <ColumnDefinition Width="*" />
 </Grid.ColumnDefinitions>
 <Grid.RowDefinitions>
 <RowDefinition Height="Auto" />
 <RowDefinition Height="Auto" />
 <RowDefinition Height="Auto" />
 <RowDefinition Height="Auto" />
 <RowDefinition Height="Auto" />
 <RowDefinition Height="Auto" />
 <RowDefinition Height="Auto" />
 </Grid.RowDefinitions>

Then the grid columns contain stackpanels with GUI elements. To guide thru the use of the demo application, these stackpanels or shown or hidden depending on the state of the demo. For example the first sate is to select a printer. In this state, only the “List Printers” button and the empty list is shown. After connecting a printer by tapping it’s name in the list. The stackpanel with “List Printers” and the list is collapsed (hidden).

As said, the code is based on the BTRFCommChat example. The first step was to change the BT service descriptor for the BT discovery to “RfcommServiceId.SerialPort”:

 // Find all paired instances of the Rfcomm service and display them in a list
 dataServiceDeviceCollection = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
 if (dataServiceDeviceCollection.Count > 0)
 {
  DeviceList.Items.Clear();
  foreach (var dataServiceDevice in dataServiceDeviceCollection)
  {
   DeviceList.Items.Add(dataServiceDevice.Name);
  }
  DeviceList.Visibility = Windows.UI.Xaml.Visibility.Visible;
 }

When a device is tapped, the application tries to create a socket connection:

 try
 {
  await dataSocket.ConnectAsync(dataService.ConnectionHostName, dataService.ConnectionServiceName);
  dataWriter = new DataWriter(dataSocket.OutputStream);
  Panel_SelectPrinter.Visibility = Visibility.Collapsed;
  PanelSelectFile.Visibility = Visibility.Visible;
  panelDisconnect.Visibility = Visibility.Visible;
  DataReader dataReader = new DataReader(dataSocket.InputStream);
  ReceiveStringLoop(dataReader);
 }

Then a list of prepared demo print files is shown. The list is build from all files deployed with the application within the files folder:

 private async void FilesListbox_Loaded(object sender, RoutedEventArgs e)
 {
  try
  {
   FilesListbox.Items.Clear();
   //fill the list with the files
   var folder = await StorageFolder.GetFolderFromPathAsync(Windows.ApplicationModel.Package.Current.InstalledLocation.Path + @"\files");
   IReadOnlyList<StorageFile> files = await folder.GetFilesAsync();
   foreach (StorageFile f in files)
    FilesListbox.Items.Add(f.Name);
  }
  catch (Exception ex)
  {
   System.Diagnostics.Debug.WriteLine("ListFiles: " + ex.Message);
  }
 }

If the user selected a file and taps the “Print” button, the file is send via the bluetooth socket connection to the printer:

 private async void SendFile()
 {
  try
  {
   if (FilesListbox.SelectedIndex == -1)
    return;
   string filename = FilesListbox.SelectedItem.ToString();
   // fp3macklabel.prn
   // Open file in application package
   // needs to be marked as Content and Copy Allways
   var fileToRead = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///files/" + filename, UriKind.Absolute));
   byte[] buffer = new byte[1024];
   int readcount = 0;
   using (BinaryReader fileReader = new BinaryReader(await fileToRead.OpenStreamForReadAsync()))
   {
    int read = fileReader.Read(buffer, 0, buffer.Length);
    while (read > 0)
    {
     readcount += read;
     Stream streamWrite = dataSocket.OutputStream.AsStreamForWrite();
     streamWrite.Write(buffer, 0, read);
     streamWrite.Flush();
     //the following does corrupt the byte stream!!!!!
     //byte[] buf = new byte[read];
     //Array.Copy(buffer, buf, read);
     //chatWriter.WriteBytes(buf);
     //await chatWriter.FlushAsync();
     //fileWriter.Write(buffer, 0, read);
     read = fileReader.Read(buffer, 0, buffer.Length);
    }
   }
   NotifyUser("sendFile " + readcount.ToString(), NotifyType.StatusMessage);
   await dataWriter.StoreAsync();
  }
  //catch hresult = 0x8000000e
  catch (NullReferenceException ex)
  {
   NotifyUser("Error: " + ex.HResult.ToString() + " - " + ex.Message,
   NotifyType.StatusMessage);
  }
  catch (IOException ex)
  {
   NotifyUser("Error: " + ex.HResult.ToString() + " - " + ex.Message,
   NotifyType.StatusMessage);
  }
  catch (Exception ex)
  {
   // TODO: Catch disconnect - HResult = 0x80072745 - catch this (remote device disconnect) ex = {"An established connection was aborted by the software in your host machine. (Exception from HRESULT: 0x80072745)"}
   NotifyUser("Error: " + ex.HResult.ToString() + " - " + ex.Message,
   NotifyType.StatusMessage);
  }
 }

That’s it. Source code available at github. The application has also been certified and is available in Windows Store.

Leave a Reply