Server/MainForm.cs
author sl
Sat, 16 Aug 2014 11:15:42 +0200
changeset 33 1363bda20171
parent 32 4c416d2878dd
child 34 59bfa4ebcbbb
permissions -rw-r--r--
Adding texts fields to our test client.
Trying to fix bugs and optimize our marquee control.
Creating a proper ClientData class to use in our UI thread client dictionary.
Centralising tree-view update.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading.Tasks;
     9 using System.Windows.Forms;
    10 using System.IO;
    11 using CodeProject.Dialog;
    12 using System.Drawing.Imaging;
    13 using System.ServiceModel;
    14 using System.Threading;
    15 using System.Diagnostics;
    16 //
    17 using SharpDisplayInterface;
    18 using SharpDisplayClient;
    19 
    20 
    21 namespace SharpDisplayManager
    22 {
    23     /// <summary>
    24     /// A UI thread copy of a client relevant data.
    25     /// Keeping this copy in the UI thread helps us deal with threading issues.
    26     /// </summary>
    27     public class ClientData
    28     {
    29         public ClientData(string aSessionId, IDisplayServiceCallback aCallback)
    30         {
    31             SessionId = aSessionId;
    32             Name = "";
    33             Texts = new List<string>();
    34             Callback = aCallback;
    35         }
    36 
    37         public string SessionId { get; set;}
    38         public string Name { get; set;}
    39         public List<string> Texts { get; set;}
    40         public IDisplayServiceCallback Callback { get; set;}
    41     }
    42 
    43 
    44     public partial class MainForm : Form
    45     {
    46         DateTime LastTickTime;
    47         Display iDisplay;
    48         System.Drawing.Bitmap iBmp;
    49         bool iCreateBitmap; //Workaround render to bitmap issues when minimized
    50         ServiceHost iServiceHost;
    51         /// <summary>
    52         /// Our collection of clients
    53         /// </summary>
    54         public Dictionary<string, ClientData> iClients;
    55         public bool iClosing;
    56 
    57         public MainForm()
    58         {
    59             LastTickTime = DateTime.Now;
    60             iDisplay = new Display();
    61             iClients = new Dictionary<string, ClientData>();
    62 
    63             InitializeComponent();
    64             UpdateStatus();
    65 
    66             //Load settings
    67             marqueeLabelTop.Font = Properties.Settings.Default.DisplayFont;
    68             marqueeLabelBottom.Font = Properties.Settings.Default.DisplayFont;
    69             checkBoxShowBorders.Checked = Properties.Settings.Default.DisplayShowBorders;
    70             checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
    71             checkBoxReverseScreen.Checked = Properties.Settings.Default.DisplayReverseScreen;
    72             //
    73             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
    74             //We have a bug when drawing minimized and reusing our bitmap
    75             iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
    76             iCreateBitmap = false;
    77         }
    78 
    79         private void MainForm_Load(object sender, EventArgs e)
    80         {
    81             StartServer();
    82 
    83             if (Properties.Settings.Default.DisplayConnectOnStartup)
    84             {
    85                 iDisplay.Open();
    86                 UpdateStatus();
    87             }
    88         }
    89 
    90 
    91         private void buttonFont_Click(object sender, EventArgs e)
    92         {
    93             //fontDialog.ShowColor = true;
    94             //fontDialog.ShowApply = true;
    95             fontDialog.ShowEffects = true;
    96             fontDialog.Font = marqueeLabelTop.Font;
    97 
    98             fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
    99 
   100             //fontDialog.ShowHelp = true;
   101 
   102             //fontDlg.MaxSize = 40;
   103             //fontDlg.MinSize = 22;
   104 
   105             //fontDialog.Parent = this;
   106             //fontDialog.StartPosition = FormStartPosition.CenterParent;
   107 
   108             //DlgBox.ShowDialog(fontDialog);
   109 
   110             //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
   111             if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
   112             {
   113 
   114                 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
   115 
   116                 //MessageBox.Show("Ok");
   117                 marqueeLabelTop.Font = fontDialog.Font;
   118                 marqueeLabelBottom.Font = fontDialog.Font;
   119                 Properties.Settings.Default.DisplayFont = fontDialog.Font;
   120                 Properties.Settings.Default.Save();
   121                 //label1.Font = fontDlg.Font;
   122                 //textBox1.BackColor = fontDlg.Color;
   123                 //label1.ForeColor = fontDlg.Color;
   124             }
   125         }
   126 
   127         private void buttonCapture_Click(object sender, EventArgs e)
   128         {
   129             System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
   130             tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
   131             //Bitmap bmpToSave = new Bitmap(bmp);
   132             bmp.Save("D:\\capture.png");
   133 
   134             marqueeLabelTop.Text = "Sweet";
   135 
   136             /*
   137             string outputFileName = "d:\\capture.png";
   138             using (MemoryStream memory = new MemoryStream())
   139             {
   140                 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
   141                 {
   142                     bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
   143                     byte[] bytes = memory.ToArray();
   144                     fs.Write(bytes, 0, bytes.Length);
   145                 }
   146             }
   147              */
   148 
   149         }
   150 
   151         private void CheckForRequestResults()
   152         {
   153             if (iDisplay.IsRequestPending())
   154             {
   155                 switch (iDisplay.AttemptRequestCompletion())
   156                 {
   157                     case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
   158                         if (iDisplay.PowerSupplyStatus())
   159                         {
   160                             toolStripStatusLabelPower.Text = "ON";
   161                         }
   162                         else
   163                         {
   164                             toolStripStatusLabelPower.Text = "OFF";
   165                         }
   166                         //Issue next request then
   167                         iDisplay.RequestDeviceId();
   168                         break;
   169 
   170                     case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
   171                         toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
   172                         //Issue next request then
   173                         iDisplay.RequestFirmwareRevision();
   174                         break;
   175 
   176                     case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
   177                         toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
   178                         //No more request to issue
   179                         break;
   180                 }
   181             }
   182         }
   183 
   184 
   185         public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
   186 
   187 
   188         public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
   189         {
   190             return aBmp.Width - aX - 1;
   191         }
   192 
   193         public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
   194         {
   195             return iBmp.Height - aY - 1;
   196         }
   197 
   198         public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
   199         {
   200             return aX;
   201         }
   202 
   203         public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
   204         {
   205             return aY;
   206         }
   207 
   208 
   209         //This is our timer tick responsible to perform our render
   210         private void timer_Tick(object sender, EventArgs e)
   211         {
   212             //Update our animations
   213             DateTime NewTickTime = DateTime.Now;
   214 
   215             marqueeLabelTop.UpdateAnimation(LastTickTime, NewTickTime);
   216             marqueeLabelBottom.UpdateAnimation(LastTickTime, NewTickTime);
   217 
   218             //Update our display
   219             if (iDisplay.IsOpen())
   220             {
   221                 CheckForRequestResults();
   222 
   223                 //Draw to bitmap
   224                 if (iCreateBitmap)
   225                 {
   226                     iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   227                 }
   228                 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
   229                 //iBmp.Save("D:\\capture.png");
   230 
   231                 //Select proper coordinate translation functions
   232                 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
   233                 CoordinateTranslationDelegate screenX;
   234                 CoordinateTranslationDelegate screenY;
   235 
   236                 if (Properties.Settings.Default.DisplayReverseScreen)
   237                 {
   238                     screenX = ScreenReversedX;
   239                     screenY = ScreenReversedY;
   240                 }
   241                 else
   242                 {
   243                     screenX = ScreenX;
   244                     screenY = ScreenY;
   245                 }
   246 
   247                 //Send it to our display
   248                 for (int i = 0; i < iBmp.Width; i++)
   249                 {
   250                     for (int j = 0; j < iBmp.Height; j++)
   251                     {
   252                         unchecked
   253                         {
   254                             uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
   255                             //For some reason when the app is minimized in the task bar only the alpha of our color is set.
   256                             //Thus that strange test for rendering to work both when the app is in the task bar and when it isn't.
   257                             iDisplay.SetPixel(screenX(iBmp, i), screenY(iBmp, j), Convert.ToInt32(!(color != 0xFF000000)));
   258                         }
   259                     }
   260                 }
   261 
   262                 iDisplay.SwapBuffers();
   263 
   264             }
   265 
   266             //Compute instant FPS
   267             toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " FPS";
   268 
   269             LastTickTime = NewTickTime;
   270 
   271         }
   272 
   273         private void buttonOpen_Click(object sender, EventArgs e)
   274         {
   275             if (iDisplay.Open())
   276             {
   277                 UpdateStatus();
   278                 iDisplay.RequestPowerSupplyStatus();
   279             }
   280             else
   281             {
   282                 UpdateStatus();
   283                 toolStripStatusLabelConnect.Text = "Connection error";
   284             }
   285 
   286         }
   287 
   288         private void buttonClose_Click(object sender, EventArgs e)
   289         {
   290             iDisplay.Close();
   291             UpdateStatus();
   292         }
   293 
   294         private void buttonClear_Click(object sender, EventArgs e)
   295         {
   296             iDisplay.Clear();
   297             iDisplay.SwapBuffers();
   298         }
   299 
   300         private void buttonFill_Click(object sender, EventArgs e)
   301         {
   302             iDisplay.Fill();
   303             iDisplay.SwapBuffers();
   304         }
   305 
   306         private void trackBarBrightness_Scroll(object sender, EventArgs e)
   307         {
   308             Properties.Settings.Default.DisplayBrightness = trackBarBrightness.Value;
   309             Properties.Settings.Default.Save();
   310             iDisplay.SetBrightness(trackBarBrightness.Value);
   311 
   312         }
   313 
   314         private void UpdateStatus()
   315         {
   316             if (iDisplay.IsOpen())
   317             {
   318                 buttonFill.Enabled = true;
   319                 buttonClear.Enabled = true;
   320                 buttonOpen.Enabled = false;
   321                 buttonClose.Enabled = true;
   322                 trackBarBrightness.Enabled = true;
   323                 trackBarBrightness.Minimum = iDisplay.MinBrightness();
   324                 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
   325                 trackBarBrightness.Value = Properties.Settings.Default.DisplayBrightness;
   326                 trackBarBrightness.LargeChange = Math.Max(1,(iDisplay.MaxBrightness() - iDisplay.MinBrightness())/5);
   327                 trackBarBrightness.SmallChange = 1;
   328                 iDisplay.SetBrightness(Properties.Settings.Default.DisplayBrightness);
   329 
   330                 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
   331                 //+ " - " + iDisplay.SerialNumber();
   332             }
   333             else
   334             {
   335                 buttonFill.Enabled = false;
   336                 buttonClear.Enabled = false;
   337                 buttonOpen.Enabled = true;
   338                 buttonClose.Enabled = false;
   339                 trackBarBrightness.Enabled = false;
   340                 toolStripStatusLabelConnect.Text = "Disconnected";
   341             }
   342         }
   343 
   344 
   345 
   346         private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
   347         {
   348             //Save our show borders setting
   349             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   350             Properties.Settings.Default.DisplayShowBorders = checkBoxShowBorders.Checked;
   351             Properties.Settings.Default.Save();
   352         }
   353 
   354         private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
   355         {
   356             //Save our connect on startup setting
   357             Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
   358             Properties.Settings.Default.Save();
   359         }
   360 
   361         private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
   362         {
   363             //Save our reverse screen setting
   364             Properties.Settings.Default.DisplayReverseScreen = checkBoxReverseScreen.Checked;
   365             Properties.Settings.Default.Save();
   366         }
   367 
   368         private void MainForm_Resize(object sender, EventArgs e)
   369         {
   370             if (WindowState == FormWindowState.Minimized)
   371             {
   372                 // Do some stuff
   373                 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   374                 iCreateBitmap = true;
   375             }
   376         }
   377 
   378         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   379         {
   380             StopServer();
   381             e.Cancel = iClosing;
   382         }
   383 
   384         public void StartServer()
   385         {
   386             iServiceHost = new ServiceHost
   387                 (
   388                     typeof(DisplayServer),
   389                     new Uri[] { new Uri("net.tcp://localhost:8001/") }
   390                 );
   391 
   392             iServiceHost.AddServiceEndpoint(typeof(IDisplayService), new NetTcpBinding(SecurityMode.None,true), "DisplayService");
   393             iServiceHost.Open();
   394         }
   395 
   396         public void StopServer()
   397         {
   398             if (iClients.Count > 0 && !iClosing)
   399             {
   400                 //Tell our clients
   401                 iClosing = true;
   402                 BroadcastCloseEvent();
   403             }
   404             else if (iClosing)
   405             {
   406                 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
   407                 {
   408                     iClosing = false; //We make sure we force close if asked twice
   409                 }
   410             }
   411             else
   412             {                
   413                 //We removed that as it often lags for some reason
   414                 //iServiceHost.Close();
   415             }
   416         }
   417 
   418         public void BroadcastCloseEvent()
   419         {
   420             Trace.TraceInformation("BroadcastCloseEvent - start");
   421 
   422             var inactiveClients = new List<string>();
   423             foreach (var client in iClients)
   424             {
   425                 //if (client.Key != eventData.ClientName)
   426                 {
   427                     try
   428                     {
   429                         Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
   430                         client.Value.Callback.OnCloseOrder(/*eventData*/);
   431                     }
   432                     catch (Exception ex)
   433                     {
   434                         inactiveClients.Add(client.Key);
   435                     }
   436                 }
   437             }
   438 
   439             if (inactiveClients.Count > 0)
   440             {
   441                 foreach (var client in inactiveClients)
   442                 {
   443                     iClients.Remove(client);
   444                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
   445                 }
   446             }
   447         }
   448 
   449         private void buttonStartClient_Click(object sender, EventArgs e)
   450         {
   451             Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
   452             clientThread.Start();
   453         }
   454 
   455         private void buttonSuspend_Click(object sender, EventArgs e)
   456         {
   457             timer.Enabled = !timer.Enabled;
   458             if (!timer.Enabled)
   459             {
   460                 buttonSuspend.Text = "Suspend";
   461             }
   462             else
   463             {
   464                 buttonSuspend.Text = "Pause";
   465             }
   466         }
   467 
   468         private void buttonCloseClients_Click(object sender, EventArgs e)
   469         {
   470             BroadcastCloseEvent();
   471         }
   472 
   473         private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
   474         {
   475 
   476         }
   477 
   478         //Delegates are used for our thread safe method 
   479         public delegate void AddClientDelegate(string aSessionId, IDisplayServiceCallback aCallback);
   480         public delegate void RemoveClientDelegate(string aSessionId);
   481         public delegate void SetTextDelegate(int aLineIndex, string aText);
   482         public delegate void SetTextsDelegate(System.Collections.Generic.IList<string> aTexts);
   483         public delegate void SetClientNameDelegate(string aSessionId, string aName);
   484 
   485        
   486         /// <summary>
   487         /// 
   488         /// </summary>
   489         /// <param name="aSessionId"></param>
   490         /// <param name="aCallback"></param>
   491         public void AddClientThreadSafe(string aSessionId, IDisplayServiceCallback aCallback)
   492         {
   493             if (this.InvokeRequired)
   494             {
   495                 //Not in the proper thread, invoke ourselves
   496                 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
   497                 this.Invoke(d, new object[] { aSessionId, aCallback });
   498             }
   499             else
   500             {
   501                 //We are in the proper thread
   502                 //Add this session to our collection of clients
   503                 ClientData newClient = new ClientData(aSessionId, aCallback);
   504                 Program.iMainForm.iClients.Add(aSessionId, newClient);
   505                 //Add this session to our UI
   506                 UpdateClientTreeViewNode(newClient);
   507             }
   508         }
   509 
   510         /// <summary>
   511         /// 
   512         /// </summary>
   513         /// <param name="aSessionId"></param>
   514         public void RemoveClientThreadSafe(string aSessionId)
   515         {
   516             if (this.InvokeRequired)
   517             {
   518                 //Not in the proper thread, invoke ourselves
   519                 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
   520                 this.Invoke(d, new object[] { aSessionId });
   521             }
   522             else
   523             {
   524                 //We are in the proper thread
   525                 //Remove this session from both client collection and UI tree view
   526                 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
   527                 {
   528                     Program.iMainForm.iClients.Remove(aSessionId);
   529                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
   530                 }
   531 
   532                 if (iClosing && iClients.Count == 0)
   533                 {
   534                     //We were closing our form
   535                     //All clients are now closed
   536                     //Just resume our close operation
   537                     iClosing = false;
   538                     Close();
   539                 }
   540             }
   541         }
   542 
   543         /// <summary>
   544         /// 
   545         /// </summary>
   546         /// <param name="aLineIndex"></param>
   547         /// <param name="aText"></param>
   548         public void SetTextThreadSafe(int aLineIndex, string aText)
   549         {
   550             if (this.InvokeRequired)
   551             {
   552                 //Not in the proper thread, invoke ourselves
   553                 SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
   554                 this.Invoke(d, new object[] { aLineIndex, aText });
   555             }
   556             else
   557             {
   558                 //We are in the proper thread
   559                 //Only support two lines for now
   560                 if (aLineIndex == 0)
   561                 {
   562                     marqueeLabelTop.Text = aText;
   563                 }
   564                 else if (aLineIndex == 1)
   565                 {
   566                     marqueeLabelBottom.Text = aText;
   567                 }
   568             }
   569         }
   570 
   571         /// <summary>
   572         /// 
   573         /// </summary>
   574         /// <param name="aTexts"></param>
   575         public void SetTextsThreadSafe(System.Collections.Generic.IList<string> aTexts)
   576         {
   577             if (this.InvokeRequired)
   578             {
   579                 //Not in the proper thread, invoke ourselves
   580                 SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
   581                 this.Invoke(d, new object[] { aTexts });
   582             }
   583             else
   584             {
   585                 //We are in the proper thread
   586                 //Only support two lines for now
   587                 for (int i = 0; i < aTexts.Count; i++)
   588                 {
   589                     if (i == 0)
   590                     {
   591                         marqueeLabelTop.Text = aTexts[i];
   592                     }
   593                     else if (i == 1)
   594                     {
   595                         marqueeLabelBottom.Text = aTexts[i];
   596                     }
   597                 }
   598             }
   599         }
   600 
   601 
   602         /// <summary>
   603         /// 
   604         /// </summary>
   605         /// <param name="aSessionId"></param>
   606         /// <param name="aName"></param>
   607         public void SetClientNameThreadSafe(string aSessionId, string aName)
   608         {
   609             if (this.InvokeRequired)
   610             {
   611                 //Not in the proper thread, invoke ourselves
   612                 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
   613                 this.Invoke(d, new object[] { aSessionId, aName });
   614             }
   615             else
   616             {
   617                 //We are in the proper thread
   618                 //Get our client
   619                 ClientData client = iClients[aSessionId];
   620                 if (client != null)
   621                 {
   622                     //Set its name
   623                     client.Name = aName;
   624                     //Update our tree-view
   625                     UpdateClientTreeViewNode(client);
   626                 }
   627             }
   628         }
   629 
   630         /// <summary>
   631         /// 
   632         /// </summary>
   633         /// <param name="aClient"></param>
   634         private void UpdateClientTreeViewNode(ClientData aClient)
   635         {
   636             if (aClient == null)
   637             {
   638                 return;
   639             }
   640 
   641             TreeNode node = null;
   642             //Check that our client node already exists
   643             //Get our client root node using its key which is our session ID
   644             TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
   645             if (nodes.Count()>0)
   646             {
   647                 //We already have a node for that client
   648                 node = nodes[0];
   649                 //Clear children as we are going to recreate them below
   650                 node.Nodes.Clear();
   651             }
   652             else
   653             {
   654                 //Client node does not exists create a new one
   655                 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
   656                 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
   657             }
   658 
   659             if (node != null)
   660             {
   661                 //Change its name
   662                 if (aClient.Name != "")
   663                 {
   664                     //We have a name, us it as text for our root node
   665                     node.Text = aClient.Name;
   666                     //Add a child with SessionId
   667                     node.Nodes.Add(new TreeNode(aClient.SessionId));
   668                 }
   669                 else
   670                 {
   671                     //No name, use session ID instead
   672                     node.Text = aClient.SessionId;
   673                 }
   674         
   675                 if (aClient.Texts.Count > 0)
   676                 {
   677                     //Create root node for our texts
   678                     TreeNode textsRoot = new TreeNode("Text");
   679                     node.Nodes.Add(textsRoot);
   680                     //For each text add a new entry
   681                     foreach (string text in aClient.Texts)
   682                     {
   683                         textsRoot.Nodes.Add(new TreeNode(text));
   684                     }
   685                 }
   686             }
   687         }
   688 
   689     }
   690 }