Audio: adding support for mute status.
2 using System.Collections.Generic;
3 using System.ComponentModel;
8 using System.Threading.Tasks;
9 using System.Windows.Forms;
11 using CodeProject.Dialog;
12 using System.Drawing.Imaging;
13 using System.ServiceModel;
14 using System.Threading;
15 using System.Diagnostics;
16 using System.Deployment.Application;
17 using System.Reflection;
19 using NAudio.CoreAudioApi;
20 using NAudio.CoreAudioApi.Interfaces;
21 using System.Runtime.InteropServices;
23 using SharpDisplayClient;
26 namespace SharpDisplayManager
29 public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
30 public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
31 //Delegates are used for our thread safe method
32 public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
33 public delegate void RemoveClientDelegate(string aSessionId);
34 public delegate void SetFieldDelegate(string SessionId, DataField aField);
35 public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList<DataField> aFields);
36 public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
37 public delegate void SetClientNameDelegate(string aSessionId, string aName);
38 public delegate void PlainUpdateDelegate();
42 /// Our Display manager main form
44 public partial class MainForm : Form, IMMNotificationClient
46 DateTime LastTickTime;
48 System.Drawing.Bitmap iBmp;
49 bool iCreateBitmap; //Workaround render to bitmap issues when minimized
50 ServiceHost iServiceHost;
51 // Our collection of clients sorted by session id.
52 public Dictionary<string, ClientData> iClients;
53 // The name of the client which informations are currently displayed.
54 public string iCurrentClientSessionId;
55 ClientData iCurrentClientData;
58 //Function pointer for pixel color filtering
59 ColorProcessingDelegate iColorFx;
60 //Function pointer for pixel X coordinate intercept
61 CoordinateTranslationDelegate iScreenX;
62 //Function pointer for pixel Y coordinate intercept
63 CoordinateTranslationDelegate iScreenY;
65 private MMDeviceEnumerator iMultiMediaDeviceEnumerator;
66 private MMDevice iMultiMediaDevice;
70 /// Manage run when Windows startup option
72 private StartupManager iStartupManager;
77 private NotifyIconAdv iNotifyIcon;
81 iCurrentClientSessionId = "";
82 iCurrentClientData = null;
83 LastTickTime = DateTime.Now;
84 //Instantiate our display and register for events notifications
85 iDisplay = new Display();
86 iDisplay.OnOpened += OnDisplayOpened;
87 iDisplay.OnClosed += OnDisplayClosed;
89 iClients = new Dictionary<string, ClientData>();
90 iStartupManager = new StartupManager();
91 iNotifyIcon = new NotifyIconAdv();
93 //Have our designer initialize its controls
94 InitializeComponent();
96 //Populate device types
97 PopulateDeviceTypes();
99 //Initial status update
102 //We have a bug when drawing minimized and reusing our bitmap
103 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
104 iCreateBitmap = false;
106 //Minimize our window if desired
107 if (Properties.Settings.Default.StartMinimized)
109 WindowState = FormWindowState.Minimized;
117 /// <param name="sender"></param>
118 /// <param name="e"></param>
119 private void MainForm_Load(object sender, EventArgs e)
121 //Check if we are running a Click Once deployed application
122 if (ApplicationDeployment.IsNetworkDeployed)
124 //This is a proper Click Once installation, fetch and show our version number
125 this.Text += " - v" + ApplicationDeployment.CurrentDeployment.CurrentVersion;
129 //Not a proper Click Once installation, assuming development build then
130 this.Text += " - development";
134 iMultiMediaDeviceEnumerator = new MMDeviceEnumerator();
135 iMultiMediaDeviceEnumerator.RegisterEndpointNotificationCallback(this);
137 UpdateAudioDeviceAndMasterVolumeThreadSafe();
139 //Setup notification icon
142 // To make sure start up with minimize to tray works
143 if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
149 //When not debugging we want the screen to be empty until a client takes over
152 //When developing we want at least one client for testing
153 StartNewClient("abcdefghijklmnopqrst-0123456789","ABCDEFGHIJKLMNOPQRST-0123456789");
156 //Open display connection on start-up if needed
157 if (Properties.Settings.Default.DisplayConnectOnStartup)
159 OpenDisplayConnection();
162 //Start our server so that we can get client requests
167 /// Called when our display is opened.
169 /// <param name="aDisplay"></param>
170 private void OnDisplayOpened(Display aDisplay)
172 //Set our screen size now that our display is connected
173 //Our panelDisplay is the container of our tableLayoutPanel
174 //tableLayoutPanel will resize itself to fit the client size of our panelDisplay
175 //panelDisplay needs an extra 2 pixels for borders on each sides
176 //tableLayoutPanel will eventually be the exact size of our display
177 Size size = new Size(iDisplay.WidthInPixels() + 2, iDisplay.HeightInPixels() + 2);
178 panelDisplay.Size = size;
180 //Our display was just opened, update our UI
182 //Initiate asynchronous request
183 iDisplay.RequestFirmwareRevision();
186 UpdateMasterVolumeThreadSafe();
189 //Testing icon in debug, no arm done if icon not supported
190 //iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconRecording, 0, 1);
191 //iDisplay.SetAllIconsStatus(2);
197 /// Called when our display is closed.
199 /// <param name="aDisplay"></param>
200 private void OnDisplayClosed(Display aDisplay)
202 //Our display was just closed, update our UI consequently
207 /// Receive volume change notification and reflect changes on our slider.
209 /// <param name="data"></param>
210 public void OnVolumeNotificationThreadSafe(AudioVolumeNotificationData data)
212 UpdateMasterVolumeThreadSafe();
216 /// Update master volume when user moves our slider.
218 /// <param name="sender"></param>
219 /// <param name="e"></param>
220 private void trackBarMasterVolume_Scroll(object sender, EventArgs e)
222 iMultiMediaDevice.AudioEndpointVolume.MasterVolumeLevelScalar = trackBarMasterVolume.Value / 100.0f;
227 /// Mute check box changed.
229 /// <param name="sender"></param>
230 /// <param name="e"></param>
231 private void checkBoxMute_CheckedChanged(object sender, EventArgs e)
233 iMultiMediaDevice.AudioEndpointVolume.Mute = checkBoxMute.Checked;
238 /// Device State Changed
240 public void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)] string deviceId, [MarshalAs(UnmanagedType.I4)] DeviceState newState){}
245 public void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId) { }
250 public void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)] string deviceId) { }
253 /// Default Device Changed
255 public void OnDefaultDeviceChanged(DataFlow flow, Role role, [MarshalAs(UnmanagedType.LPWStr)] string defaultDeviceId)
257 if (role == Role.Multimedia && flow == DataFlow.Render)
259 UpdateAudioDeviceAndMasterVolumeThreadSafe();
264 /// Property Value Changed
266 /// <param name="pwstrDeviceId"></param>
267 /// <param name="key"></param>
268 public void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId, PropertyKey key){}
276 private void UpdateMasterVolumeThreadSafe()
278 if (this.InvokeRequired)
280 //Not in the proper thread, invoke ourselves
281 PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateMasterVolumeThreadSafe);
282 this.Invoke(d, new object[] { });
286 //Update volume slider
287 float volumeLevelScalar = iMultiMediaDevice.AudioEndpointVolume.MasterVolumeLevelScalar;
288 trackBarMasterVolume.Value = Convert.ToInt32(volumeLevelScalar * 100);
289 //Update mute checkbox
290 checkBoxMute.Checked = iMultiMediaDevice.AudioEndpointVolume.Mute;
292 //TODO: Check our display device too
293 if (iDisplay.IsOpen())
295 int volumeIconCount = iDisplay.IconCount(Display.TMiniDisplayIconType.EMiniDisplayIconVolume);
296 if (volumeIconCount > 0)
298 int currentVolume = Convert.ToInt32(volumeLevelScalar * volumeIconCount);
299 for (int i = 0; i < volumeIconCount; i++)
301 if (i < currentVolume)
303 iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconVolume, i, 10);
307 iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconVolume, i, 0);
312 int muteIconCount = iDisplay.IconCount(Display.TMiniDisplayIconType.EMiniDisplayIconMute);
313 if (muteIconCount > 0)
315 for (int i = 0; i < muteIconCount; i++)
317 if (iMultiMediaDevice.AudioEndpointVolume.Mute)
319 iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconMute, i, 10);
323 iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconMute, i, 0);
335 private void UpdateAudioDeviceAndMasterVolumeThreadSafe()
337 if (this.InvokeRequired)
339 //Not in the proper thread, invoke ourselves
340 PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateAudioDeviceAndMasterVolumeThreadSafe);
341 this.Invoke(d, new object[] { });
345 //We are in the correct thread just go ahead.
348 //Get our master volume
349 iMultiMediaDevice = iMultiMediaDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
350 //Show our volume in our track bar
351 UpdateMasterVolumeThreadSafe();
353 //Register to get volume modifications
354 iMultiMediaDevice.AudioEndpointVolume.OnVolumeNotification += OnVolumeNotificationThreadSafe;
356 trackBarMasterVolume.Enabled = true;
360 Debug.WriteLine("Exception thrown in UpdateAudioDeviceAndMasterVolume");
361 Debug.WriteLine(ex.ToString());
362 //Something went wrong S/PDIF device ca throw exception I guess
363 trackBarMasterVolume.Enabled = false;
370 private void PopulateDeviceTypes()
372 int count = Display.TypeCount();
374 for (int i = 0; i < count; i++)
376 comboBoxDisplayType.Items.Add(Display.TypeName((Display.TMiniDisplayType)i));
383 private void SetupTrayIcon()
385 iNotifyIcon.Icon = GetIcon("vfd.ico");
386 iNotifyIcon.Text = "Sharp Display Manager";
387 iNotifyIcon.Visible = true;
389 //Double click toggles visibility - typically brings up the application
390 iNotifyIcon.DoubleClick += delegate(object obj, EventArgs args)
395 //Adding a context menu, useful to be able to exit the application
396 ContextMenu contextMenu = new ContextMenu();
397 //Context menu item to toggle visibility
398 MenuItem hideShowItem = new MenuItem("Hide/Show");
399 hideShowItem.Click += delegate(object obj, EventArgs args)
403 contextMenu.MenuItems.Add(hideShowItem);
405 //Context menu item separator
406 contextMenu.MenuItems.Add(new MenuItem("-"));
408 //Context menu exit item
409 MenuItem exitItem = new MenuItem("Exit");
410 exitItem.Click += delegate(object obj, EventArgs args)
414 contextMenu.MenuItems.Add(exitItem);
416 iNotifyIcon.ContextMenu = contextMenu;
420 /// Access icons from embedded resources.
422 /// <param name="name"></param>
423 /// <returns></returns>
424 public static Icon GetIcon(string name)
426 name = "SharpDisplayManager.Resources." + name;
429 Assembly.GetExecutingAssembly().GetManifestResourceNames();
430 for (int i = 0; i < names.Length; i++)
432 if (names[i].Replace('\\', '.') == name)
434 using (Stream stream = Assembly.GetExecutingAssembly().
435 GetManifestResourceStream(names[i]))
437 return new Icon(stream);
447 /// Set our current client.
448 /// This will take care of applying our client layout and set data fields.
450 /// <param name="aSessionId"></param>
451 void SetCurrentClient(string aSessionId)
453 if (aSessionId == iCurrentClientSessionId)
455 //Given client is already the current one.
456 //Don't bother changing anything then.
460 //Set current client ID.
461 iCurrentClientSessionId = aSessionId;
462 //Fetch and set current client data.
463 iCurrentClientData = iClients[aSessionId];
464 //Apply layout and set data fields.
465 UpdateTableLayoutPanel(iCurrentClientData);
468 private void buttonFont_Click(object sender, EventArgs e)
470 //fontDialog.ShowColor = true;
471 //fontDialog.ShowApply = true;
472 fontDialog.ShowEffects = true;
473 fontDialog.Font = cds.Font;
475 fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
477 //fontDialog.ShowHelp = true;
479 //fontDlg.MaxSize = 40;
480 //fontDlg.MinSize = 22;
482 //fontDialog.Parent = this;
483 //fontDialog.StartPosition = FormStartPosition.CenterParent;
485 //DlgBox.ShowDialog(fontDialog);
487 //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
488 if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
490 //Set the fonts to all our labels in our layout
491 foreach (Control ctrl in tableLayoutPanel.Controls)
493 if (ctrl is MarqueeLabel)
495 ((MarqueeLabel)ctrl).Font = fontDialog.Font;
500 cds.Font = fontDialog.Font;
501 Properties.Settings.Default.Save();
510 void CheckFontHeight()
512 //Show font height and width
513 labelFontHeight.Text = "Font height: " + cds.Font.Height;
514 float charWidth = IsFixedWidth(cds.Font);
515 if (charWidth == 0.0f)
517 labelFontWidth.Visible = false;
521 labelFontWidth.Visible = true;
522 labelFontWidth.Text = "Font width: " + charWidth;
525 MarqueeLabel label = null;
526 //Get the first label control we can find
527 foreach (Control ctrl in tableLayoutPanel.Controls)
529 if (ctrl is MarqueeLabel)
531 label = (MarqueeLabel)ctrl;
536 //Now check font height and show a warning if needed.
537 if (label != null && label.Font.Height > label.Height)
539 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
540 labelWarning.Visible = true;
544 labelWarning.Visible = false;
549 private void buttonCapture_Click(object sender, EventArgs e)
551 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
552 tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
553 //Bitmap bmpToSave = new Bitmap(bmp);
554 bmp.Save("D:\\capture.png");
556 ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
559 string outputFileName = "d:\\capture.png";
560 using (MemoryStream memory = new MemoryStream())
562 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
564 bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
565 byte[] bytes = memory.ToArray();
566 fs.Write(bytes, 0, bytes.Length);
573 private void CheckForRequestResults()
575 if (iDisplay.IsRequestPending())
577 switch (iDisplay.AttemptRequestCompletion())
579 case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
580 toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
581 //Issue next request then
582 iDisplay.RequestPowerSupplyStatus();
585 case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
586 if (iDisplay.PowerSupplyStatus())
588 toolStripStatusLabelPower.Text = "ON";
592 toolStripStatusLabelPower.Text = "OFF";
594 //Issue next request then
595 iDisplay.RequestDeviceId();
598 case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
599 toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
600 //No more request to issue
606 public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
608 if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
615 public static uint ColorUntouched(int aX, int aY, uint aPixel)
620 public static uint ColorInversed(int aX, int aY, uint aPixel)
625 public static uint ColorChessboard(int aX, int aY, uint aPixel)
627 if ((aX % 2 == 0) && (aY % 2 == 0))
631 else if ((aX % 2 != 0) && (aY % 2 != 0))
639 public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
641 return aBmp.Width - aX - 1;
644 public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
646 return iBmp.Height - aY - 1;
649 public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
654 public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
660 /// Select proper pixel delegates according to our current settings.
662 private void SetupPixelDelegates()
664 //Select our pixel processing routine
665 if (cds.InverseColors)
667 //iColorFx = ColorChessboard;
668 iColorFx = ColorInversed;
672 iColorFx = ColorWhiteIsOn;
675 //Select proper coordinate translation functions
676 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
677 if (cds.ReverseScreen)
679 iScreenX = ScreenReversedX;
680 iScreenY = ScreenReversedY;
690 //This is our timer tick responsible to perform our render
691 private void timer_Tick(object sender, EventArgs e)
693 //Update our animations
694 DateTime NewTickTime = DateTime.Now;
696 //Update animation for all our marquees
697 foreach (Control ctrl in tableLayoutPanel.Controls)
699 if (ctrl is MarqueeLabel)
701 ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
707 if (iDisplay.IsOpen())
709 CheckForRequestResults();
714 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
716 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
717 //iBmp.Save("D:\\capture.png");
719 //Send it to our display
720 for (int i = 0; i < iBmp.Width; i++)
722 for (int j = 0; j < iBmp.Height; j++)
726 //Get our processed pixel coordinates
727 int x = iScreenX(iBmp, i);
728 int y = iScreenY(iBmp, j);
730 uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
731 //Apply color effects
732 color = iColorFx(x,y,color);
734 iDisplay.SetPixel(x, y, color);
739 iDisplay.SwapBuffers();
743 //Compute instant FPS
744 toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
746 LastTickTime = NewTickTime;
751 /// Attempt to establish connection with our display hardware.
753 private void OpenDisplayConnection()
755 CloseDisplayConnection();
757 if (!iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
760 toolStripStatusLabelConnect.Text = "Connection error";
764 private void CloseDisplayConnection()
766 //Status will be updated upon receiving the closed event
770 private void buttonOpen_Click(object sender, EventArgs e)
772 OpenDisplayConnection();
775 private void buttonClose_Click(object sender, EventArgs e)
777 CloseDisplayConnection();
780 private void buttonClear_Click(object sender, EventArgs e)
783 iDisplay.SwapBuffers();
786 private void buttonFill_Click(object sender, EventArgs e)
789 iDisplay.SwapBuffers();
792 private void trackBarBrightness_Scroll(object sender, EventArgs e)
794 cds.Brightness = trackBarBrightness.Value;
795 Properties.Settings.Default.Save();
796 iDisplay.SetBrightness(trackBarBrightness.Value);
802 /// CDS stands for Current Display Settings
804 private DisplaySettings cds
808 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
809 if (settings == null)
811 settings = new DisplaysSettings();
813 Properties.Settings.Default.DisplaysSettings = settings;
816 //Make sure all our settings have been created
817 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
819 settings.Displays.Add(new DisplaySettings());
822 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
823 return displaySettings;
828 /// Check if the given font has a fixed character pitch.
830 /// <param name="ft"></param>
831 /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
832 public float IsFixedWidth(Font ft)
834 Graphics g = CreateGraphics();
835 char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
836 float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
838 bool fixedWidth = true;
840 foreach (char c in charSizes)
841 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
853 /// Synchronize UI with settings
855 private void UpdateStatus()
858 checkBoxShowBorders.Checked = cds.ShowBorders;
859 tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
861 //Set the proper font to each of our labels
862 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
864 ctrl.Font = cds.Font;
868 //Check if "run on Windows startup" is enabled
869 checkBoxAutoStart.Checked = iStartupManager.Startup;
871 checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
872 checkBoxMinimizeToTray.Checked = Properties.Settings.Default.MinimizeToTray;
873 checkBoxStartMinimized.Checked = Properties.Settings.Default.StartMinimized;
874 checkBoxReverseScreen.Checked = cds.ReverseScreen;
875 checkBoxInverseColors.Checked = cds.InverseColors;
876 checkBoxScaleToFit.Checked = cds.ScaleToFit;
877 maskedTextBoxMinFontSize.Enabled = cds.ScaleToFit;
878 labelMinFontSize.Enabled = cds.ScaleToFit;
879 maskedTextBoxMinFontSize.Text = cds.MinFontSize.ToString();
880 maskedTextBoxScrollingSpeed.Text = cds.ScrollingSpeedInPixelsPerSecond.ToString();
881 comboBoxDisplayType.SelectedIndex = cds.DisplayType;
882 timer.Interval = cds.TimerInterval;
883 maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
884 textBoxScrollLoopSeparator.Text = cds.Separator;
886 SetupPixelDelegates();
888 if (iDisplay.IsOpen())
890 //We have a display connection
891 //Reflect that in our UI
893 tableLayoutPanel.Enabled = true;
894 panelDisplay.Enabled = true;
896 //Only setup brightness if display is open
897 trackBarBrightness.Minimum = iDisplay.MinBrightness();
898 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
899 if (cds.Brightness < iDisplay.MinBrightness() || cds.Brightness > iDisplay.MaxBrightness())
901 //Brightness out of range, this can occur when using auto-detect
902 //Use max brightness instead
903 trackBarBrightness.Value = iDisplay.MaxBrightness();
904 iDisplay.SetBrightness(iDisplay.MaxBrightness());
908 trackBarBrightness.Value = cds.Brightness;
909 iDisplay.SetBrightness(cds.Brightness);
912 //Try compute the steps to something that makes sense
913 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
914 trackBarBrightness.SmallChange = 1;
917 buttonFill.Enabled = true;
918 buttonClear.Enabled = true;
919 buttonOpen.Enabled = false;
920 buttonClose.Enabled = true;
921 trackBarBrightness.Enabled = true;
922 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
923 //+ " - " + iDisplay.SerialNumber();
925 if (iDisplay.SupportPowerOnOff())
927 buttonPowerOn.Enabled = true;
928 buttonPowerOff.Enabled = true;
932 buttonPowerOn.Enabled = false;
933 buttonPowerOff.Enabled = false;
936 if (iDisplay.SupportClock())
938 buttonShowClock.Enabled = true;
939 buttonHideClock.Enabled = true;
943 buttonShowClock.Enabled = false;
944 buttonHideClock.Enabled = false;
949 //Display is connection not available
950 //Reflect that in our UI
951 tableLayoutPanel.Enabled = false;
952 panelDisplay.Enabled = false;
953 buttonFill.Enabled = false;
954 buttonClear.Enabled = false;
955 buttonOpen.Enabled = true;
956 buttonClose.Enabled = false;
957 trackBarBrightness.Enabled = false;
958 buttonPowerOn.Enabled = false;
959 buttonPowerOff.Enabled = false;
960 buttonShowClock.Enabled = false;
961 buttonHideClock.Enabled = false;
962 toolStripStatusLabelConnect.Text = "Disconnected";
963 toolStripStatusLabelPower.Text = "N/A";
970 private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
972 //Save our show borders setting
973 tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
974 cds.ShowBorders = checkBoxShowBorders.Checked;
975 Properties.Settings.Default.Save();
979 private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
981 //Save our connect on startup setting
982 Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
983 Properties.Settings.Default.Save();
986 private void checkBoxMinimizeToTray_CheckedChanged(object sender, EventArgs e)
988 //Save our "Minimize to tray" setting
989 Properties.Settings.Default.MinimizeToTray = checkBoxMinimizeToTray.Checked;
990 Properties.Settings.Default.Save();
994 private void checkBoxStartMinimized_CheckedChanged(object sender, EventArgs e)
996 //Save our "Start minimized" setting
997 Properties.Settings.Default.StartMinimized = checkBoxStartMinimized.Checked;
998 Properties.Settings.Default.Save();
1001 private void checkBoxAutoStart_CheckedChanged(object sender, EventArgs e)
1003 iStartupManager.Startup = checkBoxAutoStart.Checked;
1007 private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
1009 //Save our reverse screen setting
1010 cds.ReverseScreen = checkBoxReverseScreen.Checked;
1011 Properties.Settings.Default.Save();
1012 SetupPixelDelegates();
1015 private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
1017 //Save our inverse colors setting
1018 cds.InverseColors = checkBoxInverseColors.Checked;
1019 Properties.Settings.Default.Save();
1020 SetupPixelDelegates();
1023 private void checkBoxScaleToFit_CheckedChanged(object sender, EventArgs e)
1025 //Save our scale to fit setting
1026 cds.ScaleToFit = checkBoxScaleToFit.Checked;
1027 Properties.Settings.Default.Save();
1029 labelMinFontSize.Enabled = cds.ScaleToFit;
1030 maskedTextBoxMinFontSize.Enabled = cds.ScaleToFit;
1033 private void MainForm_Resize(object sender, EventArgs e)
1035 if (WindowState == FormWindowState.Minimized)
1038 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
1039 iCreateBitmap = true;
1043 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
1045 CloseDisplayConnection();
1047 e.Cancel = iClosing;
1050 public void StartServer()
1052 iServiceHost = new ServiceHost
1055 new Uri[] { new Uri("net.tcp://localhost:8001/") }
1058 iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
1059 iServiceHost.Open();
1062 public void StopServer()
1064 if (iClients.Count > 0 && !iClosing)
1068 BroadcastCloseEvent();
1072 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
1074 iClosing = false; //We make sure we force close if asked twice
1079 //We removed that as it often lags for some reason
1080 //iServiceHost.Close();
1084 public void BroadcastCloseEvent()
1086 Trace.TraceInformation("BroadcastCloseEvent - start");
1088 var inactiveClients = new List<string>();
1089 foreach (var client in iClients)
1091 //if (client.Key != eventData.ClientName)
1095 Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
1096 client.Value.Callback.OnCloseOrder(/*eventData*/);
1098 catch (Exception ex)
1100 inactiveClients.Add(client.Key);
1105 if (inactiveClients.Count > 0)
1107 foreach (var client in inactiveClients)
1109 iClients.Remove(client);
1110 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
1114 if (iClients.Count==0)
1121 /// Just remove all our fields.
1123 private void ClearLayout()
1125 tableLayoutPanel.Controls.Clear();
1126 tableLayoutPanel.RowStyles.Clear();
1127 tableLayoutPanel.ColumnStyles.Clear();
1131 /// Just launch a demo client.
1133 private void StartNewClient(string aTopText = "", string aBottomText = "")
1135 Thread clientThread = new Thread(SharpDisplayClient.Program.MainWithParams);
1136 SharpDisplayClient.StartParams myParams = new SharpDisplayClient.StartParams(new Point(this.Right, this.Top),aTopText,aBottomText);
1137 clientThread.Start(myParams);
1141 private void buttonStartClient_Click(object sender, EventArgs e)
1146 private void buttonSuspend_Click(object sender, EventArgs e)
1148 LastTickTime = DateTime.Now; //Reset timer to prevent jump
1149 timer.Enabled = !timer.Enabled;
1152 buttonSuspend.Text = "Run";
1156 buttonSuspend.Text = "Pause";
1160 private void buttonCloseClients_Click(object sender, EventArgs e)
1162 BroadcastCloseEvent();
1165 private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
1174 /// <param name="aSessionId"></param>
1175 /// <param name="aCallback"></param>
1176 public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
1178 if (this.InvokeRequired)
1180 //Not in the proper thread, invoke ourselves
1181 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
1182 this.Invoke(d, new object[] { aSessionId, aCallback });
1186 //We are in the proper thread
1187 //Add this session to our collection of clients
1188 ClientData newClient = new ClientData(aSessionId, aCallback);
1189 Program.iMainForm.iClients.Add(aSessionId, newClient);
1190 //Add this session to our UI
1191 UpdateClientTreeViewNode(newClient);
1198 /// <param name="aSessionId"></param>
1199 public void RemoveClientThreadSafe(string aSessionId)
1201 if (this.InvokeRequired)
1203 //Not in the proper thread, invoke ourselves
1204 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
1205 this.Invoke(d, new object[] { aSessionId });
1209 //We are in the proper thread
1210 //Remove this session from both client collection and UI tree view
1211 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
1213 Program.iMainForm.iClients.Remove(aSessionId);
1214 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
1217 if (iClients.Count == 0)
1219 //Clear our screen when last client disconnects
1224 //We were closing our form
1225 //All clients are now closed
1226 //Just resume our close operation
1237 /// <param name="aSessionId"></param>
1238 /// <param name="aLayout"></param>
1239 public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
1241 if (this.InvokeRequired)
1243 //Not in the proper thread, invoke ourselves
1244 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
1245 this.Invoke(d, new object[] { aSessionId, aLayout });
1249 ClientData client = iClients[aSessionId];
1252 client.Layout = aLayout;
1253 UpdateTableLayoutPanel(client);
1255 UpdateClientTreeViewNode(client);
1263 /// <param name="aSessionId"></param>
1264 /// <param name="aField"></param>
1265 public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
1267 if (this.InvokeRequired)
1269 //Not in the proper thread, invoke ourselves
1270 SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
1271 this.Invoke(d, new object[] { aSessionId, aField });
1275 //We are in the proper thread
1276 //Call the non-thread-safe variant
1277 SetClientField(aSessionId, aField);
1284 /// <param name="aSessionId"></param>
1285 /// <param name="aField"></param>
1286 private void SetClientField(string aSessionId, DataField aField)
1288 SetCurrentClient(aSessionId);
1289 ClientData client = iClients[aSessionId];
1292 bool somethingChanged = false;
1294 //Make sure all our fields are in place
1295 while (client.Fields.Count < (aField.Index + 1))
1297 //Add a text field with proper index
1298 client.Fields.Add(new DataField(client.Fields.Count));
1299 somethingChanged = true;
1302 if (client.Fields[aField.Index].IsSameLayout(aField))
1304 //Same layout just update our field
1305 client.Fields[aField.Index] = aField;
1307 if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
1309 //Text field control already in place, just change the text
1310 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
1311 somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
1312 label.Text = aField.Text;
1313 label.TextAlign = aField.Alignment;
1315 else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
1317 somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
1318 //Bitmap field control already in place just change the bitmap
1319 PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
1320 pictureBox.Image = aField.Bitmap;
1324 somethingChanged = true;
1325 //The requested control in our layout it not of the correct type
1326 //Wrong control type, re-create them all
1327 UpdateTableLayoutPanel(iCurrentClientData);
1332 somethingChanged = true;
1333 //Different layout, need to rebuild it
1334 client.Fields[aField.Index] = aField;
1335 UpdateTableLayoutPanel(iCurrentClientData);
1339 if (somethingChanged)
1341 UpdateClientTreeViewNode(client);
1349 /// <param name="aTexts"></param>
1350 public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
1352 if (this.InvokeRequired)
1354 //Not in the proper thread, invoke ourselves
1355 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
1356 this.Invoke(d, new object[] { aSessionId, aFields });
1360 //Put each our text fields in a label control
1361 foreach (DataField field in aFields)
1363 SetClientField(aSessionId, field);
1371 /// <param name="aSessionId"></param>
1372 /// <param name="aName"></param>
1373 public void SetClientNameThreadSafe(string aSessionId, string aName)
1375 if (this.InvokeRequired)
1377 //Not in the proper thread, invoke ourselves
1378 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
1379 this.Invoke(d, new object[] { aSessionId, aName });
1383 //We are in the proper thread
1385 ClientData client = iClients[aSessionId];
1389 client.Name = aName;
1390 //Update our tree-view
1391 UpdateClientTreeViewNode(client);
1399 /// <param name="aClient"></param>
1400 private void UpdateClientTreeViewNode(ClientData aClient)
1402 if (aClient == null)
1407 TreeNode node = null;
1408 //Check that our client node already exists
1409 //Get our client root node using its key which is our session ID
1410 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
1411 if (nodes.Count()>0)
1413 //We already have a node for that client
1415 //Clear children as we are going to recreate them below
1420 //Client node does not exists create a new one
1421 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
1422 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
1428 if (aClient.Name != "")
1430 //We have a name, us it as text for our root node
1431 node.Text = aClient.Name;
1432 //Add a child with SessionId
1433 node.Nodes.Add(new TreeNode(aClient.SessionId));
1437 //No name, use session ID instead
1438 node.Text = aClient.SessionId;
1441 if (aClient.Fields.Count > 0)
1443 //Create root node for our texts
1444 TreeNode textsRoot = new TreeNode("Fields");
1445 node.Nodes.Add(textsRoot);
1446 //For each text add a new entry
1447 foreach (DataField field in aClient.Fields)
1449 if (!field.IsBitmap)
1451 DataField textField = (DataField)field;
1452 textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
1456 textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
1466 /// Update our table layout row styles to make sure each rows have similar height
1468 private void UpdateTableLayoutRowStyles()
1470 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1472 rowStyle.SizeType = SizeType.Percent;
1473 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1479 /// Empty and recreate our table layout with the given number of columns and rows.
1480 /// Sizes of rows and columns are uniform.
1482 /// <param name="aColumn"></param>
1483 /// <param name="aRow"></param>
1484 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1486 tableLayoutPanel.Controls.Clear();
1487 tableLayoutPanel.RowStyles.Clear();
1488 tableLayoutPanel.ColumnStyles.Clear();
1489 tableLayoutPanel.RowCount = 0;
1490 tableLayoutPanel.ColumnCount = 0;
1492 while (tableLayoutPanel.RowCount < aRow)
1494 tableLayoutPanel.RowCount++;
1497 while (tableLayoutPanel.ColumnCount < aColumn)
1499 tableLayoutPanel.ColumnCount++;
1502 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1504 //Create our column styles
1505 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1507 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1511 //Create our row styles
1512 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1515 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1516 control.AutoEllipsis = true;
1517 control.AutoSize = true;
1518 control.BackColor = System.Drawing.Color.Transparent;
1519 control.Dock = System.Windows.Forms.DockStyle.Fill;
1520 control.Location = new System.Drawing.Point(1, 1);
1521 control.Margin = new System.Windows.Forms.Padding(0);
1522 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1523 control.OwnTimer = false;
1524 control.PixelsPerSecond = 64;
1525 control.Separator = cds.Separator;
1526 control.MinFontSize = cds.MinFontSize;
1527 control.ScaleToFit = cds.ScaleToFit;
1528 //control.Size = new System.Drawing.Size(254, 30);
1529 //control.TabIndex = 2;
1530 control.Font = cds.Font;
1531 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1532 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1533 control.UseCompatibleTextRendering = true;
1535 tableLayoutPanel.Controls.Add(control, i, j);
1544 /// Update our display table layout.
1546 /// <param name="aLayout"></param>
1547 private void UpdateTableLayoutPanel(ClientData aClient)
1549 if (aClient == null)
1556 TableLayout layout = aClient.Layout;
1559 tableLayoutPanel.Controls.Clear();
1560 tableLayoutPanel.RowStyles.Clear();
1561 tableLayoutPanel.ColumnStyles.Clear();
1562 tableLayoutPanel.RowCount = 0;
1563 tableLayoutPanel.ColumnCount = 0;
1565 while (tableLayoutPanel.RowCount < layout.Rows.Count)
1567 tableLayoutPanel.RowCount++;
1570 while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
1572 tableLayoutPanel.ColumnCount++;
1575 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1577 //Create our column styles
1578 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
1580 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1584 //Create our row styles
1585 this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
1588 //Check if we already have a control
1589 Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
1590 if (existingControl!=null)
1592 //We already have a control in that cell as a results of row/col spanning
1593 //Move on to next cell then
1599 //Check if a client field already exists for that cell
1600 if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
1602 //No client field specified, create a text field by default
1603 aClient.Fields.Add(new DataField(aClient.Fields.Count));
1606 //Create a control corresponding to the field specified for that cell
1607 DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
1608 Control control = CreateControlForDataField(field);
1610 //Add newly created control to our table layout at the specified row and column
1611 tableLayoutPanel.Controls.Add(control, i, j);
1612 //Make sure we specify row and column span for that new control
1613 tableLayoutPanel.SetRowSpan(control,field.RowSpan);
1614 tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
1619 while (aClient.Fields.Count > fieldCount)
1621 //We have too much fields for this layout
1622 //Just discard them until we get there
1623 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
1630 /// Check our type of data field and create corresponding control
1632 /// <param name="aField"></param>
1633 private Control CreateControlForDataField(DataField aField)
1635 Control control=null;
1636 if (!aField.IsBitmap)
1638 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
1639 label.AutoEllipsis = true;
1640 label.AutoSize = true;
1641 label.BackColor = System.Drawing.Color.Transparent;
1642 label.Dock = System.Windows.Forms.DockStyle.Fill;
1643 label.Location = new System.Drawing.Point(1, 1);
1644 label.Margin = new System.Windows.Forms.Padding(0);
1645 label.Name = "marqueeLabel" + aField.Index;
1646 label.OwnTimer = false;
1647 label.PixelsPerSecond = cds.ScrollingSpeedInPixelsPerSecond;
1648 label.Separator = cds.Separator;
1649 label.MinFontSize = cds.MinFontSize;
1650 label.ScaleToFit = cds.ScaleToFit;
1651 //control.Size = new System.Drawing.Size(254, 30);
1652 //control.TabIndex = 2;
1653 label.Font = cds.Font;
1655 label.TextAlign = aField.Alignment;
1656 label.UseCompatibleTextRendering = true;
1657 label.Text = aField.Text;
1663 //Create picture box
1664 PictureBox picture = new PictureBox();
1665 picture.AutoSize = true;
1666 picture.BackColor = System.Drawing.Color.Transparent;
1667 picture.Dock = System.Windows.Forms.DockStyle.Fill;
1668 picture.Location = new System.Drawing.Point(1, 1);
1669 picture.Margin = new System.Windows.Forms.Padding(0);
1670 picture.Name = "pictureBox" + aField;
1672 picture.Image = aField.Bitmap;
1681 /// Called when the user selected a new display type.
1683 /// <param name="sender"></param>
1684 /// <param name="e"></param>
1685 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1687 //Store the selected display type in our settings
1688 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1689 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1690 Properties.Settings.Default.Save();
1692 //Try re-opening the display connection if we were already connected.
1693 //Otherwise just update our status to reflect display type change.
1694 if (iDisplay.IsOpen())
1696 OpenDisplayConnection();
1704 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1706 if (maskedTextBoxTimerInterval.Text != "")
1708 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1712 timer.Interval = interval;
1713 cds.TimerInterval = timer.Interval;
1714 Properties.Settings.Default.Save();
1719 private void maskedTextBoxMinFontSize_TextChanged(object sender, EventArgs e)
1721 if (maskedTextBoxMinFontSize.Text != "")
1723 int minFontSize = Convert.ToInt32(maskedTextBoxMinFontSize.Text);
1725 if (minFontSize > 0)
1727 cds.MinFontSize = minFontSize;
1728 Properties.Settings.Default.Save();
1729 //We need to recreate our layout for that change to take effect
1730 UpdateTableLayoutPanel(iCurrentClientData);
1736 private void maskedTextBoxScrollingSpeed_TextChanged(object sender, EventArgs e)
1738 if (maskedTextBoxScrollingSpeed.Text != "")
1740 int scrollingSpeed = Convert.ToInt32(maskedTextBoxScrollingSpeed.Text);
1742 if (scrollingSpeed > 0)
1744 cds.ScrollingSpeedInPixelsPerSecond = scrollingSpeed;
1745 Properties.Settings.Default.Save();
1746 //We need to recreate our layout for that change to take effect
1747 UpdateTableLayoutPanel(iCurrentClientData);
1752 private void textBoxScrollLoopSeparator_TextChanged(object sender, EventArgs e)
1754 cds.Separator = textBoxScrollLoopSeparator.Text;
1755 Properties.Settings.Default.Save();
1757 //Update our text fields
1758 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1760 ctrl.Separator = cds.Separator;
1765 private void buttonPowerOn_Click(object sender, EventArgs e)
1770 private void buttonPowerOff_Click(object sender, EventArgs e)
1772 iDisplay.PowerOff();
1775 private void buttonShowClock_Click(object sender, EventArgs e)
1777 iDisplay.ShowClock();
1780 private void buttonHideClock_Click(object sender, EventArgs e)
1782 iDisplay.HideClock();
1785 private void buttonUpdate_Click(object sender, EventArgs e)
1787 InstallUpdateSyncWithInfo();
1791 private void InstallUpdateSyncWithInfo()
1793 UpdateCheckInfo info = null;
1795 if (ApplicationDeployment.IsNetworkDeployed)
1797 ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
1801 info = ad.CheckForDetailedUpdate();
1804 catch (DeploymentDownloadException dde)
1806 MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
1809 catch (InvalidDeploymentException ide)
1811 MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
1814 catch (InvalidOperationException ioe)
1816 MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
1820 if (info.UpdateAvailable)
1822 Boolean doUpdate = true;
1824 if (!info.IsUpdateRequired)
1826 DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
1827 if (!(DialogResult.OK == dr))
1834 // Display a message that the app MUST reboot. Display the minimum required version.
1835 MessageBox.Show("This application has detected a mandatory update from your current " +
1836 "version to version " + info.MinimumRequiredVersion.ToString() +
1837 ". The application will now install the update and restart.",
1838 "Update Available", MessageBoxButtons.OK,
1839 MessageBoxIcon.Information);
1847 MessageBox.Show("The application has been upgraded, and will now restart.");
1848 Application.Restart();
1850 catch (DeploymentDownloadException dde)
1852 MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
1859 MessageBox.Show("You are already running the latest version.", "Application up-to-date");
1868 private void SysTrayHideShow()
1874 WindowState = FormWindowState.Normal;
1879 /// Use to handle minimize events.
1881 /// <param name="sender"></param>
1882 /// <param name="e"></param>
1883 private void MainForm_SizeChanged(object sender, EventArgs e)
1885 if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
1898 /// <param name="sender"></param>
1899 /// <param name="e"></param>
1900 private void tableLayoutPanel_SizeChanged(object sender, EventArgs e)
1902 //Our table layout size has changed which means our display size has changed.
1903 //We need to re-create our bitmap.
1904 iCreateBitmap = true;
1910 /// A UI thread copy of a client relevant data.
1911 /// Keeping this copy in the UI thread helps us deal with threading issues.
1913 public class ClientData
1915 public ClientData(string aSessionId, ICallback aCallback)
1917 SessionId = aSessionId;
1919 Fields = new List<DataField>();
1920 Layout = new TableLayout(1, 2); //Default to one column and two rows
1921 Callback = aCallback;
1924 public string SessionId { get; set; }
1925 public string Name { get; set; }
1926 public List<DataField> Fields { get; set; }
1927 public TableLayout Layout { get; set; }
1928 public ICallback Callback { get; set; }