Category: Programming


QuizWithMates.com


Update: 19/09/2021 – Website is now offline.

I built this website due to the recent popularity of online quizzes, or ‘zoom quizzes’. I noticed that the collection of answers/marking of answers ws often a little clunky. One extreme example answer I saw was to send answers to the quizmaster by textmessage/whatsapp! All of which was unnecessary overhead, not to mention quite a lot of work for the host. I saw a need for a smoother way of organizing online quizzes, specifically submitting/collection answers, QuizWithMates.com was born.

More info can be found on the websites about page.

Some Screenshots:

1.Creating a Quiz

2. Quiz Players – Answer question

3. Quiz Host – Realtime Answers

4. Answer Marking/Review

5. Results


Stock market desktop ticker .NET application


Quick Links:

Requires .net framework 4.5 or greater

Summary:

I wanted to see how my stocks are doing periodically at a glance on my windows desktop computer throughout the day. I want a small popup that appears in the bottom right hand corner of the screen semi-frequently, which will show me the daily percentage increase/decrease of the stock.

Basic Requirements:

Behavior:

There should be a small popup in the bottom right hand corner of the screen every X seconds ( seconds are configurable ).
The small popup should list all of the stocks configured that the application is ‘watching’ and display the daily gain/loss in a percentage format.
The small popup should stay present for X seconds ( configurable ).
The list of stocks within the popup will be listed and the text will be white, the percentage gain/loss for the day will be green if positive, white if 0% and red if negative on the day.
The application can be configured to only popup within the US stock markets hours of operation ( taking into account that I live in the UK, also taking into account daylight savings time etc if need be ).
It is possible to ‘force’ the pop-up to show on an off-frequency ( upon a user request to show the popup ).
The popup will have a small X to close the popup forcefully in the top right hand corner.
The background of the pop-up will be black

UI Design template – what it could look like:

( edit/update, the above screenshot changed from the actual implementation, the main difference being the market the stock is listed on e.g. NYSE was omitted from the final implementation )

Environment/Setup:

The application should come with an installer.
The application should not use a database.
The application should reside in the task tray with a small icon.
The application should open a configuration menu when the task tray icon is double clicked.
The application should open a small pop-up menu within the task tray when the icon is right clicked the menu will have : [Open Config]; [Show Prices Now]; [Exit Application] as the menu items.
Application must start on startup of windows ( preferably via start-up folder shortcut )

Configuration:

The user will be able to add stock to watch within the config ( list ).
The stock to watch will be the official ticker abbreviation from either NASDAQ or NYSE ( only ).
The user can configure the frequency of the pop-up.
The user can configure the duration of the pop-up.

Implementation/Tutorial:

Requirements:

  • Visual studio ( I use 2017 )

General solution creation:

To start with, create a standard windows forms application ( Visual C# -> Windows Desktop -> Windows Forms App (.NET Framework ) in visual studio. Set the Framework version to target anything higher ( or equal to ) .NET Framework 4.5 ( I used 4.5 ). Call the project StockMarketPopupTickerApplication .

The default form Form1.cs  which is shown when the project is created will be our the ‘config page’ of our application, so when a user double clicks the task tray icon, the config page will show. Closing the config page will not close the application.

Setting Default Properties of Form1.cs

We need to enable this form to minimise to task tray first at load, within Form1.cs  change the WindowState  property to default to Minimized .

Adding a task tray functionality

We want the application to largely reside within the task tray ( bottom right hand corner of the screen ) so we need to find a suitable icon, and attach it to the application. I used https://www.iconfinder.com/ to find a suitable icon and I found this one:

At the following address: https://www.iconfinder.com/icons/87472/market_stock_icon

Download the file as a ICO file

Once you have downloaded your .ICO icon file, we need to attach it to the application. We will attach it to Form1.cs  via the designer by adding a NotifyIcon  within the designer toolbox:

Dragging and dropping the NotifyIcon  into the designer for Form1.cs  adds the component to the application.

Once the NotifyIcon  has been added to the designer, select the notifyIcon1 and attach the recently downloaded Icon file, you do this by clicking on the notifyIcon1  at the bottom of the Form1.csForm1.cs  Designer window, then within the properties panel on the right press the ‘…’ button on the Icon property, and browse to the file you recently downloaded:

We also need to include the icon file into our project for later use. Right click the StockMarketPopupTickerApplication  project ( project, not the solution ) and select Add -> Existing item.

Within the browse dialog box we need to find and select our icon file ( the one that was just downloaded ), remember to change the File filters within the browse dialog box, by default it will not show .ico files.

You’ll see that the icon file you have downloaded has been added into the project files appears in the list:

This stage is important, at later on within the installer section, we will need this icon file attached to the project.

Change the icon text within the notifyIcon1  properties panel to something better than “notifyIcon1” change it to “Stock market watcher” or something like that. This Text is what is shown when you hover over the icon within the task bar, so name it something human readable.

We also need to setup the context menu – which is the menu that will appear when the task tray icon is clicked in the bottom right hand corner, we need it to show the options:  [Open Config]; [Show Prices Now]; [Exit Application]. Do this by adding a ContextMenuStrip  to the Form1.cs  just like you did the NotifyIcon  ( drag and drop onto the designer ):

Once added, select the contextMenuStrip1  and from within the properties window, find and edit the “Items” property by clicking the “…” button:

A new configuration window will popup, this allows you to add the Menu Items to your context menu. We need three, so add three MenuItem , give them decent names, and also give them a meaningful Text display:

We now need to attach events to each of these Menu items, this can be accomplished by code, or by using some of the designer. I chose to use the designer. If you click on the contextMenuStrip1  at the bottom of the Form1.cs  designer, a preview of the ContextMenuStrip  will show within the designer:

You will see the context menu appear on the main form

If you now single click on each of your menu items, the properties panel will show the properties of each of the MenuItems , here is where we can add OnClick  events:

Select the events properties tab ( the lightning arrow within the properties window ) and double click in the white space next to the “Click” event. This will create an empty placeholder handler of the button being pressed. Something we will handle in the following section.

View within Form1.cs

View within properties designer showing event binding:

Repeat this process for each of the three MenuItem  buttons

Which should result in empty code handlers which look like this: ( dependant upon what you called your Menu Items ):

Finally, we need to attach the context menu that we have just built to the notifyIcon1 . Click on the notifyIcon1  within the designer.

And bind the ContextMenuStrip to the notifyIcon1:

If you run your application now, you’ll see your application begin minimised within the system tray, with an icon, which when right clicked will display the three menu items you configured earlier:

Unfortunately, within the task bar, an application icon also appears, which is what we do not want:

To get rid of this change ShowInTaskBar  to False  for Form1.cs within the designer:

You can also see I have added an Application Icon ( not to be confused with notification icon ) – which I used the same icon as before ( mentioned previously ). I also changed MaximizeBox  and MinimizeBox  to False , this is so that the settings configuration window doesn’t have a minimise/maximise buttons, which are not needed, I wanted my config window to be a static size.

You can also change the config forms default title to something more appropriate, within Form1  properties ( from the designer) set the Text field:

Which should make the designer title look like this:

If you run your application now, you will see that it has no task bar icon. It has a task tray icon that when right clicked shows three menu items. The application doesn’t do too much after this. We need to be able to restore at least the config window, so we need to hook up the “Open Config” menu item, and also the double click on system tray icon, which should maximise the config window so that we could change settings ( which we are yet to add ).

Adding listener actions to task tray icon

Firstly we can restore the configuration window to a maximized state by attaching a listener to the notify icon double click event.

Attach the event by double clicking the white space within the events list of notifyIcon1:

Within the double click handler, alter the method so that it looks like this:

private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
	if(this.WindowState == FormWindowState.Minimized)
	{
		this.WindowState = FormWindowState.Normal;
	}
}

Add a listener to the window state changing ( we don’t want it to show in task bar unless the control config box is open ).

Add a SizeChanged  event handler ( same process as before )

Form Size changed event:

Alter the handler code so that it looks like this:

private void Form1_SizeChanged(object sender, EventArgs e)
{
	if (this.WindowState == FormWindowState.Minimized)
	{
		this.ShowInTaskbar = false;
	}
	else
	{
		this.ShowInTaskbar = true;
	}
}

Finally we need to override the Form1.cs  closing event:

We want the application to remin open ( in the task tray ) even when the application configuration dialog box is closed via pressing ‘X’. The only way that we want the application to fully close is from the task tray icon being right clicked, and choosing ‘Exit’. To handle this we use a class variable for the application to signify when the ‘Exit’ menu item selection has been selected, all other ways of closing the main settings form will not exit the application.

Add the class variable to Form1:

...
public partial class Form1 : Form
    {
        private bool closeFromNotifcationTray = false;
...

Now from within the FormClosing handler for Form1, alter it to this:

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(closeFromNotifcationTray == true)
            {
                // Allow the close to happen, 
            }
            else
            {
                // Not closed from Exit button in notification tray, so just minimize.
                this.WindowState = FormWindowState.Minimized;
                e.Cancel = true;
            }
        }

Now we should adjust the task tray ‘exit’ button handler to set the closeFromNotiifcaionTray  to true:

        private void exitStripMenuItem_Click(object sender, EventArgs e)
        {
            closeFromNotifcationTray = true;
            Application.Exit();
        }

If you build and run the application now, you will see that the following functionality is available:

  • Upon start, the application is minimised to task tray
  • When task tray icon is double clicked, form1  form shows ( nothing useful shows on the form at the moment )
  • When the form1  form is in the foreground ( shown ), the application icon appears in the task bar ( task bar, not just the task tray ) with the selected application icon
  • When form1  form is closed ( X in top right hand corner ), it minimised to system tray ( not exists application ).
  • Three menu items show when icon in task tray is right clicked
  • Upon clicking Exit, the application fully exits

We can now hook up one of the other task tray icon buttons ‘Open Config’, add the following code tot he openConfigStripMenu on Click event ( or whatever you called your ‘Open’ button ):

        private void openConfigStripMenu_Click(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.WindowState = FormWindowState.Normal;
            }
        }

The Show Prices Menu item we will hook up later.

Config/Settings dialog

Ok, so now it’s time to add some config to the home dialog box which is form1.cs .

We will need to add three main controls/areas of functionality

  • List controlling the stock tickers that we want to poll for/show
  • The frequency and duration of the popup
  • The option to select if stocks only popup during market opening hours

I won’t explain the full procedure for creating this dialog box and arrangement of controls, I’ll assume you are comfortable in doing so, the target structure of the UI settings config form is show below:

Here is a table of the controls that I added to the desginer

Control type Control variable name
ListBox watchedStockList
Button removeStockButton
Button addStockButton
TextBox addStockTextBox
NumericUpDown popupFreqNUD
NumericUpDown popupDurNUD
CheckBox tradingHoursCheckbox
4x Label 4x labels to help label some of the controls

After adding the controls, and fashioning them in a way which is to your liking, we need to resize the main Form control to be a bit more size appropriate, drag and resize the main form so it fits using the designer.

Then set the form size to be an exact size with no re-size ability within the Form properties:

Change FormBorderSize  to FixedSingle

This will stop the form from being re-sizeable at run time.

Also change both NumericUpDown  controls to have a higher than default maximum. By default these NUD controls will go to a maximum of 100. Given that we are dealing in seconds, it should be a much higher value. ( One every hour would be 3600 seconds, so a max of 3600 seems appropriate for the popupFreqNUD ).

At the moment most of these controls have no events hooked up to them, this is intentional, we will hook these controls up to event handlers in the next section.

Settings Storage ( object for view ):

I want the storage configurations ( such as stocks watched ) to be saved into a persistent storage object so that on each application load, the user doesn’t have to re-configure the application. In order to do this, I firstly need to create a store config class object that I can easily serialise to disk. We will serialize a config object to a file on desk within the executing directory called settingsConfig.xml

Create the following class within your project:

    public class ConfigSettingsObject
    {
        public List<string> watchedStock { get; set; }
        public int popupFrequencySeconds { get; set; }
        public int popupDurationSeconds { get; set; }
        public bool onlyPopupDuringTradingHours { get; set; }
    }

This is the object we will store all the settings in and is to be populated on startup and upon each settings change.

Add the following object to the Form1  class:

private ConfigSettingsObject settings;

Within Form1  create some serializer methods which allow you to save/read these config settings:

Create serializer and deserializer methods to serialize to disk.

        public void SerializeObject<T>(T serializableObject, string fileName)
        {
            if (serializableObject == null) { return; }

            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
                using (MemoryStream stream = new MemoryStream())
                {
                    serializer.Serialize(stream, serializableObject);
                    stream.Position = 0;
                    xmlDocument.Load(stream);
                    xmlDocument.Save(fileName);
                    stream.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Problem with Saving settings to disk: " + ex.Message);
            }
        }

        public T DeSerializeObject<T>(string fileName)
        {
            if (string.IsNullOrEmpty(fileName)) { return default(T); }

            T objectOut = default(T);

            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load(fileName);
                string xmlString = xmlDocument.OuterXml;

                using (StringReader read = new StringReader(xmlString))
                {
                    Type outType = typeof(T);

                    XmlSerializer serializer = new XmlSerializer(outType);
                    using (XmlReader reader = new XmlTextReader(read))
                    {
                        objectOut = (T)serializer.Deserialize(reader);
                        reader.Close();
                    }

                    read.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Problem with opening settings from disk: " + ex.Message + " try deleting the settingsConfig.xml file");
            }
 
            return objectOut;
        }

Note: Upon adding this code, you’ll need to add using statement references for:

System.Xml , System.Xml.Serialization  and System.IO

Within Form1  add a load settings info config method called LoadSettingsIntoConfigForm  with the following method body:

        private void LoadSettingsIntoConfigForm()
        {
            this.popupDurNUD.Value = settings.popupDurationSeconds;
            this.popupFreqNUD.Value = settings.popupFrequencySeconds;
            this.tradingHoursCheckbox.Checked = settings.onlyPopupDuringTradingHours;
            this.addStockTextBox.Text = "";
            this.watchedStockList.Items.AddRange(settings.watchedStock.ToArray());
        }

Now create a method within Form1  to load the settings from from the .xml file we will store on disk

 private void LoadSettingsFromFile()
        {
            if(File.Exists("settingsConfig.xml"))
            {
                settings = DeSerializeObject<ConfigSettingsObject>("settingsConfig.xml");
            }
            else
            {
                // No settings config exists, so we will populate the settings with some default values
                settings = new ConfigSettingsObject();
                settings.onlyPopupDuringTradingHours = false;
                settings.popupDurationSeconds = 5;
                settings.popupFrequencySeconds = 60;
                settings.watchedStock = new List<string>() { "AAPL","TWTR" };
                SaveSettingsToFile();
            }
            // Now we have the settings file, we can have it load the settings into the config form.
            LoadSettingsIntoConfigForm();
        }

You’ll see that within this method there is reference to a method called SaveSettingsToFile() , we need to create this method now:

        private void SaveSettingsToFile()
        {
            SerializeObject(settings, "settingsConfig.xml");
        }

We now have the basic load/save settings functionality made, we finally need to add the LoadSettingsFromFile()  into the Form1_Load

Within the Form1.cs designer double click the Load event, which will add the Form1_Load event handler to the code behind:

Alter the Form1_Load  event to call the LoadSettingsFromFile()  method:

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadSettingsFromFile();
        }

You should now be able to build and run your application, which will result in a settingsConfig.xml  file being created within the application executing directory ( ..\StockMarketPopupTickerApplication\StockMarketPopupTickerApplication\bin\Debug  in my case ).

If you have a look at the XML file created ( open in notepad++ for example ), you’ll see the basic structure of the object with the default values I hard coded into the application:

<?xml version="1.0"?>
<ConfigSettingsObject xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <watchedStock>
    <string>AAPL</string>
    <string>TWTR</string>
  </watchedStock>
  <popupFrequencySeconds>60</popupFrequencySeconds>
  <popupDurationSeconds>5</popupDurationSeconds>
  <onlyPopupDuringTradingHours>false</onlyPopupDuringTradingHours>
</ConfigSettingsObject>

You’ll see AAPL and TWTR ( Apple and Twitter ) in the XML. Now you can check that the application configuration page has these matching values within it. Run the application, and double click the task tray icon to show the settings dialog box to verify that the default values have been populated into the settings controls:

Now we need to attach change values to the boxes, – note, usually you can do this via the designer route ( by attaching an event to the properties of the NUD box within the Designer – properties window ), or you can manually code the events to be attached at runtime. In this example, we need to have them attached at runtime by code, and not within the form1.cs  file, this is to stop an infinite loop.

Explanation: upon load of the form, an event is added to the NUD ( Numeric Up Down controls ) which fires upon change. Also upon load, we are going to populate the value of the NUD, so what will happen is the ‘changed event’ will fire upon loading the saved settings value, which is not strictly true, nothing has ‘changed; from the user, so we only want these events to fire after the NUD values have been loaded ( from saved values file ).

I have an AttachListeners  method within Form1.cs , which is called after the LoadSettingsFromFile  method is called. Create this method:

        // We don't want the listeners firing whilst we are loading settings
        // so we attach the listeners AFTER the load of the values from settings
        private void AttachListeners()
        {
            this.popupFreqNUD.ValueChanged += new System.EventHandler(this.popupFreqNUD_ValueChanged);
            this.tradingHoursCheckbox.CheckedChanged += new System.EventHandler(this.tradingHoursCheckbox_CheckedChanged);
            this.popupDurNUD.ValueChanged += new System.EventHandler(this.popupDurNUD_ValueChanged);
        }

The three event method handlers will currently not exist, we will create them soon.

The functionality I want is to save the settings configured by the user to file on every configuration control change we do this by calling the previously created SaveSettingsToFile  method that we created earlier.

We now need to add the three missing listeners, two NUD listeners, and one checkbox changed listener:

  private void popupFreqNUD_ValueChanged(object sender, EventArgs e)
        {
            settings.popupFrequencySeconds = Convert.ToInt32(popupFreqNUD.Value);
            SaveSettingsToFile();
        }

        private void popupDurNUD_ValueChanged(object sender, EventArgs e)
        {
            settings.popupDurationSeconds = Convert.ToInt32(popupDurNUD.Value);
            SaveSettingsToFile();
        }

        private void tradingHoursCheckbox_CheckedChanged(object sender, EventArgs e)
        {
            settings.onlyPopupDuringTradingHours = tradingHoursCheckbox.Checked;
            SaveSettingsToFile();
        }

Finally call the AttachListeners()  method from within the Form1_Load()  method:

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadSettingsFromFile();
            AttachListeners();
        }

You can now test your application by running it, and making sure that the changes you make to the two NUD and Checkboxes save to disk.

Adding/removing stock controls

Now it’s time to hook up the add/remove stock to watch control and have the list show the stocks we are watching. We need an add, remove, and re-draw method.

The re-draw method is called every time the back-end object ( in settings ) changes.

Add an ‘on-Click’ event to the remove and add buttons ( I used the designer and properties events box for this ), no need to have these in the AttachListeners()  setup method:

        private void removeStockButton_Click(object sender, EventArgs e)
        {
            if (this.watchedStockList.SelectedItem != null)
            {
                string stockToRemove = this.watchedStockList.SelectedItem.ToString();
                if(settings.watchedStock.IndexOf(stockToRemove) >= -1)
                {
                    settings.watchedStock.Remove(stockToRemove);
                    SaveSettingsToFile();
                    DrawListBasedOnStock();
                }
            }
        }

        private void addStockButton_Click(object sender, EventArgs e)
        {
            if(String.IsNullOrEmpty(this.addStockTextBox.Text) == false)
            {
                string stockToAdd = this.addStockTextBox.Text;
                if (settings.watchedStock.IndexOf(stockToAdd) >= 0)
                {
                    // Already added
                }
                else
                {
                    settings.watchedStock.Add(stockToAdd);
                    this.addStockTextBox.Text = "";
                    SaveSettingsToFile();
                    DrawListBasedOnStock();
                }
            }
        }

Then add the Referencing DrawListBasedOnStock():

        private void DrawListBasedOnStock()
        {
            this.watchedStockList.Items.Clear();
            this.watchedStockList.Items.AddRange(settings.watchedStock.ToArray());
        }

Right now, if you run your application, the config page should be all hooked up, and any changes you make to the config, should be saved back to disk. To test this, run the application, change some values, close the application, then run it again. The values should be updated.

Example:

Building the code to get prices:

Third party service selection:

For the purposes of this project, after a couple of Google searches, it seemed that a service called AlphaVantage was a suitable candidate to be able to get the stock prices from (https://www.alphavantage.co/) however after I had a play with this API, it was not clear ( or possible ) to obtain the data I wanted – I do not believe that it provides an intra-day percentage from the market opening. All I could find was an intra-day range of 60 minutes, and not the whole day. Having dug around a little bit into the responses that the API returned, I saw that within the AlphaAdvantage response data that it actually used a provider called IEX, so I decided to take a look at the IEX exchange as a stock market price provider

https://iextrading.com/developer/

Reading through their API, it seems to allow me to query one stock and get the real time percentage change of a stock.

Update: As of June 1st 2019, the original iextrading API is no longer available, they have moved to iexcloud ( which is still free, you just need to sign up ):

https://iexcloud.io/

Some of the below may be out of date, but the changes have been included in the source repository within GIT.

Querying the IEX API programmatically:

Now that we have selected an ideal API to query from, we need to build some code which can query each stock and extract the percentage from the response.

Setup a static new class to help with the calls to the IEX API:

Note: NuGet package Newtonsoft.Json  should be installed for this to work:

Install-Package Newtonsoft.Json

Create a new class IEXHelper.cs

IEX Helper Class for querying stock prices:

    public static class IEXHelper
    {
        private const string IEXURL = "https://api.iextrading.com/1.0/";
        /// <summary>
        /// returns a percentage ( as Decimal ) for a stock ticker
        /// </summary>
        /// <param name="symbol"></param>
        /// <returns></returns>
        public static decimal GetPercentageForStock(string symbol)
        {
            decimal toReturn = -1;
            // Build query to call against API:
            string paramaters = $"stock/{symbol}/quote?displayPercent=true";
            string objectAsString = APICall(paramaters);

            var data = (JObject)JsonConvert.DeserializeObject(objectAsString);
            toReturn = data["changePercent"].Value<Decimal>();

            return toReturn;
        }

        /// <summary>
        /// https://stackoverflow.com/questions/9620278/how-do-i-make-calls-to-a-rest-api-using-c
        /// </summary>
        /// <param name="paramaters"></param>
        /// <returns></returns>
        private static string APICall(string paramaters)
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(IEXURL);

            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            // List data response.
            HttpResponseMessage response = client.GetAsync(paramaters).Result;  // Blocking call!
            if (response.IsSuccessStatusCode)
            {
                // Parse the response body. Blocking!
                return response.Content.ReadAsStringAsync().Result;
            }
            else
            {
                throw new Exception("Invalid status response: " + response.StatusCode);
            }
        }
    }

You will need to make sure that your project already has the System.Net.Http assembly already added into the project ( .net 4.5 by default includes this assembly reference ):

If not, you can easily add reference to the assembly:

Within IEXHelper.cs  you will need to add references to the following namespaces within this file:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http;
using System.Net.Http.Headers;

Test project to test IEXHelper class:

I also quickly created a test project ( new Project -> Visual C# -> Test -> Unit Test Project ) to test these methods whilst developing code ( this is optional ):

    [TestClass()]
    public class IEXHelperTests
    {
        [TestMethod()]
        public void GetPercentageForStockTestValidSymbol()
        {
            decimal percentage = IEXHelper.GetPercentageForStock("AAPL");
            Assert.IsNotNull(percentage);
        }

        [TestMethod()]
        [ExpectedException(typeof(Exception))]
        public void GetPercentageForStockTestInvalidSymbol()
        {
            IEXHelper.GetPercentageForStock("EXXAMPLE");
        }
    }

Now we have a helper class which allows us to get the data from the IEX API on what we want to show in the popup. Next it is time to build the pop-up dialog box and show the data.

Building the popup box

I will use the standard Windows Forms class here and build the basic shape within the Visual Studio designer ( although it won’t have all that many controls on it ). Most of the form will be dynamic – listing X amount of stocks, so the size/controls/content will all be added dynamically upon loading the form.

Firstly, I create a new form ( right click project -> Add -> Windows Form ) called PopupForm

The size on the designer will be big by default, but this does not matter as it will be dynamically re-sized to fit the contents. We do however need to set the background of the Form to black and remove the border:

We also need the popup box to not show within the task bar ( by default an application icon will appear within the active windows task bar, which is not what Iwant ):

That is all that is needed to be changed from the Designer side of the form, the rest will be handled within code at run time.

Dynamic insertion of data into popup box

Now that we have a base popup box built ( albeit a very simple form, with no border, and a Black background ) we are not going to actually use this Form directly. We are going to create a new Class called DynamicPopupForm which will derive from the PopupForm  and override some key methods ( such as the startup method ) so that we can do some dynamic display.

Create a new class DynamicPopupForm.cs   ( right click project, Add New – Class ) which should look like this:

    public class DynamicPopupForm : PopupForm
    {
        int secondsToDisplayFor = 5;
        System.Timers.Timer timer;
        public DynamicPopupForm(List<StockListObjectData> data, int secondsToDisplayFor)
        {
            this.secondsToDisplayFor = secondsToDisplayFor;
            this.Shown += DynamicPopupForm_Shown;
        }

        private void DynamicPopupForm_Shown(object sender, EventArgs e)
        {
            timer = new System.Timers.Timer();
            timer.Interval = secondsToDisplayFor * 1000;
            timer.Elapsed += Timer_Elapsed;
            timer.Enabled = true;
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            timer.Enabled = false;
            this.Invoke((System.Windows.Forms.MethodInvoker)delegate
            {
                this.Close();
            });
        }
    }

You will see that constructor of the DynamicPopupForm  form has an List<>  of  StockListObjectData passed into it. This is a ‘model’ class that I have created in a separate file StockListObjectData.cs , create this new file, and make it look like this :

    public class StockListObjectData
    {
        public string StockName { get; set; }
        public decimal PercentageChange { get; set; }
    }

This Class is essentially our model which we are passing through to the view ( the DynamicPopupForm )

What the constructor is doing is showing the form ( it will be blank ), then after X amount of seconds, automatically closing the form.

Now re-visit the DynamicPopupForm.cs  and add a using namespace reference to System.Timers :

using System.Timers;

We can test this newly created DynamicPopupForm  by hooking up the showPricesNowMenuItem_Click  within Form1.cs  to call a new DynamicPopupForm

Within Form1.cs , hook up the show prices menu item event to a new method called ShowStockPrices :

        private void showPricesNowMenuItem_Click(object sender, EventArgs e)
        {
            ShowStockPrices();
        }

        private void ShowStockPrices()
        {
            List<StockListObjectData> data = new List<StockListObjectData>()
            {
                new StockListObjectData(){ PercentageChange = -1, StockName = "AAPL"},
                new StockListObjectData(){ PercentageChange = -0.05M, StockName = "MSFT"},
                new StockListObjectData(){ PercentageChange = 2.05M, StockName = "FMC"},
            };

            DynamicPopupForm dpop = new DynamicPopupForm(data, 5);
            dpop.Show();
        }

You can see that the ShowStockPrices()  currently builds a test set of StockListObjectData which is then passed through to the DynamicPopupForm  constructor.

Now if you run your application and right click the icon in the taskbar, you can click the “Show Prices Now” menu item, you’ll see that the DynamicPopupForm  ( all black ) shows for 5 seconds, then disappears – nothing special yet… The data is not used at the moment, the next section will use this test data.

Dynamic Layout

Now that the general control/show of the DynamicPopupForm  is built, we need to add data to it add code to dynamically resize the form based on inputs.

I used the following method to build a layout to the form ( which is placed within DynamicPopupForm.cs ):

        private Size BuildStockListUI(List<StockListObjectData> data)
        {
            // 2 pixels in, just to have a slight padding
            int xlocation = 2;
            int ylocation = 2;

            int contentHeight = 0;
            int contentWidth = 0;

            // Dynamically add controls to the form
            foreach(var stockData in data)
            {
                var stockTicker = new System.Windows.Forms.Label();
                stockTicker.AutoSize = true;
                stockTicker.Size = new System.Drawing.Size(100, 15);
                stockTicker.Name = "label" + stockData.StockName;
                stockTicker.Text = stockData.StockName;
                stockTicker.Location = new System.Drawing.Point(xlocation, ylocation);
                stockTicker.ForeColor = System.Drawing.Color.White;                

                this.Controls.Add(stockTicker);

                var percentageLabel = new System.Windows.Forms.Label();
                percentageLabel.AutoSize = true;
                percentageLabel.Size = new System.Drawing.Size(100, 15);
                percentageLabel.Name = "labelPercent" + stockData.StockName;
                percentageLabel.Text = stockData.PercentageChange.ToString("0.00") + "%";
                percentageLabel.Location = new System.Drawing.Point(xlocation+100, ylocation);

                // Change percentage based on plus mins or equal
                if (stockData.PercentageChange > 0)
                {
                    percentageLabel.ForeColor = System.Drawing.Color.Green;
                    percentageLabel.Text = "+" + percentageLabel.Text;
                }
                else if (stockData.PercentageChange < 0)
                {
                    percentageLabel.ForeColor = System.Drawing.Color.Red;
                }
                else
                {
                    percentageLabel.ForeColor = System.Drawing.Color.Gray;
                }

                this.Controls.Add(percentageLabel);            

                ylocation += 15;

                contentWidth = 200;
                contentHeight += 15;

            }
            return new System.Drawing.Size(contentWidth, contentHeight);
        }

Note: You’ll need to add using reference to System.Drawing :

using System.Drawing;

Most of this code is just dynamic layout code which adds labels to the form in an orderly fashion. It returns a Size  object so that the application knows how big the parent control should be. Notice that we set green/red fore colour of the Label  depending upon if the stock is positive/negative for the day.

To call this, adjust the constructor of the DynamicPopupForm  to the below:

        public DynamicPopupForm(List<StockListObjectData> data, int secondsToDisplayFor)
        {
            Size sizeOfContent = BuildStockListUI(data);
            //  + 4 is for the 2 pixels padding
            // + 10 is for room for X button.

            this.ClientSize = new System.Drawing.Size(sizeOfContent.Width + 14, sizeOfContent.Height + 4);

            this.secondsToDisplayFor = secondsToDisplayFor;
            this.Shown += DynamicPopupForm_Shown;

        }

By returning the Size  of the controls which are built by the BuildStockListUI method, it allows the parent form ( DynamicPopupForm ) to be resized to fit the content, which is adjusted by setting the form ClientSize property. I have added an extra 10 pixels to the width, and 4 pixels for padding on all sides.

If you now run the application, and press the ‘Show Stocks Now’ button, you’ll see a popup with our test data, which will seemly appear in the ‘middle’ of your screen.

The popup is shown correctly with the test data, and it is of appropriate size, but the positioning is wrong, I want it to appear in a discrete location on the screen ( bottom right hand corner ).

The following code allows us to do this:

            Rectangle workingArea = Screen.GetWorkingArea(this);
            this.Location = new Point(workingArea.Right - Size.Width,
                                      workingArea.Bottom - Size.Height);

Put this within the constructor within DynamicPopupForm.cs : ( full constructor code: )

        public DynamicPopupForm(List<StockListObjectData> data, int secondsToDisplayFor)
        {
            Size sizeOfContent = BuildStockListUI(data);
            //  + 4 is for the 2 pixels padding
            // + 10 is for room for X button.

            this.ClientSize = new System.Drawing.Size(sizeOfContent.Width + 14, sizeOfContent.Height + 4);

            this.TopMost = true;
            // Move it to bottom right hand corner of screen.
            Rectangle workingArea = Screen.GetWorkingArea(this);
            this.Location = new Point(workingArea.Right - Size.Width,
                                      workingArea.Bottom - Size.Height);

            this.secondsToDisplayFor = secondsToDisplayFor;
            this.Shown += DynamicPopupForm_Shown;

        }

Note: You’ll also need to add a namespace reference to System.Windows.Forms :

using System.Windows.Forms;

Note2: I also added this.TopMost  to make sure that the popup is always on top. If I clicked somewhere in a web browser that was full screen, the popup would disappear, which is not what I wanted. So Setting TopMost  to true makes sure it is always on top of other windows.

Lastly we need to add a small cross in the top right hand corner of the popup in order to be able to forcefully close the popup should we need to. Add the following code to the DynamicPopupForm class

        private void AddCloseButton(int currentWidth)
        {
            var closeLabel = new System.Windows.Forms.Label();
            closeLabel.Text = "X";
            closeLabel.ForeColor = System.Drawing.Color.Gray;
            closeLabel.AutoSize = true;
            closeLabel.Size = new System.Drawing.Size(10, 10);
            closeLabel.Location = new System.Drawing.Point(currentWidth, 0);

            closeLabel.Click += CloseLabel_Click;

            this.Controls.Add(closeLabel);
        }

        private void CloseLabel_Click(object sender, EventArgs e)
        {
            timer.Stop();
            this.Close();
        }

We hook up the close label to a new event which firstly stops the timer from firing ( timer.Stop()  ), then closes the DynamicPopupForm . Note: it is important to stop the timer first so that the application does not exception.

We call this AddCloseButton  from within the constructor after the dynamic building of the stock ( BuildStockListUI  ) has taken place:

Alter the DynamicPopupForm  constructor to call the AddCloseButton :

        public DynamicPopupForm(List<StockListObjectData> data, int secondsToDisplayFor)
        {
            Size sizeOfContent = BuildStockListUI(data);
            //  + 4 is for the 2 pixels padding
            // + 10 is for room for X button.

            AddCloseButton(sizeOfContent.Width);
            this.ClientSize = new System.Drawing.Size(sizeOfContent.Width + 14, sizeOfContent.Height + 4);
            this.TopMost = true;
            // Move it to bottom right hand corner of screen.
            Rectangle workingArea = Screen.GetWorkingArea(this);
            this.Location = new Point(workingArea.Right - Size.Width,
                                      workingArea.Bottom - Size.Height);

            this.secondsToDisplayFor = secondsToDisplayFor;
            this.Shown += DynamicPopupForm_Shown;

        }

If you run the application now, and call the “Show Popup Now” it should display the test data that we input earlier in the ShowStockPrices()  method. The popup should appear in the bottom right hand corner of your screen, and should look like:

Working with Real Data

Next we can build the application to use real data from IEX rather than the fake data we put into ShowStockPrices()  earlier. Alter the ShowStockPrices()  method within Form1.cs  and remove the fake data, and replace with the following:

        private void ShowStockPrices()
        {
            var data = GetStockPrices(settings);

            DynamicPopupForm dpop = new DynamicPopupForm(data, 5);
            dpop.Show();
        }

This calls a new method GetStockPrices() which accepts a ConfigSettingsObject object, the new method GetStockPrices()  looks like this:

        private List<StockListObjectData> GetStockPrices(ConfigSettingsObject settings)
        {
            List<StockListObjectData> toReturn = new List<StockListObjectData>();
            foreach(var stock in settings.watchedStock)
            {
                StockListObjectData newData = new StockListObjectData();
                newData.StockName = stock;
                newData.PercentageChange = IEXHelper.GetPercentageForStock(stock);
                toReturn.Add(newData);
            }
            return toReturn;
        }

This method will call the IEXHelper  method GetPercentageForStock , passing in the stock ticker name ( e.g. AAPL ). It does this for every stock that is configured/watched by the application.

Running the application now and pressing the “Show Popup Now” will get and show real data ( make sure you have some stocks added to your ‘watched list’ ), notice when pressing “Show Popup Now” there will be a small delay before the popup shows whilst the application contacts the IEX API, this is normal.

Note: I added a few more stocks to see how it would behave with many stocks:

Adding Periodic Popups

Now that manual popups are enabled via “Show Popup Now”, the application is required to popup automatically every X seconds, we can do this by utilizing a Timer.

Within Form1.cs  add a class variable of type  System.Timer.Timers

... 
public partial class Form1 : Form
    {
        private System.Timers.Timer popupTimer;
...

Then initiate that variable within the Form Load event, alter the Form1_Load  event handler to the below, and also add the PopupTimer_Elapsed  method:

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadSettingsFromFile();
            popupTimer = new System.Timers.Timer();
            popupTimer.Interval = settings.popupFrequencySeconds * 1000;
            popupTimer.Elapsed += PopupTimer_Elapsed;
            popupTimer.Start();
            AttachListeners();
        }

        private void PopupTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            ShowStockPrices();
        }

Lastly, we need the timer interval frequency to adjust whenever the config settings are altered, adjust the popupFreqNUD_ValueChanged method to change the timer interval:

        private void popupFreqNUD_ValueChanged(object sender, EventArgs e)
        {
            settings.popupFrequencySeconds = Convert.ToInt32(popupFreqNUD.Value);
            SaveSettingsToFile();
            popupTimer.Interval = settings.popupFrequencySeconds * 1000;
        }

In theory this works, but I discovered that the popup doesnt show on the execution of the timer, or if it did, it was displaying strangely e.g. :

I believe this happens because the Timer  which fires the event PopupTimer_Elapsed fires the event ( and therefore executing code within it ) on a non-UI Thread, instead it looks to be firing on a worker thread. Within Winforms in order to get UI forms to redraw/display correctly, the UI element ( in this case the DynamicPopupForm ) has to have affinity with the main UI thread ( of which there is only one ). In order to have the DynamicPopupForm  render correctly, it needs to be attached to the main UI thread, to do this we use Invoke  along with MethodInvoker.

https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker(v=vs.110).aspx

Fix:

From within the ShowStockPrices  method, alter the body to Invoke the creation and showing of the DynamicPopupForm  – this will attach the call to the DynamicPopupForm.Show()  to the main UI thread which will allow the popup to render correctly:

        private void ShowStockPrices()
        {
            var data = GetStockPrices(settings);

            Invoke(new MethodInvoker(() =>
            {
                DynamicPopupForm dpop = new DynamicPopupForm(data, 5);
                dpop.Show();
            }));
        }

Now if we run our application, the DynamicPopupForm  should display and render correctly, and disappear after 5 seconds ( dependant upon configuration you chose )

Showing only during market operational hours

There is a requirement for the popup to only show during operational market hours. The tick box/settings data values are already within the saved ConfigSettingsObject , the application needs to use the boolean value onlyPopupDuringTradingHours to check if the popup should be displayed at all.

There are a few different ways we can get if the American stock market ( NYSE NASDAQ ) if open or not ( possibly via different API calls to IEX ), I have chosen to look at the data returned by the query to IEX. I found the following returned value within the IEX data which is returned when one stock is queried:

"latestSource": "Close"

Having a look at the documentation ( https://iextrading.com/developer/docs/#quote ) it looks like the following values are possible:

“IEX real time price”
“15 minute delayed price”
“Close”
“Previous close”

Therefore, if the value returned by IEX is “Close” or “Previous close” the market is closed and so the application should not show the entries.

This has it’s advantages and disadvantages. It allows the popup to only show stocks when the exchange is open on a stock-by-stock basis, which is good – should IEX start supporting other markets. But it also means that the application will poll/query IEX even if the stock exchange is closed – for every stock, which is mostly an unnecessary overhead, an overhead I was willing to accept for this project.

Firstly we need to alter the StockListDataObject.cs  class to include a new variable which records if the stock market is open or not, adjust it so that it looks like this:

    public class StockListObjectData
    {
        public string StockName { get; set; }
        public decimal PercentageChange { get; set; }
        public bool StockStockMarketOpen { get; set; }
    }

Next, we change the IEXHelper.cs  file and alter the return object for GetPercentageForStock from a decimal  to a StockListObjectData

The full method for GetPercentageForStock  within IEXHelper.cs  should now look like this:

        public static StockListObjectData GetPercentageForStock(string symbol)
        {
            StockListObjectData toReturn = new StockListObjectData();
            toReturn.PercentageChange = -1;
            toReturn.StockName = symbol;
            toReturn.StockStockMarketOpen = false;
            // Build query to call against API:
            string paramaters = $"stock/{symbol}/quote?displayPercent=true";
            string objectAsString = APICall(paramaters);

            var data = (JObject)JsonConvert.DeserializeObject(objectAsString);
            toReturn.PercentageChange = data["changePercent"].Value<Decimal>();
            string closedValueString = data["latestSource"].Value<String>();
            if (closedValueString.ToLower().Contains("Close"))
            {
                toReturn.StockStockMarketOpen = false;
            }
            else
            {
                toReturn.StockStockMarketOpen = true;
            }
            return toReturn;
        }

Notice that this method no longer just gets the percentage for the stock, it actually does more than this, so I decided to rename the method to GetStockData within IEXHelper.cs :

 public static StockListObjectData GetStockData(string symbol)
 {
    ....

Note: If you are using a test project IEXHelperTests  like me, you’ll have to rename the method call in the tests too:

        [TestMethod()]
        public void GetPercentageForStockTestValidSymbol()
        {
            decimal percentage = IEXHelper.GetStockData("AAPL").PercentageChange;
            Assert.IsNotNull(percentage);
        }

Altering the method return will break the application/show compilation error within VS, the next step is to fix this to that it accepts the new object type, and also account for the StockStockMarketClosed  new property.

Alter the GetStockPrices  method within Form1.cs  to check for stock market being open for a stock if the settings deem it to do this check:

       private List<StockListObjectData> GetStockPrices(ConfigSettingsObject settings)
        {
            List<StockListObjectData> toReturn = new List<StockListObjectData>();
            foreach(var stock in settings.watchedStock)
            {
                StockListObjectData newData = IEXHelper.GetStockData(stock);
                if(settings.onlyPopupDuringTradingHours == true)
                {
                    if(newData.StockStockMarketOpen == true)
                    {
                        toReturn.Add(newData);
                    }
                }
                else
                {
                    toReturn.Add(newData);
                }
            }
            return toReturn;
        }

Lastly, alter the ShowStockPrices so that it does not attempt to show the dialog if no stocks are returned:

        private void ShowStockPrices()
        {
            var data = GetStockPrices(settings);
            if (data.Count() >= 1)
            {
                Invoke(new MethodInvoker(() =>
                {
                    DynamicPopupForm dpop = new DynamicPopupForm(data, 5);
                    dpop.Show();
                }));
            }
        }

You should now have a fully working Stock Market Popup Ticker application will periodically show the popup dialog in the bottom right hand corner. The major development of the application is now complete, and you have a working product. The next section discusses how to set the application up with an installer.

Installer

As part of the requirements I wanted the application to have an installer ( for easy distribution/sharing ).

I chose to use Wix for my project installer, mostly because I have used it before at work and I know that it is very captable. There are plenty of articles on stack overflow debating which installer project type is best, I feel that the consensus is that Wix is one of the more complete installer products, even though it may be tricky to use for a first timer.

Firstly, you need to download and install the Wix toolset build toolshttp://wixtoolset.org/releases/

I’m using the most current stable version which is v3.11.1. When you click download, it will take you to a github page, download the one that is an executable as shown below:

Once the executable is downloaded, run it, and the WiX installer GUI will show, just press install:

It is also necessary to install the Wix Toolset Visual Studio Extension 2017 : https://marketplace.visualstudio.com/items?itemName=RobMensching.WixToolsetVisualStudio2017Extension

Download and install that extension like any other VS extension.

( Remember to restart VS after these installations )

Add a new Setup Project for WiX v3 to your solution, call it StockMarketPopupTickerSetup

You’ll be presented with the Product.wxs  file. This is the setup configuration file ( no GUI available for WiX ) and it instructs WiX what to include in the setup file and all of the configuration details within the setup file.

Now that the setup project is created, we need to give it reference to the StockMarketPopupTickerApplication project. Add a reference to the StockMarketPopupTickerApplication  project from the StockMarketPopupTickerSetup project:

Alteration/configuration of the WiX wxs is a complicated topic – there is quite a lot of learning to be done in regards to WiX in order to begin/start using it. This is a sentiment that is echoed in other places on the internet too, although WiX is very powerful, it has a semi-steep learning curve compared to other setup/installer products.

If you would like to know more about the WiX setup, I recommend that you read the ( quite lengthy ) ‘Wix Tutorial’ tutorial from the FireGiant website: https://www.firegiant.com/wix/tutorial/getting-started/

Before we alter the WiX configuration, change the icon file that is attached to the project StockMarketPopupTicker  to be copied into the output directory, set it to copy if newer , the WiX installer will need access to this icon file in order to build the installer file and create shortcuts etc with the correct application icon.

Moving on to setting up the WiX configuration file:

I’m going to omit explaining every line/configuration section within the WiX installer from this post in detail ( I may do this in another post at a later date). This is the resulting Product.wxs  file for this product:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" >
  <Product
    Id="FB578C47-0B05-4D95-8925-AF5D61B4BBCD"
    Name="Stock Market Popup Ticker"
    Language="1033" Version="1.0.0"
    Manufacturer="Nick Saxelby"
    UpgradeCode="6D539E30-821C-4865-9498-E459A35311E0">

    <Package Id="*" InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <!-- Credit for this part: https://stackoverflow.com/questions/29919701/how-to-remove-license-dialog-from-the-wix-installer-built-in-ui-wixui-minimal -->
    <UI Id="WixUI_MinimalX">
      <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
      <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
      <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />

      <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
      <Property Id="WixUI_Mode" Value="Minimal" />

      <DialogRef Id="ErrorDlg" />
      <DialogRef Id="FatalError" />
      <DialogRef Id="FilesInUse" />
      <DialogRef Id="MsiRMFilesInUse" />
      <DialogRef Id="PrepareDlg" />
      <DialogRef Id="ProgressDlg" />
      <DialogRef Id="ResumeDlg" />
      <DialogRef Id="UserExit" />
      <DialogRef Id="WelcomeDlg" />

      <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>

      <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>

      <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>

      <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
      <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
      <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>

      <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
      <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">1</Publish>

      <Property Id="ARPNOMODIFY" Value="1" />
    </UI>

    <UIRef Id="WixUI_Common" />
    
    <Icon Id="icon.ico" SourceFile="$(var.StockMarketPopupTickerApplication.TargetDir)\if_stock-market_87472.ico"/>
    <Property Id="ARPPRODUCTICON" Value="icon.ico" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate EmbedCab="yes"/>
    

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="APPLICATIONROOTDIRECTORY" Name="Stock Market Popup Ticker" />
      </Directory>

      <Directory Id="ProgramMenuFolder">
        <Directory Id="ApplicationProgramsFolder" Name="Stock Market Popup Ticker"/>
      </Directory>

      <Directory Id="StartupFolder" >
      </Directory>
    </Directory>

    <DirectoryRef Id="APPLICATIONROOTDIRECTORY">
      <Component Id="MainExecutableFiles"  Guid="A39FB1A6-72D0-4E90-97A4-93972F30E689">
        <File Id="ExecutableFile" Name="StockMarketPopupTickerApplication.exe" Source="$(var.StockMarketPopupTickerApplication.TargetPath)" KeyPath="yes" Vital="yes" />
        <File Id="SettingsFile" Name="settingsConfig.xml" Source="$(var.StockMarketPopupTickerApplication.TargetDir)\settingsConfig.xml" Vital="yes">
          <util:PermissionEx User="Users" GenericAll="yes"/>
        </File>
        <File Id="NewtonsoftJSON" Name="Newtonsoft.Json.dll" Source="$(var.StockMarketPopupTickerApplication.TargetDir)\Newtonsoft.Json.dll" Vital="yes" />
        <File Id="NewtonsoftXML" Name="Newtonsoft.Json.xml" Source="$(var.StockMarketPopupTickerApplication.TargetDir)\Newtonsoft.Json.xml" Vital="yes" />
        <RemoveFolder Id="APPLICATIONROOTDIRECTORY" On="uninstall"/>
      </Component>
    </DirectoryRef>

    <DirectoryRef Id="ApplicationProgramsFolder">
      <Component Id="ApplicationShortcut" Guid="09DE8EAE-3458-4BA7-A628-40977552E11B">
        <Shortcut Id="ApplicationStartMenuShortcut"
             Name="Stock Market Popup Ticker"
           Description="Stock Market Popup Ticker"
            Target="[#ExecutableFile]"
                  WorkingDirectory="APPLICATIONROOTDIRECTORY"
                  Icon="icon.ico"/>
        <RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
        <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
      </Component>
    </DirectoryRef>

    <DirectoryRef Id="StartupFolder">
      <Component Id="StartUpShortcut" Guid="1E8F6723-79EC-4D98-B553-533BFD50D763">
        <Shortcut Id="ApplicationStartUpShortcut"
             Name="Stock Market Popup Ticker"
           Description="Stock Market Popup Ticker"
            Target="[#ExecutableFile]"
                  WorkingDirectory="APPLICATIONROOTDIRECTORY"
                  Icon="icon.ico"/>
        <RemoveFolder Id="StartupFolder" On="uninstall"/>
        <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Name="ShortCutStartUp" Type="integer" Value="1" KeyPath="yes"/>
      </Component>
    </DirectoryRef>

    <Feature Id="Complete" Title="Stock Market Popup Ticker Setup" Level="1">
      <ComponentRef Id="MainExecutableFiles" />
      <ComponentRef Id="ApplicationShortcut" />
      <ComponentRef Id="StartUpShortcut" />
    </Feature>
  </Product>
</Wix>

Note: Everywhere within this configuration file where it uses ‘Guid=’ followed by a GUID; has been generated by me using any online GUID generation tool ( example : https://www.guidgenerator.com/online-guid-generator.aspx ). If you are using this post to make your own product, it is important not to copy these GUID values exactly. These GUID’s are Globally unique identifiers, and so if you try to install application A which has the same GUID as application B, there will be problems. Please re-generate these GUID values if you are using this post to make your own product.

Before building this setup file, we need to add a reference to an extension that is needed: PermissionEx , which is part of the WixUtilExtension.dll  extension. To add a reference to this extension, within the WiX setup project add a reference and find the file at the location:

C:\Program Files (x86)\WiX Toolset v3.11\bin\WixUtilExtension.dll

Your insert reference dialogue will look like this ( if you are using VS 2017 ):

When you press ‘ok’, you may see the following error dialog pop up:

“Unable to cast transparent proxy to type ‘WixExtensionValidator’.”

I did a little bit of digging, and it seems that this is not as fatal an error as it may look.

If you press ‘Ok’, then unload/reload the WiX setup application ( or just restart visual studio ). When you re-visit the References section within the WiX setup project, you’ll see it has added it:

Note: if you don’t get this error, then lucky you, you should see the below:

You need to add one more reference to a Wix extension ( same process as above ), we need the WiXUIExtension to allow our .msi to have a friendly GUI on install

Add the following dll to references:

C:\Program Files (x86)\WiX Toolset v3.11\bin\WixUIExtension.dll

Note: again, same instructions as before if you see an error message pop up.

So now you should have three references within the Setup project.

You should now be able to build the setup project, browse to the output directory, and you should see a StockMarketPopupTickerSetup.msi  file which is the installer file. Give the installer a go and you’ll be guided though an installer :

What does this WiX setup file do:

  • Installs required executable files within the Program Files folder
  • Creates a shortcut to the application within the start menu
  • Creates a shortcut to the application within the windows StartUp folder – which allows the application to run on startup
  • Creates permissions to allow users to alter the settingsConfig.xml file

Future improvements/Features:

  1. Within installer, provide a GUI which allows the user to click ‘Next’ ‘Next’ ‘Next’ etc
  2. Add more stock markets, at the moment, the API that I use only finds symbols within NYSE and NASDAQ, IEX responded to me saying that in the future it may be possible to select different exchanges

Polling battery percentage on MacOs


This is an extension of my last post which covered polling battery percentage within iOS:

https://nsaxelby.com/2018/05/06/polling-battery-percentage-on-iphone/

This post is describes how to do it in MacOs

Introduction:

This post explores how to poll for the battery percentage on a MacOsx device. My MacOs device that I’m building on is a High Sierra MacBook Air ( 2014 ).

Implementation:

Fortunately querying the battery percentage on a MacOs device is much easier than on a iOS. You don’t have to worry about all of the ‘background capabilities’ and modes requires for the iOS implementation. We will use the same NSTimer to poll within the app every X seconds, but we will use IOPowerSources.h  within IOKit  to obtain the battery percentage.

Step 1:

Within your MacOs application AppDelegate.h  ( or wherever you want to put it ) import the IOKit ‘s IOPowerSources :

#import <IOKit/ps/IOPowerSources.h>

Within your AppDelegate.m create the method that will get the battery percentage and do whatever you want to do with the percentage, add the following method:

- (void)PollPercentage
{
    // Obtain blob data
    CFTypeRef powerSourceInfo = IOPSCopyPowerSourcesInfo();
    CFArrayRef powerSources = IOPSCopyPowerSourcesList(powerSourceInfo);
    
    CFDictionaryRef powerSource = NULL;

    
    long numberOfSources = CFArrayGetCount(powerSources);
    if(numberOfSources == 0)
    {
        NSLog(@"Problem, no power sources detected");
    }
    else
    {
        if(numberOfSources == 1)
        {
            NSLog(@"One power source detected");
            powerSource = IOPSGetPowerSourceDescription(powerSourceInfo, CFArrayGetValueAtIndex(powerSources, 0));
        }
        else
        {
            NSLog(@"More than one power source detected, using first one available");
            powerSource = IOPSGetPowerSourceDescription(powerSourceInfo, CFArrayGetValueAtIndex(powerSources, 0));
        }
        
        const void *psValue;
        int curCapacity = 0;
        int maxCapacity = 0;
        int percentage;
        
        // Work out percentage based on capacity current/max
        psValue = CFDictionaryGetValue(powerSource, CFSTR(kIOPSCurrentCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
        
        psValue = CFDictionaryGetValue(powerSource, CFSTR(kIOPSMaxCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
        
        percentage = (int)((double)curCapacity/(double)maxCapacity * 100);
        NSLog(@"Perentage of battery: %i", percentage);
        
        // TODO do whatever you want here code-wise with the percentage
    }
}
Step 2:

Hook up your method of a NSTimer by putting the following code in your applicationDidFinishLaunching  within the AppDelegate.m :

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    [NSTimer scheduledTimerWithTimeInterval:20.0
                                     target:self
                                   selector:@selector(PollPercentage)
                                   userInfo:nil
                                    repeats:YES];
}

If you fire up your app, you will see the the debug output look something like this:

 

Full git source code sample application here:

https://github.com/nsaxelby/MacOsBatteryMonitorApp


Polling Battery percentage on iPhone


Introduction:

This article explores techniques on how to periodically poll/check battery percentage on an Apple iPhone device using X Code and objective-c.

Use case/Purpose:

I have three apple devices ( two iPhones and a MacBook Air ). Without having to physically locate each device, I want to be able to check the battery percentage of each of the devices.

Covered in this post:

This post covers the mechanics of how to poll for battery percentage on an iOS device, polling for battery percentage on a MacOs device is covered in another article:

https://nsaxelby.com/2018/05/10/polling-battery-percentage-on-macos/

Implementation (iOS):

Theory:

We want a background task to periodically check the battery percentage and do something with it such as post it to an external service ( external service not included in this post ). We want to know the status of the battery every 5 minutes which checks the battery level.

We should do this by using a NSTimer and using UIDevice to query the batteryLevel.

Step 1: Setting up a poller to output the battery percentage level to output

We can set this up by initialising the NSTimer  from the didFinishLaunchingWithOtions  method of the AppDelegate.m  file.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
    // For the purposes of testing, I have set the interval to 20 seconds
    [NSTimer scheduledTimerWithTimeInterval:20.0
                                     target:self
                                   selector:@selector(UpdateBatteryStatus)
                                   userInfo:nil
                                    repeats:YES];
    return YES;
}

- (void)UpdateBatteryStatus
{
    UIDevice *myDevice = [UIDevice currentDevice];
    float batteryPercentageLeft = [myDevice batteryLevel] * 100;
    NSLog(@"Battery Percentage: %f", batteryPercentageLeft);
    // TODO add additional code here to do whatever you want with the battery percentage
}

If you run the application now, you will see the following in the output:

Note: if you are running the simulator ( as opposed to a real device ) the percentage will show as -100 because the simulator does not have a battery.

This is a good start, however, if the user minimises the application to the background ( press the home button on the device so that the app is not longer the ‘active’ app ), the NSTimer  will stop. The use-case of this application was to be able to monitor the battery percentage of the device when the user does not have the device to hand. For this scenario, it is therefore necessary to allow the NSTimer  to continue to poll the battery percentage even whilst the app is in the background.

Note: if you are running the simulator, you will see that the NSTimer continues polling in the background even when the app is in the background. The simulator works differently from the real device in this case.

This is where we hit a problem. After doing some research, I found Apple does not want an app to process in the background unless there is a very good reason for the app to do so. The full explanation on background execution modes is available here:

https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

To summarise the page, apps that are allowed to periodically execute within the background:

  • GPS type applications ( navigation apps )
  • Music/VOIP apps ( music streaming, or communication apps such as Skype )
  • Apps which talk to bluetooth devices ( headphones, etc )

There are other types of apps, but the frequency/control of the background execution of the other types in the list, are not suitable for this use case ( we want polling every 5 minutes ).

What does this mean? Basically, if you are planning on releasing a pure battery monitoring app ( pure as in; no other major functionality ) to the app store, you are likely to be unsuccessful with your submission.

In my case, I was not planning on releasing the app to the app store, so I had to find a technical workaround ( aka a hack ) in order for my NSTimer  to be able to execute even when in the background.

Step 2: Find a workaround to allow background execution

Theory: Alter the app so that it has a background execution attribute, and then imitate that background execution mode to keep the app alive in the background.

Firstly we need to allow the background execution mode within the capabilities of the app, we would state within the build settings that this app is of a type of ‘Audio, AirPlay and Picture in Picture’ app. We enable Background Modes capabilities within the Targets of the app:

If we run the application now, you will see that it has made no difference, when the app resides to the background, the NSTimer  stops working.

In order to keep the app alive in the background, we need to act like a regular audio player app. To do this, we will add an AVPlayer to the code, and have that player play a silent track on a continuous loop.

Within the AppDelegate.h import the AVFoundation library:

#import <AVFoundation/AVFoundation.h>

Add a AVPlayer as a property:

@property (nonatomic, strong) AVPlayer *player;

Now within the AppDelegate.m  it’s time to setup the AVPlayer  to begin playing a silent track upon app startup.

Put the following code into the didFinishLaunchingWithOptions  method:

 

    // Start playing silent file
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&sessionError];
    
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"2-seconds-of-silence" withExtension:@"mp3"]];
[self setPlayer:[[AVPlayer alloc] initWithPlayerItem:item]];
[[self player] setActionAtItemEnd:AVPlayerActionAtItemEndNone];
[[self player] play];

You will notice that we referenced a resource with the name “2-seconds-of-silence”  which has an extension of “.mp3” , this is the silent audio track that we need to go and obtain and import into the project before running the app.

Another key mention is the use of the withOptions:AVAudioSessionCategoryOptionMixWithOthers option that is used within the AVVideoSession . This option allows the silent track to continue playing and not affect other audio apps, the silent track will just mix into whatever other audio is playing, and given that the track we are playing is silent, it should have no affect on other audio output.

The complete didFinishLaunchingWithOptions will now look something like this:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
    
    // Start playing silent file
    NSError *sessionError = nil;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&sessionError];
    
    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"2-seconds-of-silence" withExtension:@"mp3"]];
    [self setPlayer:[[AVPlayer alloc] initWithPlayerItem:item]];
    [[self player] setActionAtItemEnd:AVPlayerActionAtItemEndNone];
    [[self player] play];
    
    // For the purposes of testing, I have set the interval to 20 seconds
    [NSTimer scheduledTimerWithTimeInterval:20.0
                                     target:self
                                   selector:@selector(UpdateBatteryStatus)
                                   userInfo:nil
                                    repeats:YES];
    return YES;
}
Step 3: Obtain the silent audio track

I obtained my silent audio track from the follow GitHub repo:

https://github.com/anars/blank-audio

You can use pretty much any duration of silent audio track, it should not make a difference which one you choose, I chose the 2 second audio track.

Once downloaded, you simply have to drag and drop it into your project from your finder window, and drop it into the list of files within your project navigator:

In order to test the background/foreground execution, I put an additional couple of logs within AppDelegate.m into the background/foreground event handlers, so that I could check that execution was happening where it should do:

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"App now in background");
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
        NSLog(@"App now in foreground");
}

If we execute our application on a real device, and put the app into the background ( press home button ) it should now give output like this:

Full git source for the project available at GitHub:

https://github.com/nsaxelby/BatteryMonitorApp

MacOs application is explained in another post within my blog:

https://nsaxelby.com/2018/05/10/polling-battery-percentage-on-macos/

Out of interest, this app allowed me to build up a history of how my iPhone battery performs over time, example screenshot of data that I was able to obtain, ( I may post the source code for the full project at a later date ).