Click here to Skip to main content
Click here to Skip to main content

Nutrition Analyzer: A new Windows 8 App

, 2 Dec 2012
Rate this:
Please Sign up or sign in to vote.
Submission for the Ultrabooks App Innovation Contest Category: Win 8 Desktop Apps, subcategory: Healthcare.

 Nutrition Analyzer Tile on Windows 8 Start Screen

Screenshot of Nutrition Analyzer tile and logo (symbolizing the food pyramid) on Windows 8 start screen. 

Introduction

Some images in this submission had to be resized to meet the 640 pixel size constraint for bitmap files. Unfortunately this did compromise the image quality to some degree.

Nutrition Analyzer is a new application that has been running as a Windows 7 desktop application for almost a year, to be debugged and fine-tuned. It is now being converted to a Windows 8 application to take advantage of the significantly improved ease-of-use features of Windows 8. The application provides diet or food analysis to any user who is interested in the nutritional content of daily meals.

 Potential users include (but are not limited to):

  • Ordinary people who are just trying to control weight gain.
  • Professionals who need to assess the nutritional value of specific diets to meet special needs, including institutions like hospitals that may have to obey special dietary rules for some patients.
  • Diabetics who want to monitor their intake of sugars and carbohydrates.
  • Athletes who want to monitor their intake of electrolytes, carbohydrates or protein.
  • People with cardiovascular problems that want to monitor their intake of cholesterol and saturated fats.
  • Any person who is concerned about the nutritional content of the food he or she eats.

It is important to note that the application merely analyzes the content of foods. It does not give nutritional advice. It tells you what is in the food that you eat, not what you should be eating. That is the domain of professionals in the field of nutrition. However, the users have the ability to plug in their own particular nutritional needs. For example: There are many excellent tables on the website of the Institute Of Medicine (IOM), that give the recommended intake of all nutrients, for both sexes of all age groups. The user has the ability to look up data on the IOM website, that pertain to his or her personal circumstances and to plug that data into the Nutrition Analyzer, even to adapt the recommendations to his or her personal preferences. The application will then warn users if their daily intake of any particular nutrient or nutrient factor (like calories), falls below the minimum requirement or exceeds the maximum tolerable level (potentially toxic level). But the accuracy of this daily requirement data as entered, remains the responsibility of the user and his or her professional advisor. This will be made very clear in the license agreement of the application.

The analysis of foods in the application is based on the most complete and comprehensive database that is distributed free as a public service by the US Department of Agriculture. The data in the tables of this database is available for free as an unrestricted download of delimited text files. (It is almost a 100MB download.) This database is used by thousands of manufacturers to calculate the familiar nutrition labels that appear on just about every food item in the stores. The database contains the nutrient content of almost 8,000 different food types. There are 146 nutrients (like vitamins) and other nutrient factors (like calories) listed for a 100 gram portion of every food type. It lists all the vitamins, macro minerals (calcium, potassium, etc.), micro minerals (zinc, copper, selenium, etc.), all 14 essential amino acids (from tryptophan to tyrosine) all saturated fats, unsaturated fats and other long chain fatty acids (the omega-3s, omega-6s, etc.) as well as other nutrient factors like sugars and other carbohydrates, dietary fiber, calories, caffeine, alcohol, etc. This "master data" is embedded in the application as a C# DataTable object. This is the main reason the main exe in the assembly is almost 40MB long, but it does mean the user has all the data right on his desktop / ultrabook. There is no need to run queries against external databases, or to even have a database engine on his or her machine. The user does not even need a network or Internet connection. It also means the data analysis executes at a very high speed. Embedding the master data also means that the data integrity is preserved. The data cannot be modified maliciously or by accident, without corrupting the entire application. However, we may later decide to distribute the master data table in a separate DLL, rather than embedding it in the main application. This will simplify upgrading the user's installation every few years, when the USDA publishes an updated version of the database. All the upgrade will entail is replacement of the DLL on the user's computer.

It will be impractical to expect the user to scroll through 8,000 entries to find a particular food entry. So the application allows the user to create a shortened version of the embedded Master USDA Table, called the "Basic Foods Table" which the user fills with entries of particular interest to him. Most people need about a hundred entries for their short version of the data table, but its length is unrestricted. This table is saved as a file on the user's computer and can be edited by him at any time. The user also has the capability to make custom entries into a third data table, called the "Other Foods Table". The purpose of this table is to allow the user to enter foods that are not in the master USDA data base. Typical examples will be multivitamin tablets and fish oil capsules. The user can enter his favorite brand of multivitamin with the content of each vitamin into this table. When he or she selects an entry from this table, all the user needs to specify is the number of pills or capsules taken and his or her intake of the relevant nutrients will be adjusted accordingly. The user can also create custom entries for items that may have close approximations in the USDA table, but for which there are no exact matches. For example: He or she can create a custom entry for "KASHI Almond Crunch Granola Bar" by running a query for "Granola Bar" against the master USDA data table and selecting the closest approximation. (There are more than 20 entries to select from.) The user can then adjust those nutrients that appear on the Kashi label to their exact values and know that the other nutrients for this custom item will be a reasonable approximation of the actual values. When the user selects his or her custom entry, all he or she needs to do, is specify the number of bars eaten and his or her daily nutrient totals will be adjusted accordingly.

Users have the ability to view their average daily intake of all nutrients for a period of any number of days. The period of interest is selected by picking two dates from date pickers.

The User Interface

The main user screen:

As you can see, the Basic Foods Table appears on the left. The Other Foods Table is on the right. The user selects a food type by clicking (or tapping - in the case of Windows 8) on the item. The rows can be set wide for finger tapping, or narrow for mouse input. The selection made by the user is displayed at the bottom of the screen, with the typical portion size for the selection and the calories in one typical portion. The user then enters the number of portions he or she had in the Manage Entries group on the right. The time and date for the entry will initially default to the current system time and date, but the user can change these values with the date picker and by entering the desired time in the appropriate text boxes. When the user clicks or taps ADD ENTRY the item with all 146 nutrients in quantities appropriate for the portion size entered, is saved in the user's personal table.

This personal table, and all other tables (except the main USDA table), can be edited by the user as detailed further down in this submission.

Please note that the visual styles in this submission have been modified to reflect the GUI windows as they appear in the version published by the AppUp store.

Viewing user Entries:

When the user clicks or taps VIEW ENTRIES in the above window, he or she is presented with the window below. By default, the period to view will be the current day, but he or she can select any number of days for which data exists. If he selects days for which no entries exist, those days are simply ignored. Here is a screen shot of a typical VIEW ENTRIES window:

On the left the user can see every portion of every food type that he or she consumed during the selected period. The 146 nutrients for every food entry are listed in columns to the right. The total for each nutrient column is calculated and divided by the number of days in question to give the average daily intake in the TOTALS (Daily Average) column. In the rows at the bottom, the user can see how his or her daily totals compare with the recommended daily intake. The user has to make a one-time entry of the recommended values that best suit his or her personal needs. However, we will provide links to the website of the Institute Of Medicine where many excellent tables of these values are available for on-line viewing. These tables provide recommended data for both sexes and for all age groups. Other than the USDA data, these IOM tables are copyrighted, so we could not embed them into the application. But for the user to select appropriate data and manually and entering it into a special table in the application is an easy task that most people can accomplish in less than 30 minutes. This only needs to be done once and the table of recommended values is stored as a file on the user's computer. Of course, the user (usually in consultation with a healthcare professional) has the ability to modify the data in the recommended intake table to suit any special needs he may have, like lowering the limits of sugars for diabetics, or cholesterol for people with cardiovascular issues. Weight watchers can set lower limits for the daily calorie intake (or carbohydrates - if they are on an Atkins type diet.) When the average intake of any nutrient is deficient, the Difference row right at the bottom displays the shortfall against a blue background. If the maximum tolerable intake level is exceeded, the difference is displayed against a red background.

The user can print the data if desired, by clicking PRINT. This will invoke a standard Windows print dialog. His or her daily intake levels of the 146 nutrients will be printed in vertical columns across three pages, along with warnings pertaining to excessive / inadequate levels. This will provide the user with a printout to discuss with his or her professional adviser.

This is a partial image of a printed report:

The user can also delete incorrect rows by selecting the row and clicking or tapping DELETE ENTRY. Of course, the incorrect entry can then be replaced by making the correct entry for the same date and time from the main window. All this personal data is stored in a C# DataTable object and the software re-orders all entries in the table by date and time, before saving it as a serialized stream to a file on the user's computer (or in the cloud - as the case may be.) Like other tables, except for the embedded master USDA table, the file is automatically read when the application is started.

If the user clicks or taps EDIT TABLES in the main window (see above), he or she is presented with the following window:

The user has the option to back up any of the four lesser tables: The personal table, the Basic Foods Table, the Other Foods Table and the Recommended Intake Table. Since the Master USDA Table is embedded in the application, either in the main exe file, or as a DLL, this cannot be backed up. If this master data becomes corrupted the whole application needs to be re-installed, as the entire application is probably corrupted. In this case it is very likely that the operating system will refuse to run the app.

If the user clicks VIEW PERSONAL TABLE, he or she is presented with the VIEW ENTRIES window covered some paragraphs back. From that window faulty entries can be deleted, later to be replaced by the correct entries.

If the user selects to edit the Basic Foods Table he or she is presented with the window below:

If the user clicks IMPORT NEW ITEM, he or she gets a window that allows him or her to run a query against the  embedded Master USDA Table to search for key word(s). For example: If the user enters "Potato" as a keyword, he or she will get a list of over 100 entries out of the almost 8,000 in the Master USDA Table that contain the word "potato". When the user selects one item, it and all its nutrient data is transferred to the Basic Foods Table, where it can later be easily selected for dietary intake. This is the only way data can be added to the Basic Foods Table, by importing an entire item from the Master USDA Table. Note that the USDA database, in common with all major international databases that provide nutritional data, works in the metric system. Nutrient content is usually given as micrograms, milligrams or grams per standard portion of 100 grams for each food type. This is not an issue, as all food scales nowadays measure in grams, or have the option to be set to grams. American users soon get used to even think portion sizes in grams.

The user has the ability to delete an entire entry and to save the table as a file on his or her computer.

By selecting to edit the Other Foods Table, the user has the opportunity to enter custom entries for supplements like multivitamin tablets, fish oil capsules, etc., for which there are no equivalents in the Master USDA Table. The user is presented with the following window:

By clicking CREATE NEW ENTRY the user can create a new, custom entry by setting its description and nutrients in the window below:

The user will enter his or her New Unit of Measure (in this case "cup")    The user may then click ACCEPT - SAVE  to permanently add his custom entry to the Other Foods Table, where it then becomes available for selection when he or she makes new entries into the personal data table.

Background

This project started as a hobby when I retired as an electronics engineer in 2010. Although not trained as a programmer, I have been writing apps for Microsoft platforms since I got my first IBM PC in 1984. Those first apps were in the original Microsoft Basic running on DOS II that booted from a floppy disk. I have experienced the complete evolution of the C language, from C6 to C++ to versions running on the MFC libraries to today's "visual" C# versions. C# is the only language I use nowadays and Visual Studio my only IDE.

I am very excited about the new technology with Windows 8 running on an Ultrabook with "touch" capabilities, as it will considerably improve the functionality of my app. It will be so much easier to scroll through 146 columns of data, looking for a specific nutrient column, by swiping the screen with a fingertip rather than dragging a scroll bar with a mouse. I already got some complimentary copies of Windows 8 from Microsoft and have been looking for a suitable Ultrabook but could not find "touch-enabled" versions to match Windows 8 functionality.

To keep busy in my retirement, I started this project and initially the USDA database delimited text files were converted to a proper SQL relational database in a special C# app that I coded. I installed SQL Express on my desktop and for about 6 months ran the first version of the Nutrition Analyzer on top of the SQL Express engine. But then some friends and family members (and even my neighbor - a doctor) saw the app and started asking for copies. I realized that I could never hand out an app that required access to a SQL database engine. Maintaining a SQL database engine is just too complicated for the man in the street. That is when I decided to recode the app, using embedded C# DataTable objects to hold the data, instead of a SQL database. The first challenge was to code an app to extract the master data in a specific table format from my SQL database and to save the desired table as C# DataTable object file on my computer. That was the easy part. Things got a little more complicated when I successfully embedded the resulting DataTable file as a static resource in my project during compile time, but then tried to read the file data, now embedded in the main exe of the project, during run time. I cover how I got this done in the "Using the code" section below. I ran hundreds of tests to verify that I get exactly the same result when I ran a nutrition query against the on-line USDA database and when I run the same query against me embedded DataTable file. After sorting out some glitches related to rounding errors, I got the app to return exactly the same data as the on-line USDA database engine for specific queries. Today I am satisfied that my app will return data that is a 100% match for data in the actual USDA database. At the same I started re-coding the app to avoid the requirement for a SQL database engine; I also decided to convert it from a Forms project to a WPF project. This conversion  was completed before the app was submitted to the Intel AppUp store. The app was published by the AppUp store on November 30.

Using the code

One challenge I faced with this project, was to embed a database table written out by another app as a serialized stream to an XML file on my computer, into my main project assembly. Embedding the file as a static resource using Visual Studio 2012 at compile time is quite easy. But reading the file, now embedded into the main exe of the project, during runtime to reconstruct the original DataTable object, was a little more challenging.

Important: There are risks, uncertainties and limitations involved in serializing / deserializing DataTable objects as well as using blocks of unmanaged memory as done below. Study the Microsoft documentation on these topics and be sure you address any vulnerabilities. You follow the approach below at your own peril. I shall not be responsible if you cause a disaster because you did not fully understand and address the risks.

In the end I used the following approach:

First copy the XML file (here called FullUSDA.DatTbl) to the solution folder.

Then add it to the project as static resource. In Visual Studio 2012 this is quite easy. If you do it correctly, your file will show up as resource under your project's Resources, something like this:

Now this file will be compiled as a resource into the NutritionAnalyzer project, where it can be accessed during runtime.

Since this file represents a serialized DataTable object, to reconstruct the DataTable object at runtime, we need to de-serialize the file and for this we need the following namespaces and steps:

using System.IO;
using System.Data;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace NutritionAnalyzer
{
public partial class MainWindow : IDisposable
{ 
    // Declare a class-wide DataTable object named _fullUsdaDataTable
    public DataTable _fullUsdaDataTable = new DataTable();
    
    public MainWindow()
    {
        InitializeComponent();
    }
    // Somewhere in the application, you need to call the following method:
    /********************************************************************
    * Initialize full USDA data table 
    ********************************************************************/
     private void InitializeFullUsdaDataTable()
       {
           IFormatter formatter = new BinaryFormatter();
           try
           {   //File is a byte[] in assembly
               byte[] tableByteArray = Properties.Resources.FULL_USDA;
                  //Create a stream reader that can read byte arrays from memory
               Stream tableStream = new MemoryStream(tableByteArray);
               //Get the length of the array (stream) 
               int tableStreamLength = (int)tableStream.Length;
            //Allocate unmanaged memory space for the byte array and get a pointer to it
               IntPtr tableDataPtr = Marshal.AllocCoTaskMem(tableStreamLength); 
            // Deserialize the embeddedfile, cast the result to (DataTable) and save
                // the result in _fullUsdaDataTable
               _fullUsdaDataTable = (DataTable)formatter.Deserialize(tableStream);
             //Free the unmanaged memory block immediately when it is no longer required
               Marshal.FreeCoTaskMem(tableDataPtr);
            // The DataTable object _fullUsdaDataTable is now fully loaded with 
                  //the data in the original XML file, and ready for use.
           }
           catch (Exception InitializeFullUsdaDataTable)
           {
            // Do something if an exception is thrown
           }
    }

Points of Interest

I needed to make use of older Windows Forms controls, specifically DataGridView  objects, in this project. The reason I needed Forms controls, is that WPF projects do not have controls with the same functionality offered by Forms DataGridViews. WPF DataGrids are too limited in their utility. I had no option but to host DataGridViews as child objects in my WPF windows. This is relatively easy in Visual Studio 2012, but slightly more convoluted in VS 2010 and earlier. . It is important to remember that Forms DataGridViews are disposable objects, so the window that will host these controls needs to be derived from IDisposable. You also need to provide methods to dispose of the DataGridViews in order to produce "clean" code.

See the snippet below:

namespace NutritionAnalyzer
{
       public partial class MainWindow : IDisposable
   {
           public MainWindow()
        {
            InitializeComponent();
            etc. etc.......
        }

        // Add these essential IDisposable methods:
        protected virtual void Dispose(bool disposing)
           {
               if (disposing)
               {
                   _usdaDataGridView.Dispose();// dispose managed resources
                   _otherFoodsDataGridView.Dispose();
               }
           }
           public void Dispose()
           {
               Dispose(true);
               GC.SuppressFinalize(this);
           }
    }
}

History

This is the submission to CodeProject of the application, as validated and published by the Intel AppUp store. The current version of the Nutrition Analyzer is: 3.3.0

Thanks!

Thank you for considering this submission for the Ultrabook competition.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Cornelius Henning
President American Analysis Software LLC
United States United States
I was trained as an electronics engineer and spent a large part of my life designing embedded controllers for industrial equipment. I did a lot of coding for these controllers in plain old C. I also created many apps in C, C++, as well as visual version of C++ all the way to C#. Many of these apps dealt with processing information mined in databases. I started learning to code for database engines, starting in the 1980's with DB2, Quicksilver, through to MS SQLExpress 2010. I enjoy golf and fiddling with Windows based computers. I currently own a small company: American Analysis Software LLC.

Comments and Discussions

 
QuestionCode? PinmemberRedDK23-Jul-13 11:39 
SuggestionPotential GUI Improvement PinmemberDrABELL1-Dec-12 7:24 
GeneralRe: Potential GUI Improvement PinmemberCornelius Henning1-Dec-12 8:24 
GeneralRe: Potential GUI Improvement PinmemberDrABELL1-Dec-12 9:11 
GeneralMy vote of 5 PinmemberDrABELL1-Dec-12 7:20 
QuestionGUI ääääh ? PinmemberSperneder Patrick9-Oct-12 19:59 
AnswerRe: GUI ääääh ? PinmemberCornelius Henning9-Oct-12 21:27 
Any positive suggestions that will actually help me improve the GUI? I am open to any such input.
GeneralRe: GUI ääääh ? PinmemberSperneder Patrick9-Oct-12 21:52 
GeneralRe: GUI ääääh ? PinmemberCornelius Henning9-Oct-12 22:23 
GeneralRe: GUI ääääh ? PinmemberSperneder Patrick9-Oct-12 22:31 
GeneralRe: GUI ääääh ? PinmemberCornelius Henning9-Oct-12 23:08 
QuestionHow does this make use of the features of an Ultrabook? PinadminChris Maunder9-Oct-12 15:01 
AnswerRe: How does this make use of the features of an Ultrabook? PinmemberCornelius Henning9-Oct-12 21:23 
GeneralRe: How does this make use of the features of an Ultrabook? PinadminChris Maunder10-Oct-12 4:27 
GeneralRe: How does this make use of the features of an Ultrabook? PinmemberCornelius Henning10-Oct-12 4:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 2 Dec 2012
Article Copyright 2012 by Cornelius Henning
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid