none
Visual Studio 2013 - New Project RRS feed

  • Question

  • Hi
    Many years ago I wrote a VB6 program for school students for diet analysis in terms of energy and a range of vitamins and minerals.  It drew comparisons against the national guidelines.  Results were tabulated, graphed and output provided in Word and Excel files.  The VB6 program used an Access database containing about 850 foods. It has been used by quite a few schools and appears to always be used across a network.

    My intention is to re-write the whole program in Visual Studio 2013 using Visual Basic code.  I intend to refresh the whole program and add a wider range of foods and update the comparisons using the latest national guidelines and food label formats.
     
    This will be my first attempt at Visual Studio and I intend to use a Windows Forms Application approach.  The data used is "static" - it does not change it is simply a "read only" file - get the data, multiply for mass and add up each category (energy, vitamins and minerals).  It is a "file of data" rather than a true database.  In reality a 1000 food data file should only be about 200 Kbytes.  As an Excel file it is only 150Kbytes but as an Access file it is bloated up to a 550Kbyte file.

    The program is not sophisticated, so, should I be using a WPF Application or a Window Forms Application?  The WFA just feels a bit more familiar than a WPF.  Also, the program is intended for loading onto a network at some schools or on a stand-alone computer.

    My greatest concern is about the choice of approaching the data.  A "true" database is not needed because the data is simply for about 1000 rows of food each with about 20 columns of data (numeric and text).  The Access file is simple but I could create an mdf file (I think) but would that be an advantage?  With the Access data I appear to have loaded the file and created a DataAdapter and I have experimented with GetData() which works.  My attempts to use ExecuteReader() failed completely.  Is there a better approach?  such as SQL "DataTable.Rows(RowPosition)(“column name")”??  It seems a very sophisticated method for a small file of data.

    The Access Database that I have experimented with in VS2013 appears to use Jet Drivers???? which proved to create a few problems for installations in the past.  Should I be using an mdf file approach??  I will need to distribute the data in a "resx" file.  I could use SQL Server Management Studio (free download) and then use VS2013 to read the Access file and build a new mdf database.....

    I am not convinced that I have the best solution.  Any comments and suggestions would be very greatly appreciated.

    Many thanks for reading this far.

    Winchestermili


    Winchestermili

    • Moved by Amanda Zhu Tuesday, December 2, 2014 7:36 AM better forum
    Monday, December 1, 2014 6:13 PM

Answers

  • Frank Thank you for your post. We have been in conversation for some time now and perhaps the distance has prevented full appreciation of what we want to achieve. We are very aware of the time and patience that you have taken in dealing with this but now, after one month we need to bring this matter to a conclusion. We are sorry that we have been unable to explain ourselves and our objectives but New Year New Project. Thank you for all your time and effort. Keith and Margaret

    Winchestermili

    I think I just got fired.

    So you just want to end it here then? At the very least, please close this thread by marking one or more posts as the answer please.


    Still lost in code, just at a little higher level.

    :-)

    Friday, January 2, 2015 12:48 AM

All replies

  • Jet drivers are a fact of life if you want to use Access.

    I suggest you convert to SQL Server Express, which is very well supported in VS. Once you convert your Access DB to a .mdf file, you can easily use that file as a datasource in your new app.

    As you are new to .NET development (very different from the old VB), you'll probably have a lot of questions as you go. I recommend the helpful VB experts in the VB forum as your best source of information:

    https://social.msdn.microsoft.com/Forums/en-US/vbgeneral/threads

    I realize this is, at best, only a partial answer to your questions, and I hope other readers here will add to the thread.

    Monday, December 1, 2014 6:46 PM
  • With regard to National Guidelines I don't know where you get your data. If it's SR27 ascii delimited text files I downloaded those from www.ars.usda.gov - SR27 download files and downloaded the largest one. Which comes to 47,316,992 bytes on disk and the .PDF with it is only 557,056 bytes on disk.

    That's not alot of size on todays PC's. Since the files are text delimited files I suppose it would be simple enough just to use them that way. As the .PDF has 5 tables I believe that explain the interoperation required for using the files relationally. Below is an image of a flow chart I suppose of how to do that. The .PDF has 153 pages.

    I also downloaded the 1.1 MB Ascii SR27 delimited text file but its fields would have to be known to understand how to use it. It's formatted like below. I think it would be simpler to use the 47 MB files as the information would be simpler to understand perhaps based on all of the extra information availalbe for items perhaps.

    As far as outputting to word and excel files Office Automation using VB.Net I believe can do that. But I don't have Office installed on my system. And I don't know the ins and outs of how to program for different versions of Office (older, newer, 32 bit or 64 bit) that may be installed in school districts.

    WPF is much more capable than Windows.Forms with regard to control features and capabilities. However your app will need to be compiled to the .Net framework available at schools. And Visual Studio 2013 is probably defaulted to .Net 4.5. Also .Net 4.6 is coming out soon I believe. Usually .Net 4.0 should be available as Windows XP SP3 and newer OS's support that. It's even possible your app could run under .Net 4.0 client but that would need to be known prior to installing it.

    You can alter the .Net framework for Visual Studio to use whenever it starts so you don't have to remember to change your apps application properties to a different .Net framework whenever you create a new app. Which if you want to stick to .Net 4.0 makes it simpler to alter VS for that whenever it starts. Once you create an app in .Net 4.5 you can alter its settings to use .Net 4.0 though and whenever you open that app again in VS it will still stay at .Net 4.0 even if VS's default is .Net 4.5.

    WPF has been around since .Net 2.0 I believe. I've used it a bit. Windows.Forms is kind of outdated really with regard to developing apps for commercial use in my opinion but WPF requires more knowledge due to its use of both XAML and VB.Net. I really only program with Windows.Forms and have done just a bit with WPF. But WPF is way "snazzier" capable than Windows.Forms as it supports a whole range of features that Windows.Forms controls don't have and it's graphics are much better (I forget what they're based on). But the learning curve for WPF is much greater than Windows.Forms.

    Perhaps it would be simpler to output data to a .PDF file unless it needs to be altered for some reason after it is output. As .PDF's can be printed, adobe reader is free and you can use adobe reader active x client I believe it is called in a Windows.Forms app and most likely a WPF app. Then you wouldn't have to worry about MS Office.

    ~01001~^~BUTTER,WITH SALT~^15.87^717^0.85^81.11^2.11^0.06^0.00^0.06^24^0.02^2.00^24^24^643^0.09^0.00^0.00^1.00^0.00^5.0e-03^0.03^0.04^0.11^3.0e-03^3.00^0.00^3.00^3.00^18.80^0.17^2499^684.00^671.00^0.00^158.00^0.00^0.00^0.00^2.32^1.50^60.00^7.00^51.36^21.02^3.04^215^5.00^~1 pat,  (1" sq, 1/3" high)~^14.20^~1 tbsp~^0
    ~01002~^~BUTTER,WHIPPED,WITH SALT~^15.87^717^0.85^81.11^2.11^0.06^0.00^0.06^24^0.16^2.00^23^26^659^0.05^0.01^4.0e-03^1.00^0.00^5.0e-03^0.03^0.04^0.11^3.0e-03^3.00^0.00^3.00^3.00^18.80^0.13^2499^684.00^671.00^0.00^158.00^0.00^0.00^0.00^2.32^1.50^60.00^7.00^50.48^23.42^3.01^219^3.00^~1 pat,  (1" sq, 1/3" high)~^9.40^~1 tbsp~^0
    ~01003~^~BUTTER OIL,ANHYDROUS~^0.24^876^0.28^99.48^0.00^0.00^0.00^0.00^4^0.00^0.00^3^5^2^0.01^1.0e-03^0.00^0.00^0.00^1.0e-03^5.0e-03^3.0e-03^0.01^1.0e-03^0.00^0.00^0.00^0.00^22.30^0.01^3069^840.00^824.00^0.00^193.00^0.00^0.00^0.00^2.80^1.80^73.00^8.60^61.92^28.73^3.69^256^12.00^~1 tbsp~^205.00^~1 cup~^0



    La vida loca





    Tuesday, December 2, 2014 7:18 PM
  • Winchester,

    One thought is to use XML as your "read-only data".

    It's universally applicable to many things, including what we can do with it. Unless your program writes back to it, then there's really nothing that would alter it - short of someone maliciously tampering with it anyway.

    JSON is another option - but I'm not a fan of JSON, even though it's fast becoming a de facto replacement for XML.

    *****

    If you'd care to tell me more about this whole thing I'd enjoy helping you put together a WinForms program for it.


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 2, 2014 7:47 PM
  • Here are some thoughts

    • If you create a new MS-Access 2007 database and import the data from the MS-Access MDB database you will find that bloating is not a problem anymore. The following VS2012 (VS2013 compatible) project shows read, add, edit operations. 
    • JSON is plain text structured, fast to work with, ugly and difficult to edit manually. JSON is great for web apps.
    • XML can work but you then must code things yourself that are already in databases such as using generic SQL-92 compliment SQL via a managed data provider such as OleDb or SqlClient.
    • If using SQL-Server that needs to be installed on the client machine along with your app.

    Simple read example where Builder object is shown in the link I provided above

    Public Sub LoadDemo()
        Using cn As New OleDb.OleDbConnection With {.ConnectionString = Builder.ConnectionString}
            Using cmd As New OleDb.OleDbCommand With {.Connection = cn}
                cmd.CommandText =
                    <SQL>
                        SELECT 
                            Identifier, 
                            Process, 
                            CompanyName, 
                            ContactName, 
                            ContactTitle, 
                            Address, 
                            City, 
                            PostalCode, 
                            Country
                        FROM Customer;  
                    </SQL>.Value
    
                cn.Open()
    
                Dim Reader = cmd.ExecuteReader
    
                If Reader.HasRows Then
                    While Reader.Read
                        Console.WriteLine(Reader.GetString(2))
                    End While
                End If
    
            End Using
        End Using
    End Sub


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem.

    Tuesday, December 2, 2014 8:04 PM
    Moderator
  • Kev,

    Ok, let's up the anty here. ;-)

    *****

    Have a web service instead. The return value of a qualified call to it will be in XML (or JSON, they select which), defaulted to XML. Then the XML is very easily parsed.

    :)


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 2, 2014 8:15 PM
  • I agree with Frank. XML would be a good choice since the data is static and can be easily loaded into a DataTable and processed. You should be able to export your Access database table data to XML from Microsoft Access.

    Unless you're interested in learning WPF I would stick with a Windows Forms app.


    Paul ~~~~ Microsoft MVP (Visual Basic)

    Tuesday, December 2, 2014 8:25 PM
  • Kev,

    Ok, let's up the anty here. ;-)

    *****

    Have a web service instead. The return value of a qualified call to it will be in XML (or JSON, they select which), defaulted to XML. Then the XML is very easily parsed.

    :)


    Still lost in code, just at a little higher level.

    :-)

    In a web service it is depends on if you want to squeeze every bloody millisecond in a process then use JSON but your code has to be spot on. For most situation a SOAP header for XML is not going to be an issue thus go with XML.  So I am on your side here, XML. Unless you have a profiler such as Redgate's ANT tool (excellent tool) I doubt we would see a noticeable difference. 


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem.

    Tuesday, December 2, 2014 8:34 PM
    Moderator

  • In a web service it is depends on if you want to squeeze every bloody millisecond in a process then use JSON but your code has to be spot on. For most situation a SOAP header for XML is not going to be an issue thus go with XML.  So I am on your side here, XML. Unless you have a profiler such as Redgate's ANT tool (excellent tool) I doubt we would see a noticeable difference. 


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem.

    SOAP ... that's a good middle point.

    You get to consume it and put in to your database and I get to eliminate the database all together and use my class objects instead.

    Ha! (You already knew how I'd do it all along!)


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 2, 2014 8:43 PM
  • Many, many thanks to you all for such very useful contributions.  The forum is an excellent resource. 

    I have successfully converted the Access mdb into an mdf and tested that I can navigate through all the data using SQL. 

    Mr Monkeyboy - thanks for the dietary information.  My application uses some of the data from the vast Royal Society of Chemistry database and compares an analysis against the UK Government's Dietary Reference Values (DRVs).  There are recent proposals to change the UK/EU food labels. 

    Frank - thanks for your help and the offer for further help.  Where are you based?

    I have taken on-board all the valuable suggestions and will look again at an XML approach.

    Two final questions please:
    1.  The conversion from mdb to mdf has left some fields with extremely long decimal places. e.g. 3.8000000000000003 instead of 3.8.  This appears on about 10% of the numerical data.  Is there a quick way to control the decimal places?  The conversion was by an import into SSMS.
    2.  As previously described the database is a static "file of food data".  Read only, get the data, multiply and move on.  No expansion and no changes to the data.  After creating an SQL Connection and creating the Data Adapter the DataTable is filled.  Is it possible and sensible in this read only scenario to "Close" and "Dispose" of the SQL Connection??  I assume that the DataTable resides on the remote computer and an SQL connection to the network is no longer required??  Again many thanks for the valuable contributions given. 


    Winchestermili

    Wednesday, December 3, 2014 1:51 PM
  • Hello,

    1. Use SQL-Server management Studio to alter table definitions
    2. Use using statements for connection and command, see DataOperations.vb in the following project.
    3. The DataTable resides in memory on the computer running the application, if the app is on the network the DataTable is on the local drive in regards to memory space.

    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem.

    Wednesday, December 3, 2014 2:32 PM
    Moderator
  • Frank - thanks for your help and the offer for further help.  Where are you based?

    I'm in the US (Central Time Zone), but I see that you're going with a database solution.

    That's not my forte but Kevin is very strong with them, so I don't think I'll be able to help here.


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 3, 2014 7:12 PM
  • Thank You Kevin - just a brief clarification please - your comments above refer to "Use using statements".  My "plan"  was to use the approach set out in the following tutorial - http://www.vbtutor.net/index.php/visual-basic-2013-lesson-34-working-databases-creating-connection/.  That creates the DB Connection and creates the TableAdaptor and the DataTable.  Then the approach allows a one-line Visual Basic call to retrieve specific data - MyDataTbl.Rows(row_number)(“VitaminC”).  Is the "using" method a better approach remembering that it is a read only data source.   Also, on closure of the application, is it good practice to set the DataAdaptor and the DataTable to "Nothing" or will the "END" statement have the same effect and release memory?  I plan to "Close" and Dispose of the Connection after creation of the DataTable.  Thank you for your help.


    Winchestermili

    Thursday, December 4, 2014 10:16 AM
  • I agree with Frank (and Paul) about the XML file on this. A database adds nothing for you then installation problems.

    I disagree with Paul about the WPF solution. Going on with Windows Forms is going on with a presentation format Microsoft left 7 years ago.

    WPF is a little bit confusing if you use it for the first time. But it is nothing else than making the Presentation more changeable outside a designer.

    A pity is that it uses more general used names for properties than the old Windows Forms ones.

    (Be aware, I'm the one who often does not agree with Frank about his choice for an XML file and choose then a database)


    Success
    Cor

    Thursday, December 4, 2014 10:36 AM
  • I agree with Cor Ligtherts post on this.

    I kind of wish I had started programming WPF apps but when I started self learning VB a couple of years ago. I didn't want to use Console apps and didn't know what WPF was and Windows Forms was plainly simple to use off the bat (numerous source code available for it with regard to the controls and everything being plainly recognizable). WPF has some really neat capabilities though that you may realize when developing your app.

    Also do you have links to these "Royal Society of Chemistry database and compares an analysis against the UK Government's Dietary Reference Values (DRVs)" with regard to data from them? Do you have to go online with each app to access the RSofC database or do you download data for use from that database for use with your app prior to creating an install for your app? Not that any of that really matters I suppose but may be of interest to other responders trying to assist you.

    With regard to XML I've only used it a bit but the formatting is easy to read and understand in an XML file for the ones I've used and read in my opinion.

    But I don't know on a network how an app can be installed on a server then used by anybody from the server as I've never done that even though I've read about it. Or if an app is provided to each client what the difference for the IT dept may be in providing database access at a central location rather than XML files to each app. And then if the server goes down for some period the database may not be available. Maybe none of that matters.


    La vida loca

    Thursday, December 4, 2014 12:51 PM
  • Hello,

    So if we look at OleDbCommand it implements IDisposable Interface so the Using statement handles disposal.

    public sealed class OleDbCommand : DbCommand, ICloneable, IDbCommand, IDisposable

    In regards to END which is a left over from VB6, better to close a form application by a) closing the main form via Close method on the main form, if you wanted to close the app from another location such as a form, code module or class we can use Application.ExitThread.

    Using the following project code and adding ReadSingleField you can get an idea an alternate way to work without Adapters and control everything.

    Imports System.Data.SqlClient
    
    Public Class DataOperations
        Private CustomerDataTable As DataTable
        Public Function GetCustomers() As DataTable
            Return CustomerDataTable
        End Function
        Public Sub New()
            Me.CustomerDataTable = New DataTable
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = "SELECT Identifier, CompanyName FROM [Customer]"
                    cn.Open()
                    Me.CustomerDataTable.Load(cmd.ExecuteReader)
                End Using
            End Using
        End Sub
        Public Function AddNewCustomer(ByVal Name As String, ByRef NewIdentifier As Integer) As Boolean
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = "INSERT INTO [Customer] (CompanyName) VALUES (@CompanyName); SELECT CAST(scope_identity() AS int);"
                    cmd.Parameters.AddWithValue("@CompanyName", Name)
                    cn.Open()
                    Try
                        NewIdentifier = CInt(cmd.ExecuteScalar)
                        Return True
                    Catch ex As Exception
                        Return False
                    End Try
                End Using
            End Using
        End Function
        Public Function ReadSingleField(ByVal CompanyName As String) As Integer
            Dim Identifier As Integer = 0
            Using cn As New SqlConnection With {.ConnectionString = My.Settings.ConnectionString}
                Using cmd As New SqlCommand With {.Connection = cn}
                    cmd.CommandText = "SELECT Identifier FROM [Customer] WHERE CompanyName=@CompanyName"
                    cmd.Parameters.AddWithValue("@CompanyName", CompanyName)
                    cn.Open()
                    Identifier = CInt(cmd.ExecuteScalar)
                End Using
            End Using
    
            Return Identifier
    
        End Function
    End Class
    

    Usage for the last function, the other parts are in the project link above

    Private Sub cmdFindByCompanyName_Click(sender As Object, e As EventArgs) Handles cmdFindByCompanyName.Click
        If Not String.IsNullOrWhiteSpace(txtCompanyNameFind.Text) Then
            Dim DataOps As New DataOperations
            Dim Identifier As Integer = DataOps.ReadSingleField("ABC Traps")
            If Identifier > 0 Then
                MessageBox.Show(txtCompanyNameFind.Text & " Key is: " & Identifier.ToString)
            End If
        End If
    End Sub

    Now if you want to stick with adapters why not take one step farther and have Visual Studio generate classes for you, examples are found in MSDN Data Walkthroughs.

    Please note that what is used for a database in the end is your choice, a database or XML. If you elect to using XML that is your choice, same thing if you elect to use a database. Personally XML is good for single user but when you get other users into the mix doing write operations we can go South fast.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem.

    Thursday, December 4, 2014 2:13 PM
    Moderator
  • Personally XML is good for single user...

    And that's what this should be - a single user (no matter how many millions of people might use it).

    I've thought about this and the more I do, the more I'm convinced there's no need to have anything (other than the program's installer maybe) online or anywhere else.

    Create a garden variety - not SOAP - XML file, include it in the resources, parse in the program and use it directly from there.

    Going back to two things Winchester said originally:

    The data used is "static" - it does not change it is simply a "read only" file - get the data, multiply for mass and add up each category (energy, vitamins and minerals).

    Based on that then why have it anywhere other than directly IN the program itself?

    *****

    Winchester, if you want me to embellish this notion and explain how the data can be parsed and used, then let me know please.


    Still lost in code, just at a little higher level.

    :-)

    Thursday, December 4, 2014 3:00 PM
  • @Frank,

    That was my thought as well. However there is one thing against it "Size", in memory a XML file with all its identifier texts can be huge.

    I think it is better to keep the XML file outside the program. 

    Then it can be loaded at load time into a List of the Class.

    I've seen samples given by you for that, so I leave this to you.

     


    Success
    Cor

    Thursday, December 4, 2014 4:03 PM
  • @Frank,

    That was my thought as well. However there is one thing against it "Size", in memory a XML file with all its identifier texts can be huge.

    I think it is better to keep the XML file outside the program. 

    Then it can be loaded at load time into a List of the Class.

    I've seen samples given by you for that, so I leave this to you.

     


    Success
    Cor

    Well, until we see the data (and schema), there's no telling if it would be prohibitive. If attributes can be used rather than tagged elements, that would cut it down considerably. Also, it can be done inside a resource-only .dll file, so that's also an option.

    Putting it online isn't necessarily a bad idea, but if so then I have some suggestions there also.

    First, have the program create an application-specific AppData folder and the program first looks to see if the XML file is in that folder. At first it won't be so that can be used to then load the XML from online and save it into the AppData folder.

    There's no comparison to speed when it comes to loading it from a local file compared to loading it  from an online source - I don't care how fast the connection is - the local file will always load much more quickly.

    As for knowing when it's been updated (which may very well be "never"), a second file could be used. A very small single-line text file which has the XML's build datetime as UTC in it. The DateTime from the online file would be compared to the local XML's CreationTimeUTC.

    If the user doesn't have internet access, use the one they have already, or if they have internet access, it'll look to see if there's an update to the data. I definitely like that idea and it removes it from being carried around in the program or even in the installer (which is something to consider - have the installer put that first one in the AppData folder).

    I like that idea but it's contingent on the user having internet access at least once. That might not be a big deal, but I wanted to at least toss the idea out.

    SOAP can be used and the fact that it's set up to be read by lots of things is good - but - not so good. Maybe. ;-)

    The benefit of SOAP is that it creates references (for reference types, like strings) the same that binary serialization does, but the drawback is that if there's not a lot of repeating reference types in there, that's a very large (bloated in my opinion) XML file.

    A plain old everyday no frills XML file which may or may not have nested elements (depending on the data) will probably be a smaller file. Again though, it's all speculation until we can see the data and the schema (in particular if it contains relations between data tables).

    It'll be interesting to see if Winchester wants to pursue this idea.


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Thursday, December 4, 2014 4:39 PM ...I typed in "user specific" but I meant "application specific"
    Thursday, December 4, 2014 4:20 PM
  • This is all sounding way more complicated than it needs to be. If it's a local file then SQL Server or Express is overkill. Based upon the description by the OP the file isn't very large to begin with.

    If you want high performance with the ability to manage the data I would go with an embedded database such as SQL CE or SQLite, or just stick with Access and compact the database periodically.


    Paul ~~~~ Microsoft MVP (Visual Basic)

    Thursday, December 4, 2014 5:19 PM
  • Winchester,

    It’s a bit disappointing that we’ve not heard back from you. Because of that, I don’t have your data and don’t know the schema of course, so instead I took the data from the USDA Nutritional Database as cited earlier in this thread by Monkeyboy.

    I didn’t use all that’s there – and I don’t see a need to. It’s as much to do with the research and testing methods used (and references to those who performed the research) as it is about the actual nutritional data.

    They offer an “abbreviated” version which is what I used, although I embellished. I very intentionally flattened out one part of it: The food groups.

    I wanted this one to have the food groups but rather than creating a class for those and a reference from each of the 8,618 food items, I put them in along with each entry. That does make for duplicated data which is a waste, but it also allowed me to slim down the XML file.

    You can view the XML file on my website here – and it weighs in at [about] five megs. I realize that the data looks arcane but that was done not for obfuscation but for character count, keeping everything as small as reasonable. Think about it: There are 8,618 entries with 54 fields for a total of 465,372 data points total. To only be five (5) megs is pretty good I think! ;-)

    So long as the class knows how to ‘decipher’ it, I don’t see a problem with doing it that way.

    I put the whole class together (not including the part that created the data) into a namespace and you can have a look at the code on a page of my website here. Also, if you’re interested in experimenting with it – and I hope you will – I have that namespace file zipped up and uploaded here. The easiest way to get a feel for the overall class called “FoodComposition” is to have a look at the class diagram as shown here.

    I’ve changed my mind about a few things along the way that I’ll explain next.

    First, the XML file is NOT saved to the user’s computer; a binary file is instead:

    Notice where that file is placed (I’m on XP if you haven’t surmised that yet) – which is common to the users of the computer. There’s no need to have but one copy somewhere because it’s read-only.

    It’s not as small as I’d like but that’s mainly because of the way that the binary serializer treats strings. When you first look at the contents you’ll see this:

    …but when you scroll down some, you’ll see this:

    This file would zip pretty well so that’s an option if you want to do that. It would take more time to compress/decompress but it would cut down the file’s size a fair amount (speculation but I feel certain it would).

    If you create a new project for experimenting then add that namespace to it (in Solution Explorer, right-click and choose Add >> Existing Item, then browse to where you extracted the file from that zip file), in the form’s .Load event you might want to do something like what I did to test it:

    Option Strict On Option Explicit On Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim sw As New Stopwatch sw.Start() Dim fcList As New List(Of USDA_Nutrient_Data.FoodComposition) Dim url As String = "http://www.fls-online.com/VBNet_Forum/12-06-14/Nutrition.xml" If USDA_Nutrient_Data.FoodComposition.NutritionDataNeedsToBeUpdated(url) Then USDA_Nutrient_Data.FoodComposition.ImportFromXML(fcList, url, USDA_Nutrient_Data.FoodComposition.FileStringType.URL) USDA_Nutrient_Data.FoodComposition.Save(fcList) End If If fcList.Count = 0 Then USDA_Nutrient_Data.FoodComposition.Load(fcList) End If Dim ndbNumbers() As String = USDA_Nutrient_Data.FoodComposition.GetAllNutrionalDataBaseNumbers(fcList) Dim fc As USDA_Nutrient_Data.FoodComposition = USDA_Nutrient_Data.FoodComposition.GetItemByNDB(fcList, ndbNumbers(10)) Dim groups() As String = USDA_Nutrient_Data.FoodComposition.GetAllFoodGroups(fcList) Dim foods As List(Of USDA_Nutrient_Data.FoodComposition) = USDA_Nutrient_Data.FoodComposition.GetFoodsInFoodGroup(fcList, groups(1)) foods = USDA_Nutrient_Data.FoodComposition.GetFoodsInFoodGroup(fcList, "egg", True) sw.Stop() Stop End Sub End Class



    I realize this isn’t what you want – I have no way to know what you have or what you want to do with the data so this is really just food for thought (pun intentional). :)


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Saturday, December 6, 2014 7:20 PM ...modified the link to the class diagram. I had it showing the thumbnail, not the full-size image.
    Saturday, December 6, 2014 7:04 PM
  • Apologies for the delay but a winter cold has wiped me out for a couple of days.  I have considered all the proposed options and have tried SQL(my dataadaptor and Kevin's better version).  I have looked at simply loading the data into memory from a datafile and I have looked closely at XML.  XML seems a very sensible route because of the "small" volume of read-only data.  So I used "Zamzar" to convert an xlsx spreadsheet into an XML file.  It has produced some strange headers (Records, Record, Row) but I can tidy that up later.

    I have created a simple app which has a DataSet control added to the Main Form and the XML data can be read.  This appears to have been achieved with "one" line of code:

    NutrientsDataSet.ReadXml(filePath)

    I have loaded the data into a DataGridView control and can review the data.  I can successful access each line of the database using a single call which will be improved into a function, e.g.:

    foodname = CType(NutrientsDataSet.Tables("Row").Rows(n).Item("E"), String)

    VitaminC = CType(NutrientsDataSet.Tables("Row").Rows(n).Item("U"), String)

    where "n" is the fooddata row in the XML file.

    There seem to be several ways to read the XML data and I am left wondering if this is the most appropriate.  Some methods involve FileIO which seems unnecessary??

    The data needs to be local to the program because in UK schools the access to the internet my be very busy and response will be slow.  Not good for the concentration of 15 years olds.  Anyway, the one "simple" thing that I cannot get to work is the "resx".  I have added the XML to the application Resources but no matter what I simply cannot get the application to change the filepath to the Resources folder:

    filePath = My.Resources.NutData                 OR
    filePath = Nutrients.My.Resources.ResourceManager.GetObject("NutData")

    The Food Data originates from the UK Royal Society of Chemistry.  We could get access to electronic data but as Frank pointed out we suffer the same format issue of the data.  It can be read but we are using a tiny proportion of the data available (about 10%).  The software is an educational tool for 11 to 16 year old students.  The data is published in a book called - The Composition of Food by McCance and Widdowson published by the UK Food Standards Agency:  http://www.amazon.co.uk/McCance-Widdowsons-Composition-Foods-Seventh/dp/1849736367

    We have 866 foods already from the VB6 access database so we will check each element of data and increase the number of foods to about 1000; based mainly on the feedback by the users.  Also the database contains additional information that we have added; such as typical portion sizes, mass of a teaspoonful, REMEMBER to add milk and sugar, ideas to Labels...............

    So, in summary, is adding a DataSet control and then calling NutrientsDataSet.ReadXml(filePath) the most appropriate method??

    I need to have the data locally available to avoid sluggishness when numerous school students access the application at once.  But I simply cannot make the My.Resources.NutData work............

    Many thanks for all the help and interest shown.

    Winchestermili


    Winchestermili

    Sunday, December 7, 2014 9:37 AM

  • Winchestermili

    Sunday, December 7, 2014 9:55 AM
  • Winchester,

    Is the Excel file proprietary? What I'm getting at is this: I can give you an URL where you can upload the file to my FTP server - unless it's something that you'd prefer not to do?

    Would I be correct that it's "flat" (no relations) data? If so it'll be pretty simple and I'll go back to what I had in mind originally: Storing the XML file locally but periodically checking for updates online.

    I initially thought about having it IN the program - in the resources - and that still may be an option but updating it would be cumbersome.

    As for using a DataGridView, once you have the data set up in something which supports encapsulation (whether that's a class as with my example, or a DataRow in a DataTable), you can do a multitude of things.

    What are you using the DGV for though?

    Let me know your thoughts please.


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 7, 2014 2:11 PM
  • Winchester,

    Here's a way we can get started. I just put a little program together that has my XML file in the resources:

    I have the project folder zipped up and uploaded here.

    When you download and extract it, your version of Visual Studio will prompt you to convert it to your version (I'm on a much older version here). You can see what it does:

    Option Strict On Option Explicit On Imports System.IO.Path Imports System.Environment Public Class Form1 Private programDataFolderPath As String = _ Combine(GetFolderPath(SpecialFolder.CommonApplicationData), _ My.Application.Info.AssemblyName) Private xmlFilePath As String = Combine(programDataFolderPath, "Nutrition.xml") Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load WriteXML_ToFile() End Sub Private Sub WriteXML_ToFile() Try If Not My.Computer.FileSystem.DirectoryExists(programDataFolderPath) Then My.Computer.FileSystem.CreateDirectory(programDataFolderPath) My.Computer.FileSystem.WriteAllText(xmlFilePath, My.Resources.Nutrition, False) Process.Start(programDataFolderPath) End If Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub End Class


    This is just to get the idea going - When the program starts it will run the sub which looks to see if the folder exists. If it doesn't then it will create it, save the XML file to that folder, then open the folder so you can have a look at the file (and where it put it on your computer).

    Doing it this way rather than parsing the XML directly from the resources will make it easier later when the data needs to be updated.

    Give it a try if you will please.


    Still lost in code, just at a little higher level.

    :-)


    Sunday, December 7, 2014 2:52 PM
  • Hi Frank

    Thank you very much for the excellent explanation and the encouragement to go forward.

    The Excel file is not "proprietary" in so far we have, under UK licence, entered Royal Society of Chemistry (RSC) copyright data into a file.  In that respect the IPR lies with the RSC and not with ourselves.  Then we added our own comments for students to be able to use the database.  You are welcome to view the XML that has been created.  If you prefer you can review the data in xlsx, mdb or xml format.  The data is "flat" (self contained with no outside influences or relations) (what is in the tin, stays in the tin) and any update would be through a new release of the software.  At this stage I do not see any great need to add complexity by introducing an on-line update for the food data.  Who knows that might come later - please remember that my experience was a VB6 program many years ago....  An on-line database update might come later if users see a need.

    The DGV was a point of frustration!  It was simply so that I could see the data had arrived where I wanted it.  If you look at the NutData.xml you will see three "headers": "Records", "Record", "Row" - it took a long time for me to realise that the "Table" name was "Row"........  In Frank's xml file there are two "headers" called "Nutrition" and "Data" - the Table is called "Data". 

    Frank - Thank you so much for the VS demo that you sent - greatly appreciated.  I have placed a DataSet control on Form1 and used NutDataSet.ReadXml(filePath) to fill the DataSet.

    I can successfully cycle through all the food names using:
    Dim n As Integer
    n = CInt(NumericUpDown1.Value)
    Label1.Text = CType(NutDataSet.Tables("Data").Rows(n).Item("n3"), String)

    I really like the proposed approach.

    Best Wishes


    Winchestermili

    Sunday, December 7, 2014 8:04 PM
  • Hi Frank

    Thank you very much for the excellent explanation and the encouragement to go forward.

    The Excel file is not "proprietary" in so far we have, under UK licence, entered Royal Society of Chemistry (RSC) copyright data into a file.  In that respect the IPR lies with the RSC and not with ourselves.  Then we added our own comments for students to be able to use the database.  You are welcome to view the XML that has been created.  If you prefer you can review the data in xlsx, mdb or xml format.  The data is "flat" (self contained with no outside influences or relations) (what is in the tin, stays in the tin) and any update would be through a new release of the software.  At this stage I do not see any great need to add complexity by introducing an on-line update for the food data.  Who knows that might come later - please remember that my experience was a VB6 program many years ago....  An on-line database update might come later if users see a need.

    The DGV was a point of frustration!  It was simply so that I could see the data had arrived where I wanted it.  If you look at the NutData.xml you will see three "headers": "Records", "Record", "Row" - it took a long time for me to realise that the "Table" name was "Row"........  In Frank's xml file there are two "headers" called "Nutrition" and "Data" - the Table is called "Data". 

    Frank - Thank you so much for the VS demo that you sent - greatly appreciated.  I have placed a DataSet control on Form1 and used NutDataSet.ReadXml(filePath) to fill the DataSet.

    I can successfully cycle through all the food names using:
    Dim n As Integer
    n = CInt(NumericUpDown1.Value)
    Label1.Text = CType(NutDataSet.Tables("Data").Rows(n).Item("n3"), String)

    I really like the proposed approach.

    Best Wishes


    Winchestermili

    Winchester,

    That's a lot to take in all at once, but let's start with this:

    This is the URL to my FTP server.

    If you will, please create a new folder then you can put whatever you want in there. I'd prefer to see it the way it originally is (Excel?), but whatever you want to include is fine. Please do be aware that it will then become public but if you want me to remove it once I download it, let me know and I'll do that.

    You don't need a control of any sort to "hold" the data - that's what encapsulation is for but let's get there when we get there.

    If you're sure that you'll never need to do online updates, I'll just parse it directly in code from the resources, but please do give that thought. Updating the entire program for a data update will get really old really fast! Been there done it! ;-)

    I may not reply right away but please don't think I've abandoned this. :)


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 7, 2014 8:17 PM
  • Hi Frank

    I have created a new folder called "winchestermili" at that URL and uploaded both the original mdb and the xlsx.  Might be a good idea to delete from the server once you have downloaded please.  I know that you are right about the on-line updating so please could we plan that in for a future improvement...

    Thanks for your time


    Winchestermili

    Sunday, December 7, 2014 8:34 PM
  • Hi Frank

    I have created a new folder called "winchestermili" at that URL and uploaded both the original mdb and the xlsx.  Might be a good idea to delete from the server once you have downloaded please.  I know that you are right about the on-line updating so please could we plan that in for a future improvement...

    Thanks for your time


    Winchestermili

    Ok I have it and I've removed it from the FTP server.

    I have to leave here for a few hours but I'll have a good look at this either tonight or tomorrow.

    Up to this point we've more been talking about "the data", not so much the program itself. Can you give me an idea of what it does and all that?

    I'll get back to this soon. :)


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 7, 2014 8:40 PM
  • Hi Frank

    I have created a new folder called "winchestermili" at that URL and uploaded both the original mdb and the xlsx.  Might be a good idea to delete from the server once you have downloaded please.  I know that you are right about the on-line updating so please could we plan that in for a future improvement...

    Thanks for your time


    Winchestermili

    Winchester,

    I have some questions about the data. You said that it's "flat" but looking at the Access database, I can see that's not how it was originally set up - or at least that's how it appears.

    First I wanted you to know that just because we want one single .xml file, that doesn't mean that it can't contain multiple "datasets" (for lack of a better way to put it). It can have as many as you want in there and I'll show you how if/when we get to that point. I didn't do that in my example from the other day, honestly, just out of laziness. ;-)

    I also have some questions about the meanings of some of the fields (columns) and other questions, but so not to get things confused, please give me a detailed explanation about what the program is and does. That itself might help resolve some of the confusion.


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Sunday, December 7, 2014 11:35 PM ...typos (typical of me)
    Sunday, December 7, 2014 10:54 PM
  • Frank

    Please have a look in the "winchestermili" folder at your URL.  The key stages of this educational program are:
    1.  See top image.  The food data is listed in about 20 categories - left hand listbox.  Selecting a category displays the foods in that Category in the RH Listbox.

    2.  Selecting a food opens the "Input Amount" dialogue.  You can select a food and then use the "Add to list" button, OR double click the food OR drag the food from that Category to Your Food list.

    3.  A mass is entered and the "Food List" is added to  - see the green list on the RH side.  Most foods have "Portion information" which we added to assist students in entering an appropriate amount.  A simple "calculator" was also added to allow division of amounts from a recipe.

    4.  A completed list can then be Analysed - see the RH window.  each food is checked and each attribute is modified for mass and summated.  The data can also be exported to Excel and tabulated results are produced for further analysis by the students.

    5.  In the UK the government guidelines are based on Dietary Reference Values (DRVs) - historically these were called Reference Daily Amounts (RDAs) but that has been superseded

    6.  The summary data from the Analysis is compared for a PRATICULAR age group.  There are about 20 different groups ranging from boys, girls, men, women across varying age groups.  Each attribute is compared with the DRV - and 3 columns are given.  The food list total, the guideline DRV and a percentage of the DRV achieved.

    7.  The same comparison is also displayed graphically as a series in a bar chart having a 100% DRV reference line.  The energy breakdown (Prot/Carb/Fat) is displayed as a pie chart.  This DRV comparison is exported to Word for further anlysis by the student

    8.  An Investigate window slices the data in the "opposite direction".  Each element is examined across the list of foods.  The example only shows energy.  The students can easily identify which  foods have the most fat or salt or which foods provide the Vitamin C or Niacin.  That data and the bar chart is exported to Excel.

    9.  A Food Label designer is provided.  This area will change the most due to new UK/EU requirements.  The food list is analysed and a "portion divider" provided incase a recipe is to be divided into a number of servings (4 in this case).  The export to Word also allows a selection of three different food lables.  The Word output contains the food list the label text and a "high/low" style graphic.  I was thinking about using a templte for the typical graphics because these might change and users could download a new template or design their own.


    Winchestermili

    Monday, December 8, 2014 9:45 AM
  • Hi

    Just to fill in some background of what this is about.  My wife is a school teacher in Winchester, UK, teaching Food Technology (you might call it Food and Nutrition) for 11 to 16 year old pupils.  As part of the education "technology" curriculum it was required that numerical analysis had to be taught.  Many years ago she brought home a revolting piece of software - pupils were given a pamphlet which listed about 500 foods.  The pupils read the list and entered a number from that list which represented the food.  The data had to entered at the "Command Line" as a specific format 

    foodnumber, mass_in_grams

    e.g 123, 120  or 120 grams of baked beans.  This became impossible because there was no error trapping for large masses, or for food numbers > 500 or for no spaces or two spaces in the input.  Then the user had to enter "M" or "F" for male or female but if lower case was entered the program crashed.  The programmer did not reply to my letters (yes - before the days of email) so I modified the program for my wife's school.  She then decided that it was using the wrong data anyway.  So I set about writing a new program BUT for the Acorn Computer's platform - you might have heard of a BBC Micro?  When Acorn went out of business I was asked to re-write it using Visual Basic; hence the VB6 program. 

    That program was designed to look and feel like the existing version of Word - with the same icons and button bar.  It looks very dated now.  The food data that is used has been superseded, the DRV data (government guideline daily amounts), some pupils have requested additional foods, food label requirements have changed.  Hence the need for a new program.


    Winchestermili

    Monday, December 8, 2014 10:10 AM

  • That program was designed to look and feel like the existing version of Word - with the same icons and button bar.  It looks very dated now.  The food data that is used has been superseded, the DRV data (government guideline daily amounts), some pupils have requested additional foods, food label requirements have changed.  Hence the need for a new program.


    Winchestermili

    And because of that I stay with my replies about WPF and XML. WPF gives you the latest look and feel (also usable on W8) while XML (not embedded in your program) gives you the chance to add foods on a regular base while not changing the program.

    Success
    Cor

    Monday, December 8, 2014 2:55 PM
  • Winchester,

    That's quite a lot then.

    *****

    I'd like to ask about the data itself. In the Excel file you sent, I see "db_Number" and "V2_db_Number". Would you explain those please?

    The column "MandW" - what is that? It looks like maybe a reference to something? I have the same question about the numbers shown in "Category".

    For the column "foodname", are those unique or do they repeat somewhere in it?

    The columns "retinol" and "carotene" are both blank all the way down as best I can tell. Are those going to be filled in later?

    Lastly is "typort1", "typort2" and "Labnote". Explain those please?


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 8, 2014 3:07 PM
  • Hi Frank - The data format...

    The first column is not really needed - a bit of a throwback to my first attempt to add a control to a VB6 form about 25 years ago; so admittedly, db_number is simply a sequential database row.  My wife had a bad habit of re-sorting the data so it gave an immediate way of re-sorting the data.  The second column is more important because currently the program stands at Version2.  Version 3 will have more foods so for backward compatibility I can accept a food list saved under V2 and check if the food all are present but with new V3 row numbers and offer the choice to update.  So V2_db_number is the same a column 1 until new foods are added.

    "MandW" is a quick reference to the source of the Royal Society of Chemistry Data which is published in McCance and Widdowson's book.  That gives a unique cross reference for immediate access.  From memory I do not think that it appears in the program output.

    The Categories are "Food categories" - e.g. "pears" appear in "Fruit".  Please have a quick look at the Word file that I posted.  So, when loading a ListBox the program knows which foods to put in each category.  No doubt you have a far more intelligent way of categorisation, but look at the "Nutrition" database and you will see significant space is taken by category names.  A number reference was used simply for space.

    "foodnames" are unique - but my wife slightly re-worded a few of the original names to be more user friendly.

    Vitamin A can be estimated from retinol equivalents.  VitA = ug retinol + (ug beta-carotene eqiv)/6  For V2 we did the calculations on a calculator and entered them.  This time, for accuracy, we will enter the retinol and carotene values and calculate in a VitA cell.  Then those two columns will be redundant as far as the program is concerned.

    11 to 16 year old students lack cooking experience.  So to assist them in adding suitable masses my wife measured and weighed many foods.  The information was added as "typort1 and 2" two lines of Typical Portions, e.g. "one bagel weighs 90g" (well, it does in the UK).

    Many of the "typical portion" size comments were the same or similar so a simple "#x" was used to save space.  The program sniffed the "typort" column for the # and looked up the appropriate portion size comment.  This was also the case with guidance notes for the information when a food label was produced.  The Label name is simply an abbreviated name for students to use in a food label - it simplified "yogurt, virtually fat free, plain *" down to "diet yogurt".

     


    Winchestermili

    Monday, December 8, 2014 6:30 PM
  • Winchester,

    I think I understand and we'll need a few "datatable relations". No I'm not using datatables but that's the easiest way to explain the concept.

    It'll become more clear once I actually start to put it together, or I should say, the next round of questions will. ;-)

    I don't understand the purpose of the db numbers though - maybe it made sense (the primary key maybe?) in a database, but I don't see any use for them here. Do you agree?

    I do need something to test for being unique though - otherwise I can't test for duplicates. Do you think the food names are unique enough for that purpose (now and in the future)?


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 8, 2014 6:53 PM
  • Frank - Agreed - the first column is no longer needed - except that it is an instant resorter during development. Ideally the data should firstly be sorted by category and then sorted alphabetically by food name. This (in my opinion) would be the way to pour the categories of foods into a ListBox control - I suspect that I am about to learn a lot more about xml...... It is safe to assume that each food name is unique. Because we have reviewed the source data a few times we have annotated the book containing the data, so we are confident. We will ensure that no duplicates exist in the future. Incidentally the copying of the xml file to a ProgramData folder works perfectly. A minor point is that if someone deletes the copied xml file (and they do in schools) then when re-run a problem might occur because the existence of the file in that folder location is assumed

    Winchestermili

    Tuesday, December 9, 2014 1:30 AM
  • Frank - Agreed - the first column is no longer needed - except that it is an instant resorter during development. Ideally the data should firstly be sorted by category and then sorted alphabetically by food name. This (in my opinion) would be the way to pour the categories of foods into a ListBox control - I suspect that I am about to learn a lot more about xml...... It is safe to assume that each food name is unique. Because we have reviewed the source data a few times we have annotated the book containing the data, so we are confident. We will ensure that no duplicates exist in the future. Incidentally the copying of the xml file to a ProgramData folder works perfectly. A minor point is that if someone deletes the copied xml file (and they do in schools) then when re-run a problem might occur because the existence of the file in that folder location is assumed

    Winchestermili

    Wow you're up late - or early!

    *****

    XML is just a storage mechanism - "data" - nothing more, but I can put what we need in there and I'll show you when we get that far.

    *****

    I'll set up methods to get the data in a number of ways - whether you use a ListBox or other control, the "getting" will be a cinch, including parameters for filtering and sorting. I'm not there yet but I've done it many times so I do have a decent idea of what I want from it.

    I'd like to learn more about the calculated values though. If there are any more of them, then all the better; it's data that doesn't need to be stored which makes the "data store" all the smaller.

    *****

    I'm still working out (in my head) how to make sure the data will always be available and how to manage updates either via the internet or by redistributing the program with an update. I'm sure we'll come up with a way to do this though.

    *****

    Would you mind having a look at the following PDF files and answer a few questions please?

    This one, from CAT_Pointers is, presumably, the categories? Is there any significance to the first or third columns?

    This one, from DRV, has me confused. Is this duplicate data or if not - please explain.

    This one is, of course, the food names. I notice some have an asterisk. Is that of any significance?


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 9, 2014 2:01 AM
  • 25 years ago my "methods" to obtain which food was selected were not in the "cinch" category.....

    The VitA (from retinol and carotene equivalents) is the only data column that involves a calculation.  No others are planned. Therefore the "retinol" and "carotene" columns can be eliminated when the final xml is produced.

    When a fooditem was selected from a ListBox then the Category Number was already known because it was that category that was used to populate the ListBox.  Therefore, a set of pointers gave the "food_number" of the FIRST item in that selected Category (it is a lookup list).  Then when a food was selected the "List Index" was added to the Cat_Pointer to give the foodnumber.  It was simply a way of linking a foodname TO a database row number.  In hindsight I  could have used the db_number as a ListBox "tag".  Selecting a food would give the database row number.  Any method will do.

    ============

    1.  Cat_Pointers - first and third column issue.......  Margaret, my wife, spent a great deal of time mulling over what foods to include from the RSC database.  She produced many versions of varying size.  To avoid errors and before I discovered an EOF method in Acorn Basic she provided three bits of information in the first column.  There are 21 Categories.  There were 866 foods.  Bottom of "Field2" is the date when that version was completed and Bottom of "Field3" is a checksum for the total number of foods.  This was not sophisticated programming....

    ================

    2.  DRV is not duplicate data, it is the Dietary Reference Value matrix.  There are 29 rows and 11 columns for:

    Energy(kcal), protein, sodium, calcium, iron, vitA, vitB1, vitB2, niacin, vitC, vitD

    Note: there are NO DRV's for fat, saturates, carbohydrates and sugar,   however, fibre does have a guideline value (18grams/day for adults)

    There are 29 records for the 29 DRV Groups:

    Public Sub LoadDRVGroups_into_ToolBar()
    With frmMain.cboToolbar
        .AddItem "boy aged 4-6 months"
        .AddItem "boy aged 7-9 months"
        .AddItem "boy aged 10-12 months"
        .AddItem "boy aged 1-3 years"
        .AddItem "boy aged 4-6 years"
        .AddItem "boy aged 7-10 years"
        .AddItem "boy aged 11-14 years"
        .AddItem "boy aged 15-18 years"
        .AddItem "girl aged 4-6 months"
        .AddItem "girl aged 7-9 months"
        .AddItem "girl aged 10-12 months"
        .AddItem "girl aged 1-3 years"
        .AddItem "girl aged 4-6 years"
        .AddItem "girl aged 7-10 years"
        .AddItem "girl aged 11-14 years"
        .AddItem "girl aged 15-18 years"
        .AddItem "man aged 19-50 years old"
        .AddItem "man aged 51-59 years old"
        .AddItem "man aged 60-64 years old"
        .AddItem "man aged 65-74 years old"
        .AddItem "man aged 75+ years old"
        .AddItem "woman aged 19-50 years old"
        .AddItem "woman aged 51-59 years old"
        .AddItem "woman aged 60-64 years old"
        .AddItem "woman aged 65-74 years old"
        .AddItem "woman aged 75+ years old"
        .AddItem "pregnant woman"
        .AddItem "breast feeding woman (1mth)"
        .AddItem "breast feeding woman (3mths)"
    End With
    End Sub

    Please look at the "Getting Started" summary that I uploaded.  The DRV is for a "boy aged 11-14 years".  The Energy DRV is "2220 kcals" and the VitC DRV is "35mg".  That DRV Group is DRV Group ROW 7 (see above).  Column1 and the VitC Column are the DRVs that are needed for comparison with the ACTUAL DIET.

    I cannot remember why I decided NOT to have the data in the DRV database but instead I put the DRV Group name inside the program as a lookup table when filling a cbo_list in the toolbar.   In hindsight a DRV Graoup name in column 1 would have made a lot more sense.

    These data will be changing and the government will be publishing new guidelines.  Hovever, the broad format should remain very similar.

    ============

    3.  The asterisks against certain foodnames means that the data may not have been tested or is obviously so low that it is not worth testing.  E.g. "Christmas Pudding" (not a US staple) has an asterisk.  The analysis by the RSC did not look at retinol and carotene therefore the VitA is recorded as zero.  However, a Trace of "Vitamin C" was found but not worth recording - hence VitC =0.

    Incidentally, in the MAIN food database Category 19 is for "Bought Savoury Dishes" .  For example foods 736 and 737 have the annotation "ta" or "rm" for "Take Away" or "Ready Meal".  This abbreviation had a boolean switch to show or hide a mini window explaining the abbreviations.  The user could hide the mini-window after first viewing.  Probably more easily achieved with a tool-tip.

    If we are straying away from the main purpose of the MSDN Forum then I could let you have a private gmail address.


    Winchestermili

    Tuesday, December 9, 2014 4:32 PM
  • Winchester,

    I'm sure I'll have to read through all of this several times before I really "get it", but I'm going to start with the basics either today or tomorrow. During the weekdays (I'm six hours behind you, I'm pretty sure), it's difficult because I'm at work.

    I work from a home-office which isn't the panacea that many people think, but nevertheless I am at work in earnest.

    I'll catch you up in a few days. Also, I think I have worked out how the data can be updated whether it's online or a new embedded version in the resources, but until I test it I don't want to explain more right now.


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 9, 2014 5:03 PM
  • Wichester,

    Can you tell me the units of measure for these nutrients? Other than energy, I don't see them shown anywhere (unless I missed it?).


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 9, 2014 10:20 PM
  • Frank - I can sort out the details because I have been there before albeit many years ago. The units are kcala, kJ, grams, mg and ug. Typically retinal and cartene are ug. The details era not important because at this stage they are simply numbers.

    Winchestermili

    Tuesday, December 9, 2014 10:44 PM
  • Frank - I can sort out the details because I have been there before albeit many years ago. The units are kcala, kJ, grams, mg and ug. Typically retinal and cartene are ug. The details era not important because at this stage they are simply numbers.

    Winchestermili

    Ok - I'll proceed without them but I think they actually are important.

    *****

    More later in the week...


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 9, 2014 10:47 PM
  • Winchester,

    Some of this stuff I figured I'd revisit when I got to it and that it would make sense then, however what you said the other makes no sense at all:

    Vitamin A can be estimated from retinol equivalents. VitA = ug retinol + (ug beta-carotene eqiv)/6 For V2 we did the calculations on a calculator and entered them. This time, for accuracy, we will enter the retinol and carotene values and calculate in a VitA cell. Then those two columns will be redundant as far as the program is concerned.

    Your data has the values for Vitamin A, but not for retinol or carotene.

    How should I proceed?


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 10, 2014 6:29 PM
  • Hi Frank

    In Version 2 (the VB6 version) the database only had VitA as an entered value.  We read the retinol and carotene values from the book and did the calculation using a calculator.  Mistakes occurred.

    In THIS Visual Studio application (Version 3) we will enter the retinol and carotene values and use a formula in the VitA cell.  Then the retinol and catotene columns can be "deleted".

    The Excel spreadsheet that I sent you was for Version 2 but with blank retinol and carotene colums added for FUTURE use.  So the final spreadsheet will have values in retinol and carotene and a formula in the VitA column.  Obviously we will need to cut and paste VALUES into the VitA column if we delete the retinol and carotene columns.

    Apologies for the confusion.


    Winchestermili

    Wednesday, December 10, 2014 8:14 PM
  • Hi Frank

    In Version 2 (the VB6 version) the database only had VitA as an entered value.  We read the retinol and carotene values from the book and did the calculation using a calculator.  Mistakes occurred.

    In THIS Visual Studio application (Version 3) we will enter the retinol and carotene values and use a formula in the VitA cell.  Then the retinol and catotene columns can be "deleted".

    The Excel spreadsheet that I sent you was for Version 2 but with blank retinol and carotene colums added for FUTURE use.  So the final spreadsheet will have values in retinol and carotene and a formula in the VitA column.  Obviously we will need to cut and paste VALUES into the VitA column if we delete the retinol and carotene columns.

    Apologies for the confusion.


    Winchestermili

    I'm still confused on where to go from here? Do I remove Retinol and Carotene and leave the Vitamin A or ...?

    *****

    Currently I have three classes started (not completed) and the following shows my initial tests. The following are using the overridden .ToString method so it's just a test to see the data itself:

    Class Name: DietaryReferenceValue

    Class Name: FoodCategory

    Class Name: FoodComposition

    *****

    Please have a look at those. The latter one can't be right because of this confusion and other things regarding the various little "shortcuts" and things like a asterisk here and a "rm" there and all that. I'm trying to decipher it as I go.

    At the end of all of this, you'll have a class library that will allow you to build a program to manage the data (add new, edit existing, remove existing) and rebuild the XML file. I'm nowhere near that point now, so this is just a basic test.

    That same class library will be used in the user's program, but obviously they won't have access to adding/removing and such -- only reading the data.

    Please let me know your thoughts.


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 10, 2014 8:24 PM
  • Frank I have looked at all the three classes that you have created. It all makes absolute sense to me. The opportunity to add to, edie and remove is ideal. I am extremely keen to see the data handling. Thank you so much for your incredible help. Regards,

    Winchestermili

    Wednesday, December 10, 2014 8:39 PM
  • The retinol and carotene colums can be deleted in the xml file used in the program.

    Winchestermili

    Wednesday, December 10, 2014 8:42 PM
  • The retinol and carotene colums can be deleted in the xml file used in the program.

    Winchestermili

    Ok so I just use the Vitamin A values from the database (which I turned into .csv files for my "initial data"), is that correct or did I misunderstand?

    *****

    Please look again at this link.

    A typical one might show this:

    Typical Portion (2 of 2): #19

    What does #19 mean? Will it mean something to them or does it mean that I need to go get something from line 19 or ...?

    Also, please explain the very last column that you're calling "LabNote". I'm currently not doing anything with it but I feel sure that I'm supposed to. ;-)


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 10, 2014 8:47 PM
  • Apologies for the confusion over VitA . Please stick with the method you have used because the program does not need to know anything about retinol or carotene. They are just a means to an end. We might have to have a sub-sheet to enter the retinol and carotene data and use a cell to calculate the VitA and that value will then appear in the final xml file. To save space in the Typical Potions - many of the comments were very similar. Eg a tablespoonful is 20 grams. OR a tablespoonful is 15 grams. To save space an speed data entry these comments were assigned #19 and #20. The program used a simple lookup table to enter the correct comment. A very similar approach was used for the Label Notes Regards

    Winchestermili

    Wednesday, December 10, 2014 9:03 PM
  • Apologies for the confusion over VitA . Please stick with the method you have used because the program does not need to know anything about retinol or carotene. They are just a means to an end. We might have to have a sub-sheet to enter the retinol and carotene data and use a cell to calculate the VitA and that value will then appear in the final xml file. To save space in the Typical Potions - many of the comments were very similar. Eg a tablespoonful is 20 grams. OR a tablespoonful is 15 grams. To save space an speed data entry these comments were assigned #19 and #20. The program used a simple lookup table to enter the correct comment. A very similar approach was used for the Label Notes Regards

    Winchestermili

    Once you get an understanding about how it all works then I suspect you'll get the gist of my questions.

    Since you have some sort of look-up routine ... to a reference that I don't have ... can you provide that so that I can make the correct substitutions please?

    *****

    This is the "initial data" and once I get that and get it to the point that it will write out the "real deal data", you won't have to go back to those routines again.

    In many ways you'll think that I'm using DataTables in a database, but I'm not. This is object binding where I'm creating the objects (instances of a class) and in one case, a reference to another class through an instance of the other class. Specifically I'm referring to the Food Category for each instance of Food Composition.

    That class has a member (exposed publicly as a read-only property) which is an instance of a then already created collection of instances of the Food Categories. I'm betting that's confusing but in time it will make sense. ;-)

    The advantage of doing it this way is in reality there will only be however many instances are in the FoodCategory class - but each instance of FoodComposition references one of them.

    The data isn't repeated; it's a "pointer" to the same place in memory.

    Also, let's say that at some point in the future you decide to rename one of those FoodCategory names. Because it's a reference, the instances of them in FoodComposition will likewise be updated (because it's looking at the same place in memory, and there's only one of them!).

    *****

    I'm rambling here -- for now I'll leave Vitamin A, Carotene, and Retinal as members of the class, but only Vitamin A will be in the XML file when I get that far. I can always modify things later once we're on the same page with everything and you start to actually use it. That's always the best and ultimate test of it all.

    I do need those look-up values though.


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Wednesday, December 10, 2014 10:13 PM ...typos
    Wednesday, December 10, 2014 9:16 PM
  • Frank,

    Your "ramblings" are very welcome.  Many thanks for the explanation.

    There are 22 items in the “#” lookup table:

    Public Function TypicalPortion(text As String)

    Select Case text

        Case "#1": TypicalPortion = "typical portion = 25g"

        Case "#2": TypicalPortion = "typical portion = 30g"

        Case "#3": TypicalPortion = "typical portion = 50g"

        Case "#4": TypicalPortion = "typical portion = 100g"

        Case "#5": TypicalPortion = "typical portion = 200g"

        Case "#6": TypicalPortion = "typical portion = 50 to 75g"

        Case "#7": TypicalPortion = "typical portion = 50 to 100g"

        Case "#8": TypicalPortion = "typical portion = 150 to 200g"

        Case "#9": TypicalPortion = "typical portion = 100 to 150g"

        Case "#10": TypicalPortion = "typical portion = 125 to 175g"

        Case "#11": TypicalPortion = "typical portion = 120 to 160g"

        Case "#12": TypicalPortion = "typical portion = 200 to 300g"

        Case "#13": TypicalPortion = "1 glass = 250g, 1 pint = 560g"

        Case "#14": TypicalPortion = "1 tablespoon = 20g"

        Case "#15": TypicalPortion = "1 tablespoon = 15g"

        Case "#16": TypicalPortion = "1 level teaspoon = 2g"

        Case "#17": TypicalPortion = "1 tub = 150g"

        Case "#18": TypicalPortion = "see your recipe for amount used"

        Case "#19": TypicalPortion = "or see your recipe for amount used"

        Case "#20": TypicalPortion = "REMEMBER : milk and sugar"

        Case "#21": TypicalPortion = "REMEMBER : milk"

        Case "#22": TypicalPortion = "REMEMBER : appetites vary!"

    End Select

    End Function

    ==========

    The LabelNOTE can best be explained by looking at the Word File that I have uploaded to your URL – please look at “Food Label and NOTE” in folder “winchestermili”.   The format of comments after the label can be many and varied.  In its simplest form there are three options.  Please look at the end of the Word file and the list of “Ingredients” and the two comments in red.

    A single “x” is a switch to accumulate a series of “Label NAMES” from the database.  These are simplified / shortened names and by cycling through the foodlist a list of ingredients is created.  Duplicate names are removed.  A bubblesort is used to arrange the ingredients in descending order of mass.  The single “x” also requires an additional comment after the list of ingredients:  text = "() = The list of ingredients contains components that" & vbCrLf & "should have their ingredients listed in ()"

    A double “xx” does NOT accumulate a series of “Label NAMES” from the database.  The double “xx”  requires an additional comment after the list of ingredients:  text = "The food list contains ready made food item(s) which" & vbCrLf & "have not been included in the ingredients list."

    Therefore by using a simple “x” or “xx” flexibility is maintained and a single comment change in the program will be applied throughout.    There are miles of code for the Food Label because there were so many options and formats available.  We are still waiting for the EU to publish the long awaited new guidelines that will be proposed for Europe.


    Winchestermili

    Thursday, December 11, 2014 10:03 AM
  • Frank - To avoid later problems please could you name the VS Project "Nutrients" - many thanks


    Winchestermili

    Thursday, December 11, 2014 4:39 PM
  • Frank - To avoid later problems please could you name the VS Project "Nutrients" - many thanks


    Winchestermili

    Winchester,

    Sorry for the delay - I've just gotten back from a multi-hour meeting (I'm a mechanical engineer, not a developer) and suffice that I just got real busy on a new project.

    Please bear with me until I get the basics done on my real work, then I'll get back to this.


    Still lost in code, just at a little higher level.

    :-)

    Thursday, December 11, 2014 5:38 PM
  • Frank

    No problem.  I am a Naval Architect / Ship Surveyor so I sympathise.  The delay is "welcome" because I have to go to assess a damaged yacht on Friday.  Look forward to hearing from You sometime over the weekend.

    Keith


    Winchestermili

    Thursday, December 11, 2014 7:15 PM
  • Keith,

    First things first here: Have a look at the revised test which has the substitutions for the the Typical Portions:

    http://www.fls-online.com/VBNet_Forum/12-11-14/FoodCompositionTest.txt

    The only change made there from yesterday is this substituted data. Let me know if that's all correct please.

    *****

    You said:

    ...please look at “Food Label and NOTE” in folder “winchestermili”

    There's only one file there - were there supposed to be two? I hope so because I'm definitely lost on that last part of your reply from early this morning.


    Still lost in code, just at a little higher level.

    :-)

    Thursday, December 11, 2014 10:06 PM
  • Wow, lots going on in this thread and after perusing it I think all I'm going to do is second other suggestions, but perhaps there will be a new tid-bit as well.

    Based on the distribution of the final application, I would highly recommend using a click-once deployment on a file share with automatic updates enabled.  The school then only needs to provide a file share accessible by the clients.  The client will run the setup from the file share one time, and from then on it will automatically update itself when run if you provide the school with an update and they copy it over the existing shared folder.

    And to further simplify the distribution, I would go with the flat XML file exported out of the old Access Database.  You can modify this file with the new data and embed it within your application as a resource.  It then becomes fairly trivial to write code to load that xml into a dataset for use with databound controls in the form, or just manipulate the XML via code if you want to work with and display the data in another fashion.

    You could even skip the installer and just distribute a stand-alone executable if you wanted (though I recommend the installer for the versioning if nothing else).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Thursday, December 11, 2014 11:02 PM
    Moderator
  • Wow, lots going on in this thread and after perusing it I think all I'm going to do is second other suggestions, but perhaps there will be a new tid-bit as well.

    Based on the distribution of the final application, I would highly recommend using a click-once deployment on a file share with automatic updates enabled.  The school then only needs to provide a file share accessible by the clients.  The client will run the setup from the file share one time, and from then on it will automatically update itself when run if you provide the school with an update and they copy it over the existing shared folder.

    And to further simplify the distribution, I would go with the flat XML file exported out of the old Access Database.  You can modify this file with the new data and embed it within your application as a resource.  It then becomes fairly trivial to write code to load that xml into a dataset for use with databound controls in the form, or just manipulate the XML via code if you want to work with and display the data in another fashion.

    You could even skip the installer and just distribute a stand-alone executable if you wanted (though I recommend the installer for the versioning if nothing else).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Reed,

    I completely disagree about going back to the original Access file (I have it!).

    You haven't read through this to see how many hiccups are in that thing where an asterisk means this, two of them mean that, a special character means something else, and on it goes.

    That needs to go away forever - quickly! (In my opinion of course).

    When I'm done with the class library I'm going to offer to build the "programmer's version" which is where he and his wife will be able to add, edit, modify -- ultimately resulting in one (1) single .xml file but that XML will have four sets of data as it currently stands:

    The first one will be very easy: It'll be a time-stamp. It doesn't need to be in any particular format although I will add that. The reason no particular format is that there will be a routine which looks at potentially three of them to see which has the latest one:

    • The version which will be parsed directly from resources
    • The version which the user has in the common application data folder (if it exists)
    • The version which is online (if it exists/can be accessed)

    It will never use the user's datetime for any comparison; so long as the format is the same in all three of those, it's just there for a comparison - a "version" of sorts.

    Yes I'll have to hold all three of these in memory, temporarily, but once that function returns which one has the latest version, those are out of scope and the GC will attend to them (and none of this is large, not even combined it's not).

    *****

    I think that once he gets away from the older part which was put together through a number of years and through a number of ways - and goes to one single "source" - I really think it'll end up being more easily maintained and more easily worked.

    That's my goal at least. :)


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Thursday, December 11, 2014 11:29 PM ...typos and additional thoughts
    Thursday, December 11, 2014 11:26 PM
  • Frank,

    Apparently I didn't peruse far enough =P  I didn't realize you were that far along.

    I was under the assumption that the original data was good; obviously that is the place to start if there were problems (which it sounds like there were).  So I'd have to agree that rebuilding the data set sounds like a good idea.

    My main point was that the distribution model would probably be best served with as simple a deployment as possible, so SQL was probably not a good idea if it wasn't expressly needed.  But it sounds like you've got all of that covered, so I'll just leave you to it! :)


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Thursday, December 11, 2014 11:42 PM
    Moderator
  • Frank,

    Apparently I didn't peruse far enough =P  I didn't realize you were that far along.

    I was under the assumption that the original data was good; obviously that is the place to start if there were problems (which it sounds like there were).  So I'd have to agree that rebuilding the data set sounds like a good idea.

    My main point was that the distribution model would probably be best served with as simple a deployment as possible, so SQL was probably not a good idea if it wasn't expressly needed.  But it sounds like you've got all of that covered, so I'll just leave you to it! :)


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Ha!

    Part of this is that we can't depend on internet connectivity (at all), although he wants methods in there for "when they can". Add to that the fact that he said that sometimes school admins DELETE the data files! ... so I'm coming up with a way to cover all of that, but I only have concept as of now.

    Right now I need to concentrate on handling the data itself.

    I'm nearly done on that part (I hope!) and then I can move to the handling of the rest, getting the methods I need, making sure that validation is properly done (you can't have a negative value, for instance), and all of that.

    We'll see! :)

    ******

    It's been an interesting adventure - and it continues to be, as seems to be indicated by the number of reads this thread has had in the short time it's been here. Why that's so, I don't know.

    *****

    I just hate that "real work" does have a way of getting in the way sometimes! ;-)


    Still lost in code, just at a little higher level.

    :-)

    Thursday, December 11, 2014 11:54 PM
  • Frank

    Food Labels have many shapes and forms.  It is different for either a drink OR a food.  The label could contain a list of ingredients OR not.  Additional explanatory notes may OR may not be needed.  The last field "x" or "xx" is a look up method to add certain additional information. 

     

    In essence:

    a single "x" adds the text comment:  "() = The list of ingredients contains components that" & vbCrLf & "should have their ingredients listed in ()"

    A double “xx” adds the text comment:   "The food list contains ready made food item(s) which" & vbCrLf & "have not been included in the ingredients list."

    There will be hundreds of these comments - ALL the same.  So a simple lookup table is the most efficient and flexible approach.  Alternatively "Label comment 1", "Label comment 2"....  it was simply to save space.


    Winchestermili

    Friday, December 12, 2014 2:06 PM
  • Last post should have contained the following graphic:


    Winchestermili

    Friday, December 12, 2014 2:09 PM
  • Last post should have contained the following graphic:


    Winchestermili

    Keith,

    I've created another class in the library and I've named it "LabelNote". It only has three instances, the first being an empty string, and the other two being what you showed above.

    You can look at the text test here.

    I also added a reference to it in the main class ("FoodComposition"), the same way that Food Category is done. You can review that here.

    Let me know your thoughts on it so far please.


    Still lost in code, just at a little higher level.

    :-)


    Friday, December 12, 2014 5:30 PM
  • And this is the first run test of the XML file (287 K -- not bad!).

    :)


    Still lost in code, just at a little higher level.

    :-)

    Friday, December 12, 2014 6:49 PM
  • ...followed quickly by the sequel: The second test run shown here.

    The difference can be seen in the section "LabelNote". The fact that it contains vbCrLf, the XML won't balk at it but it won't parse correctly trying to get it back out. I've come to use this "replacement" technique and it works.

    When I parse it back out I have it look for "#-LINEBREAKHERE-#" and then replace that with vbCrLf.

    In time I'll do that with all of the strings in all of the classes (note that this is done when creating the XML, not in the classes that have the actual data).


    Still lost in code, just at a little higher level.

    :-)

    Friday, December 12, 2014 7:00 PM
  • Frank
    I have reviewed the database and can confirm that the proposed layout is ideal.

    The format (sequence of data) will take a bit of getting used to but all the essential data appears to be correct.

    At 287K that is very cool!

    I understand about the "Linebreak" but if you think that it will be more robust without then we could use a word-wrap text box to control it.

    This are looking good and making more sense to me by the hour..............

    Many thanks.

    Keith


    Winchestermili

    Friday, December 12, 2014 7:42 PM
  • Frank
    I have reviewed the database and can confirm that the proposed layout is ideal.

    The format (sequence of data) will take a bit of getting used to but all the essential data appears to be correct.

    At 287K that is very cool!

    I understand about the "Linebreak" but if you think that it will be more robust without then we could use a word-wrap text box to control it.

    This are looking good and making more sense to me by the hour..............

    Many thanks.

    Keith


    Winchestermili

    Keith - it's entirely up to you if you want to remove the vbCrLf. In fact, consider it and when I get done and hand it all over to you (with the "programmer's version" actual program), use that to test out the ability to revise it.

    Testing it will be an arduous task in itself - essentially I'll be asking you to break it! ;-)

    I'm a fair ways from that yet - this is just the bare bones stuff so far, but I'm glad that you're in agreement that it's moving in the right direction.

    *****

    As for the substitution for vbCrLf, in some cases it's just not avoidable as shown here.

    *****

    I'll do my best to continue working on this over the weekend but with this new project looming it's difficult to promise anything right now.

    By the way, is the yacht a total wreck? It has me curious. ;-)


    Still lost in code, just at a little higher level.

    :-)

    Friday, December 12, 2014 7:56 PM
  • Frank

    The 34m yacht just has a hole where there should not be a hole.  It suffers in a similar way to some of my programs.  A hefty "patch" over the embarrassment will suffice.  It has been a long, cold and wet day.

    Keep going with your XML quest - I get the feeling that this is going to be a Class act.

    Keith


    Winchestermili

    Friday, December 12, 2014 8:03 PM
  • I get the feeling that this is going to be a Class act.

    Pardon the pun! ;-)

    *****

    Will do. :)


    Still lost in code, just at a little higher level.

    :-)

    Friday, December 12, 2014 8:11 PM
  • The format (sequence of data) will take a bit of getting used to...

    Keith,

    Even though this is far from being "ready for prime time", the basics are put together now. Earlier this morning I wrote the method to read the XML either from a local file or from a URL.

    With that done, I'd like to give you an idea about what it all is and from that I think you can see how to use your data.

    *****

    I have the class library (again, it's not complete) zipped up and uploaded here. I'd like to get you to download that and extract the contents somewhere. It contains one file named "NutritionData.vb".

    Start a new project (name whatever you want and save it) and once you do, to add this new set of classes to your project, in Solution Explorer right-click, choose "Add" then "Existing Item":

    Now browse to wherever you extracted the file to and select it. When you "OK" your way back, Solution Explorer will now show that class library:

    In your new project, replace your code with the following:

    Option Strict On Option Explicit On Public Class Form1 Private drvList As New List(Of NutritionData.DietaryReferenceValue) Private catList As New List(Of NutritionData.FoodCategory) Private lnList As New List(Of NutritionData.LabelNote) Private foodCompositionList As New List(Of NutritionData.FoodComposition) Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim url As String = _ "http://www.fls-online.com/VBNet_Forum/12-13-14/NutritionData.xml" Dim sw As New Stopwatch sw.Start() GetNutritonData(url) sw.Stop() Stop End Sub Private Sub GetNutritonData(ByVal url As String) Try NutritionData.Utilites.ReadXML(drvList, catList, lnList, _ foodCompositionList, url, _ NutritionData.Utilites.FileStringType.URL) Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub End Class


    You can see there's not a lot to this part. When the code gets to the "Stop" in the .Load event handler sub, go to the top where the four class-scoped (form-scoped) lists are shown. I don't have a way to show a screenshot of this but hover your mouse over each of them.

    When you do you'll see the count of each of them and a "+" sign. If you'll click that "+" sign, you expand that part of it. Click through several of them to see the actual contents, then let me know and we'll talk some more about what you'll see there.


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 13, 2014 3:12 PM
  • Frank

    Looking good!  The "attachment" to a new project worked first time.

    I can see all the new Classes by hovering a pointer over the "declarations" above "Public Class Form1"

    Seems to access the VBNetForum URL quite quickly using a high speed BB connection.

    I am greatly looking forward to the next stage...........

    Regards

    Keith


    Winchestermili

    Saturday, December 13, 2014 6:10 PM
  • Frank

    Looking good!  The "attachment" to a new project worked first time.

    I can see all the new Classes by hovering a pointer over the "declarations" above "Public Class Form1"

    Seems to access the VBNetForum URL quite quickly using a high speed BB connection.

    I am greatly looking forward to the next stage...........

    Regards

    Keith


    Winchestermili

    Good. :)

    Once it's a local file, it'll be MUCH faster than that.

    Internet access can't compete with grabbing the data from a file on the user's system (well I suppose that depends on the type drive but in general that statement is so).

    *****

    Give me a little while to type out my thoughts please...


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 13, 2014 6:14 PM
  • Frank

    Looking good!  The "attachment" to a new project worked first time.

    I can see all the new Classes by hovering a pointer over the "declarations" above "Public Class Form1"

    Seems to access the VBNetForum URL quite quickly using a high speed BB connection.

    I am greatly looking forward to the next stage...........

    Regards

    Keith


    Winchestermili


    Keith,

    I intentionally truncated that post with “let me know when you’re that far along” simply because it’s very easy to get lost with a concept that’s new. This isn’t as different as you might think though – you’ve been using a database, and now you’ll be using instances of a class (various ones).

    Over the years here, I’ve seen many times where people use databases because they assume “that’s the only way to do it”. The “it” actually being encapsulation.

    Encapsulation is what they need and certainly a database provides that (and a lot more), but it’s not the only way it can be done.

    Think about this a bit: A DataRow encapsulates the related data for whatever it is. For example maybe it’s a person’s data – you’d want to keep the person’s first name, surname, and things like that all together because it defines something related to that one person. You then have a collection of those DataRows in a DataTable.

    In much the same way, what I have here is similar: Instead of a DataRow, I’m using instances of a class. Instead of columns in a DataRow, I’m using properties of the instance, and instead of a DataTable, I’m using a List(Of Class).

    …the concept is identical.

    Classes are a means of building an object in OOP. In and of itself, it’s really just a template or a blueprint (overused metaphor). Deborah Kurata put it best, in my opinion, when she said that a class is like a cookie-cutter and the objects created are cookies. You eat the cookies, not the cookie-cutter!

    A class works that way exactly: You can’t “consume” a class; you consume the objects (instances) created by them and in this case, like a DataTable housing DataRows, I’m storing them in a very specific type of collection known as a List(Of T).

    I don’t want to get too far adrift about classes and/or OOP here – not that I would mind the discussion – but it’s a new concept to you and it’s easy to get confused about what’s doing what. I’ll get more to the specifics next.

    *****

    That entire class library is the data layer; it doesn’t work with controls of any sort, only the data.

    That said though, in the following I’ll explain how controls can be ‘assisted’ by the methods in the classes.

    *****

    The main class in this is the one called “FoodComposition”. That one is only barely started – the only method in it so far is an overloaded way to add a new instance to a list of them.

    Two of the classes are really just ‘supporting classes’ – those being the ones called “FoodCategory” and “LabelNote”. Don’t get me wrong here, they do have methods in them (with more to be added), but you won’t too much be working with those in the user’s program – you will in the program that I’ll create for you to add/modify/remove* and so on, but for now let’s set those two aside.

     

    *  The fact that these are “supporting” classes, I have it set up such that you cannot remove an instance of those if there’s a reference to them in FoodComposition. If you want to see where/how I’m doing that, look at the code of the class FoodCategory, for example, and go to line 633, then read the code of that method named “Remove”.

     

    The one class in the bunch which is pretty much self-contained is the one called DietaryReferenceValue (DRV is the name you used). That one makes for a good topic to explain how I can provide methods which lend a helping hand to your controls but don’t, directly, have anything to do with controls.

    I have a method in that class named “GetAllGroupNames” which is a function that returns a string array containing the names of each instance’s group. That might be used, for example, if you wanted to show a ListBox or a ComboBox to allow the user to select one of the group names:

    Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim url As String = _ "http://www.fls-online.com/VBNet_Forum/12-13-14/NutritionData.xml" GetNutritonData(url) ListBox1.Items.AddRange(NutritionData.DietaryReferenceValue.GetAllGroupNames(drvList)) End Sub



    So, for example, when the user selects one of them:

    Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles ListBox1.SelectedIndexChanged Try If ListBox1.SelectedIndex > -1 Then Dim selectedGroup As String = _ ListBox1.Items(ListBox1.SelectedIndex).ToString Dim drv As NutritionData.DietaryReferenceValue = _ NutritionData.DietaryReferenceValue.GetInstance(drvList, selectedGroup) MessageBox.Show(drv.ToString, drv.SexAndAgeGroup) End If Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub



    As you can see there, I’m using the .ToString method which I have overridden in the class. That’s also part of what I wanted to discuss: What it gets.

    Currently I don’t have much else (other than maintenance routines like adding, removing, renaming) in there; the methods that you use are methods that I set up – but in the words of Hamlet, “therein lies the rub” … I don’t know what you want!

    Give some thought to just what methods you might want to have in there. For example maybe you might want to have a method which will return the value of one specific nutrient which you specify. I can do that, I just don’t know yet that you want it so it’s not there.

    Quite often I’ll also provide what I’m come to call “convenience properties”. For example with the property named “Sodium”, I might have another property (read-only) named “Sodium_String” which returns a string in whatever format you wanted it to have.

    These are things I don’t know that you want and also things which you may not have known can be done, thus this writing. ;-)

    *****

    The other day I asked about units. It may not be where you want to go with this but I’d also like to offer that we can provide more granularity to the nutrients themselves. Don’t get me wrong, it’d be an overhaul of what I have right now, but I’ll do it if you want to proceed:

    Imagine that we have a class, all by itself, that we call “Nutrients”. At the very least that class would have members like Name and UnitOfMeasure, but it could have anything else you wanted. An example that comes to mind might be the URL to a page on Wikipedia about it, or maybe a URL to an appropriate image or … whatever you dream of here.

    So then when using them in the other classes, “Calcium” would, itself, be an object which has a name (“Calcium”), a unit-of-measure (maybe “milligram”), and so on.

    *****

    It’s a lot to take in all at once and even this is something you may want to reread, but do give it thought. Let me know what methods you want in the classes which will help you in your user’s program.

    :)


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 13, 2014 6:56 PM
  • Frank

    Excellent and thank you for another superb explanation.  I have read your notes a few times and Yes, I now get the concept of encapsulation. 

    I will go through Your last posting again in the morning.  I have managed to cycle through the data and can easily use the class to locate all that data e.g. using:

    Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles     NumericUpDown1.ValueChanged
        Dim n As Integer
        n = CInt(NumericUpDown1.Value)
        Label1.Text = foodCompositionList.Item(n).FoodName
    End Sub

    The approach makes far more sense than a DataTable.

    I can locate any item of data with incredible ease.

    In particular I most like the loading of a ListBox with the "GetAllGroupNames" approach; which will work perfectly with the DRV Groups.    With the Food Category Groups I assume that we will cycle through the database for say "FoodCategory =3" until we meet category 4?

    Let me have a soak and get back to You.

    The approach is ideal and makes so much sense.

    Many congratulations and thank you for your time.
    Keith


    Winchestermili

    Saturday, December 13, 2014 8:07 PM
  • With the Food Category Groups I assume that we will cycle through the database for say "FoodCategory =3" until we meet category 4?

    I can set this up with methods which will provide things any way you want (well, within reason ;-)), I just don't yet know what those things are. I will be adding in methods which I'll need for the program that I'll provide - but for the user's program, I don't know what all you might can use.

    We can always come back of course, and you don't need to release any version of it until it's "right" for you - so that is certainly an option. Try it out in a way we agree with (once I'm done) and that will give you ideas like "I wonder if I can also have that class ... {fill in the blank}".

    *****

    Give it thought but I do think that you'll see that where a database is a sort of "one-size-fits-all" approach, this is a very specific approach and as such, I can most likely provide a method to do whatever you want it to do. :)


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 13, 2014 8:20 PM
  • Hi Frank

    Looking back over the VB6 code there are numerous instances of the units being repeated for different sections of the analysis, for saving and for printing.  This was mainly caused by the evolution of the program.  Again, you were right in your previous suggestions when you requested the details of the units.  Sincere apologies.  A Class would be an excellent way forward, if possible, please.

    "Energy":              unit = "kcal"
    "Protein":              unit = "gms"
    "Fat":                   unit = "gms"
    "Saturated Fat":    unit = "gms"
    "Carbohydrates":   unit = "gms"
    "Sugar":               unit = "gms"
    "Sodium":             unit = "mg"
    "Calcium":            unit = "mg"
    "Iron":                 unit = "mg"
    "Vitamin A":         unit = "ug"
    "Vitamin B1":       unit = "mg"
    "Vitamin B2":       unit = "mg"
    "Niacin":              unit = "mg"
    "Vitamin C":         unit = "mg"
    "Vitamin D":         unit = "ug"
    "Fibre":                unit = "gms"

    Please note that both vitamins "A and D" use micrograms.

    The objectives in handling the data are three fold:

    Firstly we need to be able to take the existing 866 food database and add about 200 new rows whilst checking the latest data for ALL the existing foods.  Originally, I assumed that this would be by direct entry into the XML file which would be updated.  However, I have had a long hard look at the methods being established for handling the data Add, Remove, Rename etc.  I can see a very clear way ahead.

    Secondly we need to display the available foods.  In the VB6 program this was done by having two side-by-side ListBoxes (please see the “Getting Started” summary Word file).  One ListBox gave the Categories and once selected the food_names were poured from the database into the second ListBox.  That is where the “Cat_Pointers” were used.  Selecting a food from the RH ListBox from say Category “3” looked up the “Cat_Pointer” for the first food in that Category and added the “ListBox.Index” for that selection – giving the food_number in the database.  In hindsight as each food was entered into the VB6 ListBox the entries could have had their “tag” set to the “food_number”.  Obviously, using the Class Structure we can now get back to the Class that originated the ListBox in the first place.

    Now, strict control was maintained in the ordering of foods to ensure no duplication and to aid checking.  Our best solution was to sort our database into Category Order (from 1 to 21), THEN sort them alphabetically in those Categories.  That way it was a straight forward and reliable way to fill the ListBoxes with food_names from e.g. “Cat_Pointer 3” to “Cat_Pointer 4” minus 1.

    Also, the VB6 program used a “Search” facility whereby part of the “food_name” was entered.  A simple VB “Instr” function was used to search from 1 to 866 foods for that string.  Searching for “rice” will find 11 foods (including liquorice allsorts).  More sophistication might be added so that for example “Take Away” foods are excluded.

    Thirdly, we need to randomly access the data for individual foods.  This is used in a number of places throughout the program:

    1. Analyse the selected list of foods,
    2. Compare the diet against the DRV
    3. Section across the list of foods to examine where individual nutrients occur (e.g. which foods contain the most salt or high levels of saturated fat)

    In dealing with each food we will take each and every item and modify the value for mass.  The database contains data for 100grams of each food so the user enters a mass at the “food_list” and a simple multiplication is used for each and every piece of data and then summated “vertically” through the list.

    *******

    Thinking about the use of a URL for the data I think that we might need to cater for both a URL and if no connection is found then default to the latest version or an option to download the latest XML?  I think that by combining your two demonstrations then I should be able to provide that option.  Some schools are very cautious about which websites children can access and blocking might become a problem.

    ******

    The loading of the “DietaryReferenceValue” data into a ListBox using the “GetAllGroupNames(drvList))” is extremely efficient.   Can we add the data in the list order rather than alphabetically (the ListBox switches between boys, women, girls and men)?

    Many thanks for all Your time.


    Winchestermili

    Sunday, December 14, 2014 12:17 PM
  • Keith,

    That's a lot to take in at a little after seven on a Sunday morning. ;-)

    I'll give thought to how to do this but I agree that this will add flexibility down the road so better to rework things now.

    *****

    As for getting information where you specify conditions (and, optionally, indicate a sorting order), I'll build in some ways to do that, but even if I miss something that you want, you have the power of LINQ-To-Object to get what you want.

    It's an odd animal to work with at first, but it's very powerful. As an example, if you'll go back to your project from yesterday, modify your form's .Load event handler sub to the following and run it:

    Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim url As String = _ "http://www.fls-online.com/VBNet_Forum/12-13-14/NutritionData.xml" GetNutritonData(url) Dim sb As New System.Text.StringBuilder Dim qry1 As IEnumerable(Of NutritionData.FoodComposition) = _ From fc As NutritionData.FoodComposition In _ foodCompositionList _ Where fc.FoodName.ToLower.Contains("rice") For i As Integer = 0 To qry1.Count - 1 sb.AppendLine(qry1(i).FoodName) If i < qry1.Count - 1 Then sb.AppendLine() sb.AppendLine("----------") sb.AppendLine() End If Next If sb.Length > 0 Then MessageBox.Show(sb.ToString, "qry1") End If sb.Length = 0 Dim qry2 As IOrderedEnumerable(Of NutritionData.FoodComposition) = _ From fc As NutritionData.FoodComposition In _ foodCompositionList _ Where fc.FoodName.ToLower.Contains("rice") _ Order By fc.Carbohydrate Descending For i As Integer = 0 To qry2.Count - 1 sb.AppendLine(qry2(i).FoodName & " | " & _ qry2(i).Carbohydrate.ToString) If i < qry2.Count - 1 Then sb.AppendLine() sb.AppendLine("----------") sb.AppendLine() End If Next If sb.Length > 0 Then MessageBox.Show(sb.ToString, "qry2") End If Stop ' ListBox1.Items.AddRange(NutritionData.DietaryReferenceValue.GetAllGroupNames(drvList)) End Sub


    Try that and let me know your thoughts on it while I continue to digest your message here.


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 14, 2014 1:27 PM
  • Keith,

    This is definitely a setback in terms of time, but I still think it's worth the effort. I want to show you what I've done and get your feedback about it before I continue though.

    I've added two new classes now, one called "UnitOfMeasure" and the other called "Nutrient". Have a look at these two classes as shown on a page of my website here.

    The class "Nutrient" is set up as instance members; everything else you've been working with has been shared instead.

    The idea here goes back to what we were talking about yesterday: Encapsulation. I want the name of the nutrient, the unit-of-measure of it, and the value of it to be encapsulated, so for each nutrient in the other classes, there will be a new instance of that class (that is, of "Nutrient").

    You might also have a look at the .ToString method in Nutrient - you'll see that it's both overridden and overloaded (say that three times and your tongue will be in a knot).

    The overloaded version allows the consumer of it to tell it whether to return the UOM as the short name or the long name and also has a parameter to set the number of decimal places to show.

    Starting out first with the DRV's, have a look at the results here.

    Your thoughts?


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 14, 2014 3:43 PM
  • Frank

    Well the "Find" method is ideal. It clearly demonstrates the power of the Class approach. So few lines of code and very reliable.

    The second demonstration where the "Finds" are ordered in "Descending Carbohydrate" levels that has given me idea that the Food List created by the user can be treated as a separate Class and the contents used to section the data to examine specific levels of Energy, Nutrients and Vitamins.    If successful that that will dispense with a few yards of original VB6 code.....  Now the new Class called "Nutrient" that you have created seems to fit that approach perfectly by Encapulating both the Name and the Value (and usefully the uom) so that makes perfect sense.

    The DRVs look good.  The list order is ideal because people will be familiar with the order.    Unfortunately the Food Database and the DRVs do not map easily onto each other because there simply are no DRVs for such things as fat, sat fat carbohydrate etc. and only guidance for fibre.  The uom's are correctly assigned.

    Many thanks

    Keith


    Winchestermili

    Sunday, December 14, 2014 5:03 PM
  • Frank

    Well the "Find" method is ideal. It clearly demonstrates the power of the Class approach. So few lines of code and very reliable.

    The second demonstration where the "Finds" are ordered in "Descending Carbohydrate" levels that has given me idea that the Food List created by the user can be treated as a separate Class and the contents used to section the data to examine specific levels of Energy, Nutrients and Vitamins.    If successful that that will dispense with a few yards of original VB6 code.....  Now the new Class called "Nutrient" that you have created seems to fit that approach perfectly by Encapulating both the Name and the Value (and usefully the uom) so that makes perfect sense.

    The DRVs look good.  The list order is ideal because people will be familiar with the order.    Unfortunately the Food Database and the DRVs do not map easily onto each other because there simply are no DRVs for such things as fat, sat fat carbohydrate etc. and only guidance for fibre.  The uom's are correctly assigned.

    Many thanks

    Keith


    Winchestermili

    Keith,

    I'll read this more thoroughly here shortly but I wanted to address some of the other things you brought up earlier.

    If you'll go back to your project from yesterday I'd like to get you to modify the class (I know this might be confusing because as it stands there are two "versions" of the class right now but they'll be eventually consolidated).

    In your current version, go to about line 1749 (in the class library), which should be about where the overloaded "AddNew" ends and just before the private methods start. Add in a few lines so that you can then insert the following code:

    Public Shared Function GetFoodsByCategory(ByVal fcList As List(Of FoodComposition), _ ByVal categoryNameToReturn As String) As String() Dim retVal() As String = New String() {} Try ' This is strictly temporary! - I'll have a more ' robust version in the real deal... Dim qry As IOrderedEnumerable(Of String) = _ From fc As FoodComposition In fcList _ Where fc.FoodCategoryReference.CategoryName.ToLower.Replace(" "c, "") = _ categoryNameToReturn.ToLower.Replace(" "c, "") _ Select fc.FoodName Distinct Order By FoodName If qry.Count > 0 Then retVal = qry.ToArray End If Catch ex As Exception Throw End Try Return retVal End Function


    Now add two ListBoxes to your project. I have my example laid out as follows, but lay them out any way you'd care to:

    Then in your Form1, change all of your code to the following:

    Option Strict On Option Explicit On Public Class Form1 Private drvList As New List(Of NutritionData.DietaryReferenceValue) Private catList As New List(Of NutritionData.FoodCategory) Private lnList As New List(Of NutritionData.LabelNote) Private foodCompositionList As New List(Of NutritionData.FoodComposition) Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim url As String = _ "http://www.fls-online.com/VBNet_Forum/12-13-14/NutritionData.xml" GetNutritonData(url) ListBox1.Items.AddRange(NutritionData.FoodCategory.GetAllCategoryNames(catList)) End Sub Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles ListBox1.SelectedIndexChanged Try If ListBox1.SelectedIndex > -1 Then ListBox2.Items.Clear() Dim categoryName As String = _ ListBox1.Items(ListBox1.SelectedIndex).ToString Dim matchingFoods() As String = _ NutritionData.FoodComposition.GetFoodsByCategory(foodCompositionList, _ categoryName) If matchingFoods.Count = 0 Then MessageBox.Show("The query returned no results", "Nothing To Show!", _ MessageBoxButtons.OK, MessageBoxIcon.Hand) Else ListBox2.Items.AddRange(matchingFoods) End If End If Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub Private Sub GetNutritonData(ByVal url As String) Try NutritionData.Utilites.ReadXML(drvList, catList, lnList, _ foodCompositionList, url, _ NutritionData.Utilites.FileStringType.URL) Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub End Class


    Try it out - shown below is my quick test of it:

    *****

    I'll come back to your message in a bit and reply to it. Let me know what you think of this test though please.


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 14, 2014 5:17 PM
  • ...that has given me idea that the Food List created by the user...

    I've been focusing on the data itself so you might have mentioned (or implied) this somewhere in this trail of replies, but explain what you mean here please?

    I guess I haven't really noticed much about the user's side of it.

    They can create their own list(s) of foods? That's great if so and yes that should be dealt with in another class, including methods to save and reload, but I'd like to know more about this please?


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 14, 2014 5:34 PM
  • Frank

    The double ListBox worked perfectly.  However, I notice that the "Categories" have been re-ordered into alphabetical order.  For familiarity I would prefer the numerical order that appears in the database.  I have added the "GetFoodsByCategory" Function and all works fine.

    That conveniently brings us up to the User's operation of the software.  The objective is for the User to create a "Food_List".  Please refer to the "Getting Started" Word document that I uploaded previously.  The following graphic, from that Word file, is the important next step.

    The list of foods is used as a picker list to create a Food_List - e.g the foods consumed by a User in one day.    "Sultanas" is selected and an "Input Amount"window opens.  The database is exclusively based on a 100gram sample of the food.  The user enters the mass eaten in grams.  Hence in this example the database value is halved and added to the running totals of Energy, Vitamins and minerals.  Please see the "Food_List" with the green background above.  The mass is added to the foodname string - which is not a great approach.  I am looking at a two column Food_List hopefully with a writable column for the entry of the mass.  That way I could dispense with the "Input Amount Window".

    Then it is that User "Food_List" that is Analysed - ref the other steps in the "Getting Started" summary.

    The user can save their personalised "Food_List" for re-use another day.  It is saved as a simple datafile - basically a CSV file having food_number and mass in grams.  A simple header states which Version was used to create the Food_List - hence the need for the V2_db_number so backward compatibility can be achieved.  As new foods are added to expand the database then the V2_dbnumber will be preserved ready to look up a new food_number for Version 3.

    I hope that this makes good sense to You.

    Keith


    Winchestermili

    Sunday, December 14, 2014 7:13 PM
  • Keith,

    First things first - getting the data ordered (sorted) is just a habit but certainly it can be done any way you want it to be, so that's something that I'll include when I rework the whole thing. A selection of an enum (enumarable) would be a good way to do that.

    *****

    I do see what you mean about the user's side of it, but for now I want to focus on the reworking of it to get all of the data back to where I was before I made the change that I did this morning.

    Right now I have hundreds of lines commented out because it wouldn't compile with my changes; those will be changed in time of course.

    *****

    I hope you understand and agree -- for now I'll just let all of this settle then get back to it this next week as I can. I have this new project which I have to get on top of and I'm waiting for their stuff to come through. This is still in the bidding process - they have to have all of my stuff to them before January 8, but ... at the end of this next week I'll be on vacation until January 5. You see the problem here!

    (and no, I'm not willing to work on it during my vacation - if I were I'd have stayed in business for myself 22 years ago).

    *****

    ... rambling again aren't I. ;-)

    To the good, the week after this next one I can dedicate time to this in earnest. I do like the way it's shaping up - I think it'll end up being a very nice, robust program.

    :)


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Sunday, December 14, 2014 7:32 PM ...typical FLS typos
    Sunday, December 14, 2014 7:28 PM
  • Frank

    No problem at all - I plan to go over all your words and whilst you get on top of your new work project I will get on top of Classes and Encapsulation.

    It is definitely shaping up to be a neat approach.

    I hope that the Forum will keep this as a valuable resource for other programmers.

    Your "rambles" are very helpful.  Looking forward to hearing from You.

    Regards

    Keith


    Winchestermili

    Sunday, December 14, 2014 8:10 PM
  • Frank

    No problem at all - I plan to go over all your words and whilst you get on top of your new work project I will get on top of Classes and Encapsulation.

    It is definitely shaping up to be a neat approach.

    I hope that the Forum will keep this as a valuable resource for other programmers.

    Your "rambles" are very helpful.  Looking forward to hearing from You.

    Regards

    Keith


    Winchestermili

    Have a look at this when you have a few minutes. It's a quick bird's-eye view of OOP in general.

    I'll talk to you again in a few days. :)


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 14, 2014 8:14 PM
  • Frank

    No problem at all - I plan to go over all your words and whilst you get on top of your new work project I will get on top of Classes and Encapsulation.

    It is definitely shaping up to be a neat approach.

    I hope that the Forum will keep this as a valuable resource for other programmers.

    Your "rambles" are very helpful.  Looking forward to hearing from You.

    Regards

    Keith


    Winchestermili

    Keith,

    Would you please have a look at this and let me know if this is correct?

    I'm guessing that retinol and carotene are based in units of micrograms, but is that correct?

    *****

    Also, this is the XML file (now 1K larger than last week). I don't yet have it reading it back in but that'll be the next step.


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Saturday, December 20, 2014 2:50 PM ...additional info
    Saturday, December 20, 2014 2:35 PM
  • Frank

    Good to hear from You.

    Correct both the UOMs for retinol and carotene are micrograms.

    The XML file is looking fine.  We will be adding a series of new foods to increase the food data from 866 to about 1000 foods.  Will we be able to cater for converting previous food lists?  The datafiles, saved by the user is basically a small CSV file in the format (food_number, food_mass) which worked fine with SQL.  The intention with "V2_dbnumber" column in the Excel file that I sent was to store the food_number whilst new lines were added then a new version datafile could be converted into the new format.  OR is there a more cunning plan?......

    Keith


    Winchestermili

    Saturday, December 20, 2014 5:41 PM
  • Frank

    Good to hear from You.

    Correct both the UOMs for retinol and carotene are micrograms.

    The XML file is looking fine.  We will be adding a series of new foods to increase the food data from 866 to about 1000 foods.  Will we be able to cater for converting previous food lists?  The datafiles, saved by the user is basically a small CSV file in the format (food_number, food_mass) which worked fine with SQL.  The intention with "V2_dbnumber" column in the Excel file that I sent was to store the food_number whilst new lines were added then a new version datafile could be converted into the new format.  OR is there a more cunning plan?......

    Keith


    Winchestermili

    Sorry for the hiatus but it's not something that I could control - "real work" has to come first and I'm sure that you understand. I'm on vacation until after the new year now though. :)

    *****

    There is no need to convert anything - it'll do the same as it does now it'll just have more entries is all. It's already set up for that.

    *****

    As for the user's side of it, let's leave that until the data side is complete. What I have in mind there will be another namespace entirely so that this one (Nutrition_Data) is just that: The core data only and, of course, methods to work with that data.

    One thought, though, is to let the user save and retrieve their own work through serialization to a binary file, but that's for later.

    *****

    Tell me more about the carotene (presumably beta-carotene?) and retinol please. I'm confused on where/why it's needed.


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 20, 2014 5:48 PM
  • Frank

    I feel very guilty and embarrassed that this is invading your vacation.

    I am reliably informed by Margaret (who is cooking my Saturday evening meal) that................... Beta-carotene is the most important carotenoid in terms of human nutrition.  There are approx. 600 carotenoids found in foods but few contribute to the usefulness of Vitamin A.  The database that we are using refers to beta-carotene so in this case "carotene" and "beta-carotene" are used interchangeably.  For simplicity in a school students (11 to 16 year olds) the name "carotene" was only used.  There are other carotenoids in food which have no real use in human nutrition. 

    The RSC data source does not list Vitamin A as a direct piece of information.  The RSC data does list retinol and carotene and gives the user a formula to calculate the Vitamin A.

    Vitamin A (ug) = retinol (ug) + beta-carotene (ug) equiv./ 6 

    When we created the Access database we only entered our calculated value for Vitamin A to save space.  Minor errors were made but now we have the opportunity to have three columns so I suggest that we just leave all three in the XML file to show where the Vitamin A value came from.

    Now that you have achieved an XML file of <300K we could afford to leave the three columns.

    Keith

     


    Winchestermili

    Saturday, December 20, 2014 6:14 PM
  • Frank

    I feel very guilty and embarrassed that this is invading your vacation.

    I am reliably informed by Margaret (who is cooking my Saturday evening meal) that................... Beta-carotene is the most important carotenoid in terms of human nutrition.  There are approx. 600 carotenoids found in foods but few contribute to the usefulness of Vitamin A.  The database that we are using refers to beta-carotene so in this case "carotene" and "beta-carotene" are used interchangeably.  For simplicity in a school students (11 to 16 year olds) the name "carotene" was only used.  There are other carotenoids in food which have no real use in human nutrition. 

    The RSC data source does not list Vitamin A as a direct piece of information.  The RSC data does list retinol and carotene and gives the user a formula to calculate the Vitamin A.

    Vitamin A (ug) = retinol (ug) + beta-carotene (ug) equiv./ 6 

    When we created the Access database we only entered our calculated value for Vitamin A to save space.  Minor errors were made but now we have the opportunity to have three columns so I suggest that we just leave all three in the XML file to show where the Vitamin A value came from.

    Now that you have achieved an XML file of <300K we could afford to leave the three columns.

    Keith

     


    Winchestermili

    This is what I like to do on my "downtime" so please don't feel that way. :)

    *****

    Will there ever be a time when the β-carotene and/or retinol be used though?

    If it's always going to have a value of zero (which is currently the case) then I can remove them from the XML and likewise remove them from the parameters in the "AddNew" method.

    I don't have to remove the actual properties/backing fields unless ... maybe derive the amounts of each from the formula that you posted? If it's useful information then that's an idea - keep them and the derive the values for them, but if it's not of any real informational use, then let's eliminate them entirely.

    Your thoughts?


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 20, 2014 6:22 PM
  • Frank

    I feel very guilty and embarrassed that this is invading your vacation.

    I am reliably informed by Margaret (who is cooking my Saturday evening meal) that................... Beta-carotene is the most important carotenoid in terms of human nutrition.  There are approx. 600 carotenoids found in foods but few contribute to the usefulness of Vitamin A.  The database that we are using refers to beta-carotene so in this case "carotene" and "beta-carotene" are used interchangeably.  For simplicity in a school students (11 to 16 year olds) the name "carotene" was only used.  There are other carotenoids in food which have no real use in human nutrition. 

    The RSC data source does not list Vitamin A as a direct piece of information.  The RSC data does list retinol and carotene and gives the user a formula to calculate the Vitamin A.

    Vitamin A (ug) = retinol (ug) + beta-carotene (ug) equiv./ 6 

    When we created the Access database we only entered our calculated value for Vitamin A to save space.  Minor errors were made but now we have the opportunity to have three columns so I suggest that we just leave all three in the XML file to show where the Vitamin A value came from.

    Now that you have achieved an XML file of <300K we could afford to leave the three columns.

    Keith

     


    Winchestermili

    Does Margaret provide takeout or delivery? Cause I'm hungry after reading that.

    I would suppose soon enough there will be 3D food printers (NASA was paying $25000.00 for somebody to invent one for printing Pizzas in space) that will include your RDA's for food perhaps and then you could email Margarets dinner recipe to someone in some format and the printer would reproduce the necessities uncooked I suppose. Or send that to the cooking or cooling process maybe.


    La vida loca

    Saturday, December 20, 2014 6:33 PM
  • I am reliably informed by Margaret...

    This gives me a thought and she (and only she) can answer this:

    What about if, when I get to the user's side of things (that namespace), I put together a class which will have the ability to add/edit/remove ... all that ... which will be a multiple choice quiz. The class will have a method to randomly get "x" questions for the quiz and a method to grade them on the fly, showing either that their reply was correct, or that it was incorrect "and here's why".

    She'll need to be the one to set it all up with the questions, the choices, and the explanations of why "choice such and such is the correct answer".

    Very intentionally don't prevent old ones from not being asked again because when the kids say to themselves "oh, I know this one, it's Vitamin C, I've been asked this before", that's positive reinforcement and that is, after all, the intended effect.

    Food for thought. :)


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 20, 2014 6:35 PM
  • I would suppose soon enough there will be 3D food printers...

    It's already being tested:

    http://www.cnn.com/2014/11/06/tech/innovation/foodini-machine-print-food/


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 20, 2014 6:39 PM
  • Hi Frank and Mr Monkeyboy

    Unfortunately take away meals are not on the menu.  Perhaps it is best that I do not mention how much I enjoyed the Moussaka.......

    Neither retinol or β-carotene are used specifically in the program.  Only the resultant value of Vitamin A is used by the program.  Leaving the retinol and carotene embedded in the XML must? be the preferred way so we can see where the values came from.  The cost on space is minor.  We will enter the values of retinol and β-carotene for each and every food and have a formula in the file to create the value of Vitamin A.  Therefore the retinol and β-carotene values need to stay so that Vitamin A can be used within the program?

    Pizzas in space.  Now that would interest the average 11-16 year old who should be studying healthy nutrition.  Margaret has read the posts and let me pass you over to her.......

    Hi Lads,

    The possibility of a quiz is interesting.  Unfortunately using the database as it stands would yield a rather "numeric" quiz.  Over many years of teaching I have developed a series of Worksheets that are accessible through the software as Word files.  That gives "guided learning" and individual teachers can use the worksheets in a flexible way and tailor them to their own requirements.  You are very welcome to read through all the worksheets - we can upload these Word files.  The main idea is to take a specific food list and examine it for low proteien or low vitamins or high salt or high saturated fat.  Also there are educational VLEs that allow a flexible approach to generating suitable quiz facilities.  Certainly at this stage I believe that a review of the existing "guided education" worksheets would be the best way ahead.

    Frank - We are very impressed with and extremely grateful for all the work that you have done.  The interesting point is the vast difference between the length of your code in VS against Keith's attempts in VB6!

    Fodder for thinking.

    Margaret


    Winchestermili

    Saturday, December 20, 2014 8:03 PM
  • Hi Frank and Mr Monkeyboy

    Unfortunately take away meals are not on the menu.  Perhaps it is best that I do not mention how much I enjoyed the Moussaka.......

    Neither retinol or β-carotene are used specifically in the program.  Only the resultant value of Vitamin A is used by the program.  Leaving the retinol and carotene embedded in the XML must? be the preferred way so we can see where the values came from.  The cost on space is minor.  We will enter the values of retinol and β-carotene for each and every food and have a formula in the file to create the value of Vitamin A.  Therefore the retinol and β-carotene values need to stay so that Vitamin A can be used within the program?

    Pizzas in space.  Now that would interest the average 11-16 year old who should be studying healthy nutrition.  Margaret has read the posts and let me pass you over to her.......

    Hi Lads,

    The possibility of a quiz is interesting.  Unfortunately using the database as it stands would yield a rather "numeric" quiz.  Over many years of teaching I have developed a series of Worksheets that are accessible through the software as Word files.  That gives "guided learning" and individual teachers can use the worksheets in a flexible way and tailor them to their own requirements.  You are very welcome to read through all the worksheets - we can upload these Word files.  The main idea is to take a specific food list and examine it for low proteien or low vitamins or high salt or high saturated fat.  Also there are educational VLEs that allow a flexible approach to generating suitable quiz facilities.  Certainly at this stage I believe that a review of the existing "guided education" worksheets would be the best way ahead.

    Frank - We are very impressed with and extremely grateful for all the work that you have done.  The interesting point is the vast difference between the length of your code in VS against Keith's attempts in VB6!

    Fodder for thinking.

    Margaret


    Winchestermili

    Holy smoke - this never showed up as being a new post here in the forum nor did I get an e-mail notification on it. I figured I was waiting on you and turns out to be the other way.

    This forum is flakey - they (MSFT) used to have it working perfectly but not any longer.

    At any rate, I'll explain what I popped in here to say, but then I'll return to your message about the components of Vitamin A.

    In waiting (or so I thought) on a reply from what I wrote yesterday, today I've gone ahead and added methods to the primary class which is "FoodComposition" and you can see an overview of it in this image on my website (it's too big to show here):

    Class Diagram, Food Composition

    If you'll notice, MOST of the methods are for editing; that's the part that I'll take on when I build the administrator program for y'all to use to add to, modify, remove and so on. What I show in the image is only for the main class but all classes will have something similar.

    For the two methods (currently) which you'll work with in the user's program - GETTING the data - not shown is an optional setting for sort order and the default is the natural order, but the other two ways are ascending and descending. If you have ideas for other types of sorting - or filtering for that matter - please do let me know and I can build them in.

    *****

    As for what you said about the carotene (beta-carotene) and retinol, I'm confused on when/where that's added in. If it's going to default to zero in the base data though I think the listings should be removed in the .ToString method and in the XML file. Currently what they show are obviously erroneous because they're zero.

    *****

    Your thoughts on this all? Sorry again about the delay but heck I thought I was still waiting on you, not the other way around! ;-)


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 21, 2014 8:43 PM
  • Hi Frank

    The carotene and retinol subject: 

    1.  The RSC data source does not uniquely define Vitamin A
    2.  The RSC data does however give values for carotene and retinol
    3.  The RSC data source gives a calculation to approximate a value for Vitamin A
    4.  The program uses the calculated value for Vitamin A
    5.  The program does not use the actual values of retinol or carotene anywhere.

    There are 3 possible approaches:
    1.  Have only one column in the XML file for Vitamin.  Manually calculate and enter the value of Vitamin A into the XML file.
    2.  Have two Columns in the XML file - carotene and retinol.  These values will be entered from the data source and the value of Vitamin A calculated within the VB Program.
    3.  Have three columns in the XML file.  These values will be entered from the data source and the value of Vitamin A calculated as a cell formula in Excel?

    I assume you will not be keen on option 3?  So option 2 is fine. 

    **************

    The article by Deborah Kurata is essential reading and has helped in getting to grips with the concept of encapsulation.  Another valuable resource for the Forum.  I have reviewed the Class Diagram and it has become very clear regarding the direction this is headed.

    ************** 

    One minor query is that we deliberately left out Energy in KJoules because it was extremely easy to convert the value of the kcals where it was included in various forms and on printouts.  We will use both Kcals and kJ so is it appropriate to include the units in the "UOM" class?

    ************** 

    Regarding the sorting there is one issue that we have not really addressed.  All foods in the database are quotes at 100 grams.   The sorting is mainly at a feature in the program called "Investigate".  A Users food list is analysed AFTER each component is modified for mass.  So, for example, if a User wants to find out where a food list is high in salt each food is examined after the salt value has been modified by mass.  Therefore a bag of crisps is quite light but (can be) very high in salt whilst a ready meal is fairly heavy and contains quite a lot of salt.  So the comparison is made at that point and not directly from the database.  I created my own simple bubble sort routine which sorted a 2D array which contained the Access database food_number and the value to be sorted.  I get the feeling that Frank has a far smarter method.........

    Keith


    Winchestermili

    Monday, December 22, 2014 1:27 PM
  • Hi Frank

    As a supplement to my last post above.

    The Ordering as you have laid out is fine.  Regarding the "NutrientType" Class the greatest use will probably be "Natural".  The list is pretty much a "constant" throughout the program through the Analysis and the Investigare stages.  The layout is Energy, then Protein, Fats, Elements (Sodium etc), then a group of Vitamins.  No real need to sort that group.  But a User option might be set up for alphabetical sorting in menus / comboboxes.

    Please note that the format of the DRV headings is different - so items are omitted because no national guidelines are given. 

    The real sorting in ascending / descending orders is as a result of the analysis - reference my comments above.

    I cannot think of anything that needs real filtering.  In the VB6 program I gave the option to look at the whole food list or just the top 10 foods.

    It remains an education debate to have features such as "find foods that are high in protein and low in saturated fats" Or get the little blighters to work it out for themselves....the problem is that it all depends on the mass of food consumed. 

    Keith


    Winchestermili

    Monday, December 22, 2014 1:44 PM
  • Hi Keith,

    To take this a bit at a time, if the retinol and beta-carotene are of no value to the user's program then how about we eliminate them entirely?

    If they are of value then (in my opinion) having the values of retinol and beta-carotene (for each food) would be the way to go and the Vitamin A will then be a derived value.

    Your thoughts?


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 1:52 PM
  • Frank

    It would be sensible to have retinol and beta-carotene included so we can check in the future.  We should go ahead with Vitamin A being a derived value within the program.

    Regards

    Keith


    Winchestermili

    Monday, December 22, 2014 1:57 PM
  • Frank

    It would be sensible to have retinol and beta-carotene included so we can check in the future.  We should go ahead with Vitamin A being a derived value within the program.

    Regards

    Keith


    Winchestermili

    Ok good, I agree.

    Did you keep up with those values though? I do hope you'll say "sure, I have them right here" or something? ;-)


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 2:01 PM
  • Frank

    Unfortunately no.  When I wrote the first Acorn program in about 1990 space was critical.  Hence the datafiles had the terrible "#xx" lookup and the "x"/"xx" lookup tables - simply to save space.  We sat down and used a calculator to workout the Vitamin A and entered the value into Access.  We can leave the values as zero because we intend to review all values used.

    Keith


    Winchestermili

    Monday, December 22, 2014 2:07 PM
  • Frank

    Unfortunately no.  When I wrote the first Acorn program in about 1990 space was critical.  Hence the datafiles had the terrible "#xx" lookup and the "x"/"xx" lookup tables - simply to save space.  We sat down and used a calculator to workout the Vitamin A and entered the value into Access.  We can leave the values as zero because we intend to review all values used.

    Keith


    Winchestermili


    Ok, just to confirm then - you want me to set it up as though I had valid values of retinol and beta-carotene, but for now I'll use the default (0), correct?

    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 2:15 PM
  • Yes please.  We will enter the two pieces of data for each food.

    Winchestermili

    Monday, December 22, 2014 2:28 PM
  • Yes please.  We will enter the two pieces of data for each food.

    Winchestermili


    Ok, bear with me a few hours and I'll give you an update on it.

    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 2:32 PM
  • Yes please.  We will enter the two pieces of data for each food.

    Winchestermili

    Sorry this took so long. I'm pretty sure (real sure, honestly) that I'm losing my c:\ and I'm trying to get things as ready as possible. In fact, if I'm silent for a few days this week, you'll know why.

    *****

    I've modified the class so that the consumer of the class (your program) cannot directly modify the value of Vitamin A; rather, it's a derived value based on the values of Carotene and Retinol. I'll show you the pertinent parts that do that:

    I have a private method (instance, not shared) in the class as shown below:

    Private Sub UpdateVitaminA() Try If _vitaminA IsNot Nothing AndAlso _ _retinol IsNot Nothing AndAlso _ _carotene IsNot Nothing Then _vitaminA.Value = _retinol.Value + (_carotene.Value / 6) End If Catch ex As Exception Throw End Try End Sub




    The private setter of the two pertinent properties then call that sub:

    Public Property Carotene() As Nutrient Get Return _carotene End Get Private Set(ByVal value As Nutrient) _carotene = value UpdateVitaminA() End Set End Property


    Public Property Retinol() As Nutrient Get Return _retinol End Get Private Set(ByVal value As Nutrient) _retinol = value UpdateVitaminA() End Set End Property




    Also, when a new FoodComposition entry is added, Vitamin A is set to a new instance of the class "Nutrient" with a value of zero and is instantiated BEFORE either carotene or retinol is. It has to do this so that the method will work - it can't be null at that point in time.

    *****

    This is the modified XML which is now 280 K (because Vitamin A has been eliminated). Also note that the "a" numbers have changed from what they formerly were.

    This is the updated .ToString text test which is different now in that all values of Vitamin A are shown as zero.

    Finally, this shows a method which I added to the "Utilities" class:


    I'll have a look at the other things when I'm able to but obviously c:\ isn't something that I can ignore for long! ;-)

    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Monday, December 22, 2014 5:54 PM ...typo - it's 280 kB, not 290 kB
    Monday, December 22, 2014 5:49 PM
  • Hi Frank
    Many thanks for the interesting update of your progress.

    Several of the methods look similar:  GetInstance, GetNutrientData and GetNutrientValue.  If you get a moment then a brief description would be greatly appreciated.

    Sorry to hear about your C: drive; I am sure that it has done a lot more work than many other drives.

    Regards,
    Keith


    Winchestermili

    Monday, December 22, 2014 7:26 PM
  • Hi Frank
    Many thanks for the interesting update of your progress.

    Several of the methods look similar:  GetInstance, GetNutrientData and GetNutrientValue.  If you get a moment then a brief description would be greatly appreciated.

    Sorry to hear about your C: drive; I am sure that it has done a lot more work than many other drives.

    Regards,
    Keith


    Winchestermili

    The tough part about my hard driving failing is trying to get anything - of quality - this time of year, let alone "I need it now!", but I'm going to try to work with what I have until I get what I need.

    *****

    Your questions are reasonable and understandable. I intend that when I get done with all of this that I'll also include documentation (including XML documentation so that IntelliSense will kick in when you're using all of these things).

    I've put together another sample project that I hope you'll try. First you'll need the class library file as I currently have it and that's here.

    I hope you recall how to add it into your project? If not then I'll explain again. The code follows:

    Option Strict On
    Option Explicit On
    
    Public Class Form1
        Private drvList As New List(Of NutritionData.DietaryReferenceValue)
        Private catList As New List(Of NutritionData.FoodCategory)
        Private lnList As New List(Of NutritionData.LabelNote)
        Private uomList As New List(Of NutritionData.UnitOfMeasure)
        Private foodCompositionList As New List(Of NutritionData.FoodComposition)
    
    
    
        Private Sub Form1_Load(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) _
                               Handles MyBase.Load
    
            Dim url As String = _
                "http://www.fls-online.com/VBNet_Forum/12-22-14/NutritionData.xml"
    
            GetNutritonData(url)
    
            ' Uncomment the following out, one at a time, then
            ' run the program:
    
    
    
            ' Example1()
            ' Example2()
            ' Example3()
            ' Example4()
            ' Example5()
    
            Stop
    
        End Sub
    
    
    
        Private Sub Example1()
    
            Try
                ' This is an example of using the method named
                ' "GetAllFoodNames".
                ' 
                ' The purpose of this method is to return a
                ' string array of ALL of the names of the foods in
                ' the generic list which stores them (that is,
                ' that stores instances of the class
                ' "FoodComposition". In this example program,
                ' that's "foodCompositionList" as shown in the
                ' class-scoped (form-scoped) variables declared
                ' near the top of this form.
                ' 
                ' It will return all of the food names ordered in
                ' any of the three following ways:
                ' 
                ' * Natural Order (the default)
                ' * Ascending
                ' * Descending
                ' 
                ' You can use it as shown below:
    
                Dim foodNames() As String = _
                    NutritionData.FoodComposition.GetAllFoodNames(foodCompositionList)
    
                Stop
    
                ' When the program gets to "Stop" above,
                ' execustion will halt the same though you'd put a
                ' breakpoint in.
                ' 
                ' When it does, hover your mouse over the variable
                ' "foodNames" and expand it. It will show all of
                ' names of the various FoodComposition.FoodName
                ' entries in natural order because that's the
                ' default.
    
    
    
                ' This is the usage if you want to specify the
                ' order to be OTHER than "Natural Order":
    
                foodNames = _
                    NutritionData.FoodComposition.GetAllFoodNames(foodCompositionList, _
                                    NutritionData.FoodComposition.SortOrder.Descending)
    
                Stop
    
    
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub
    
    
    
        Private Sub Example2()
    
            Try
                ' This is an example of using the method named
                ' 
                ' "GetFoodsByCategory".
                ' 
                ' The purpose of this method is to return a string
                ' array of all of the names of the foods based on
                ' the category name. The category name is the name
                ' of one of the instances of the class
                ' "FoodCategory".
                ' 
                ' This one can also be optionally sorted but the
                ' default is "Natural Order":
    
                Dim foodNames() As String = _
                    NutritionData.FoodComposition.GetFoodsByCategory(foodCompositionList, _
                                                                     "Milk, cream")
    
                Stop
    
                ' As before, hover over "foodNames" above.
    
    
    
                ' This is the usage if you want to specify the
                ' order to be OTHER than "Natural Order":
    
                foodNames = _
                    NutritionData.FoodComposition.GetFoodsByCategory(foodCompositionList, _
                                                                     "MILK, c r e a m", _
                                            NutritionData.FoodComposition.SortOrder.Descending)
    
                Stop
    
                ' Please notice above that I very intentionally
                ' skewed how the name is composed.
                ' 
                ' In all of these methods where a string is one of
                ' the parameters, I have it set up to ignore
                ' capitalization and ignore space characters.
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub
    
    
    
        Private Sub Example3()
    
            Try
                ' This is an example of using the method named
                ' "GetInstance".
                ' 
                ' The purpose of this method is to return a single
                ' instance of the class named "FoodComposition"
                ' based on the one thing which is unique: The name
                ' of the food:
    
                Dim fc As NutritionData.FoodComposition = _
                    NutritionData.FoodComposition.GetInstance(foodCompositionList, _
                                                        "bReAd, WhItE,       toasted")
    
                Stop
    
                ' Hover your mouse over the variable "fc" above
                ' and have a look.
                ' 
                ' For some of what you'll see, you'll see a "+"
                ' beside them (such as the nutrients) so you might
                ' want to click a few of those "+" signs to see
                ' the underlying data of that instance of them.
    
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub
    
    
    
        Private Sub Example4()
    
            Try
                ' This is an example of using the method named
                ' "GetNutrientData".
                ' 
                ' The purpose of this method is to return a single
                ' instance of the class "Nutrient" based on the
                ' name of the food and which nutrient you want it
                ' to return. You choose which nutrient based on
                ' the value of an enum which you'll use.
                ' 
                ' Note that this returns the instance of Nutrient
                ' that's the member of the instance - not a NEW
                ' nutrient instance:
    
                Dim n As NutritionData.Nutrient = _
                    NutritionData.FoodComposition.GetNutrientData(foodCompositionList, _
                                                                  "bran", _
                                        NutritionData.FoodComposition.NutrientType.Iron)
    
                Stop
    
                ' Now hover your mouse over "n" above and I'm sure
                ' you know what to do from there. ;-)
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub
    
    
    
        Private Sub Example5()
    
            Try
                ' This is an example of using the method named
                ' 
                ' "GetNutrientValue".
                ' 
                ' The purpose of this method is to return a type
                ' Double, which is the value of "GetNutrientData"
                ' above. My thought here is that if you want to go
                ' quickly to the actual numeric value of it, use
                ' this one.
                ' 
                ' This method, by the way, will call the method
                ' "GetNutrientData", then it returns only the
                ' value back to you:
    
                Dim value As Double = _
                    NutritionData.FoodComposition.GetNutrientValue(foodCompositionList, _
                                                                   "b  ra  n", _
                                            NutritionData.FoodComposition.NutrientType.Iron)
    
                Stop
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub
    
    
    
        Private Sub GetNutritonData(ByVal url As String)
    
            Try
                NutritionData.Utilites.ReadXML(drvList, _
                                               catList, _
                                               lnList, _
                                               foodCompositionList, _
                                               uomList, _
                                               url, _
                                               NutritionData.Utilites.FileStringType.URL)
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub
    End Class

    Let me know if that explains or if you need me to explain something more precisely please?


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 8:41 PM
  • Keith,

    This is very same code as just a minute ago other than me using Imports statements. It shortens the code, but at first it can be confusing.

    When you see "Forum_Query_9", replace that with the name of your program (it's actually the assembly name but unless you change it, that's your program's name). I'm hoping you can see the code in this forum with my shortened version here:

    Option Strict On Option Explicit On Imports Forum_Query_9.NutritionData Imports Forum_Query_9.NutritionData.FoodComposition Public Class Form1 Private drvList As New List(Of DietaryReferenceValue) Private catList As New List(Of FoodCategory) Private lnList As New List(Of LabelNote) Private uomList As New List(Of UnitOfMeasure) Private foodCompositionList As New List(Of FoodComposition) Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim url As String = _ "http://www.fls-online.com/VBNet_Forum/12-22-14/NutritionData.xml" GetNutritonData(url) ' Uncomment the following out, one at a time, then ' run the program: ' Example1() ' Example2() ' Example3() ' Example4() ' Example5() Stop End Sub Private Sub Example1() Try ' This is an example of using the method named ' "GetAllFoodNames". ' ' The purpose of this method is to return a ' string array of ALL of the names of the foods in ' the generic list which stores them (that is, ' that stores instances of the class ' "FoodComposition". In this example program, ' that's "foodCompositionList" as shown in the ' class-scoped (form-scoped) variables declared ' near the top of this form. ' ' It will return all of the food names ordered in ' any of the three following ways: ' ' * Natural Order (the default) ' * Ascending ' * Descending ' ' You can use it as shown below: Dim foodNames() As String = _ GetAllFoodNames(foodCompositionList) Stop ' When the program gets to "Stop" above, ' execustion will halt the same though you'd put a ' breakpoint in. ' ' When it does, hover your mouse over the variable ' "foodNames" and expand it. It will show all of ' names of the various FoodComposition.FoodName ' entries in natural order because that's the ' default. ' This is the usage if you want to specify the ' order to be OTHER than "Natural Order": foodNames = _ GetAllFoodNames(foodCompositionList, _ NutritionData.FoodComposition.SortOrder.Descending) Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub Private Sub Example2() Try ' This is an example of using the method named ' ' "GetFoodsByCategory". ' ' The purpose of this method is to return a string ' array of all of the names of the foods based on ' the category name. The category name is the name ' of one of the instances of the class ' "FoodCategory". ' ' This one can also be optionally sorted but the ' default is "Natural Order": Dim foodNames() As String = _ GetFoodsByCategory(foodCompositionList, _ "Milk, cream") Stop ' As before, hover over "foodNames" above. ' This is the usage if you want to specify the ' order to be OTHER than "Natural Order": foodNames = _ GetFoodsByCategory(foodCompositionList, _ "MILK, c r e a m", _ NutritionData.FoodComposition.SortOrder.Descending) Stop ' Please notice above that I very intentionally ' skewed how the name is composed. ' ' In all of these methods where a string is one of ' the parameters, I have it set up to ignore ' capitalization and ignore space characters. Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub Private Sub Example3() Try ' This is an example of using the method named ' "GetInstance". ' ' The purpose of this method is to return a single ' instance of the class named "FoodComposition" ' based on the one thing which is unique: The name ' of the food: Dim fc As FoodComposition = _ GetInstance(foodCompositionList, _ "bReAd, WhItE, toasted") Stop ' Hover your mouse over the variable "fc" above ' and have a look. ' ' For some of what you'll see, you'll see a "+" ' beside them (such as the nutrients) so you might ' want to click a few of those "+" signs to see ' the underlying data of that instance of them. Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub Private Sub Example4() Try ' This is an example of using the method named ' "GetNutrientData". ' ' The purpose of this method is to return a single ' instance of the class "Nutrient" based on the ' name of the food and which nutrient you want it ' to return. You choose which nutrient based on ' the value of an enum which you'll use. ' ' Note that this returns the instance of Nutrient ' that's the member of the instance - not a NEW ' nutrient instance: Dim n As Nutrient = _ GetNutrientData(foodCompositionList, _ "bran", _ NutritionData.FoodComposition.NutrientType.Iron) Stop ' Now hover your mouse over "n" above and I'm sure ' you know what to do from there. ;-) Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub Private Sub Example5() Try ' This is an example of using the method named ' ' "GetNutrientValue". ' ' The purpose of this method is to return a type ' Double, which is the value of "GetNutrientData" ' above. My thought here is that if you want to go ' quickly to the actual numeric value of it, use ' this one. ' ' This method, by the way, will call the method ' "GetNutrientData", then it returns only the ' value back to you: Dim value As Double = _ GetNutrientValue(foodCompositionList, _ "b ra n", _ NutritionData.FoodComposition.NutrientType.Iron) Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub Private Sub GetNutritonData(ByVal url As String) Try Utilites.ReadXML(drvList, _ catList, _ lnList, _ foodCompositionList, _ uomList, _ url, _ NutritionData.Utilites.FileStringType.URL) Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub End Class



    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 9:03 PM
  • Hi Frank

    BOTH versions worked perfectly and at the first attempt.  Substitution made for program name:
    Imports Nutrients.NutritionData
    Imports Nutrients.NutritionData.FoodComposition

    I will get my test bed program to work from a local file - things coughed a bit when repeatedly downloading from your url.

    Anyway, excellent success.  It all makes perfect sense.  All the methods yield the data in excellent order.  The differences between the separate methods is fully understood.

    Many thanks.

    Regards
    Keith


    Winchestermili

    Monday, December 22, 2014 9:23 PM
  • Hi Frank

    BOTH versions worked perfectly and at the first attempt.  Substitution made for program name:
    Imports Nutrients.NutritionData
    Imports Nutrients.NutritionData.FoodComposition

    I will get my test bed program to work from a local file - things coughed a bit when repeatedly downloading from your url.

    Anyway, excellent success.  It all makes perfect sense.  All the methods yield the data in excellent order.  The differences between the separate methods is fully understood.

    Many thanks.

    Regards
    Keith


    Winchestermili

    Ok at least it made a little more sense from being able to read the code in the forum here - we didn't used to have that issue but MSFT "changed things" a few years ago. Did anyone ask those of us who USE the forum?

    OF COURSE NOT!

    Anyway, I'll continue on this when I can and apprise you of the updates.


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 9:51 PM
  • Hi Frank

    I will try to keep in contact but things will be different over this coming week.

    Tomorrow I have the misfortune to attend an old friends funeral.  On Wednesday I MUST remember to collect the mother-in-law and bring her to Winchester for Christmas.  If I forget then encapsulation of body parts will follow.  Then Christmas on Thursday and Boxing Day Friday.  Limited time but I will try to keep in contact.

    Thanks for all Your help.  Speak soon....

    Keith


    Winchestermili

    Monday, December 22, 2014 10:36 PM
  • Hi Frank

    I will try to keep in contact but things will be different over this coming week.

    Tomorrow I have the misfortune to attend an old friends funeral.  On Wednesday I MUST remember to collect the mother-in-law and bring her to Winchester for Christmas.  If I forget then encapsulation of body parts will follow.  Then Christmas on Thursday and Boxing Day Friday.  Limited time but I will try to keep in contact.

    Thanks for all Your help.  Speak soon....

    Keith


    Winchestermili

    I'm saddened to hear of your loss. It seems that the older we get, the more of these things we have to attend.

    *****

    Likewise given the time of year and my new-found hardware issues, I may be a while in replying back.


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 22, 2014 10:59 PM
  • It remains an education debate to have features such as "find foods that are high in protein and low in saturated fats" Or get the little blighters to work it out for themselves....the problem is that it all depends on the mass of food consumed. 

    Keith


    Winchestermili

    Keith,

    The following might be a help in accomplishing the goal here, or it might be completely off-base to that end - only you can know the answer here but I've added a new method called "GetNutrientTopN".

    You'll need the latest version of the library and that's here.

    Going back to the test program from yesterday, I've added a new sub as shown below:

    Private Sub Example6() Try ' This is an example of using the method named ' "GetNutrientTopN". ' ' The purpose of this method is to return a ' generic List(Of FoodComposition) which will ' have, in descending order, the top "n" foods for ' the nutrient that you want evaluated. ' ' Probably the better way to explain what it does ' will be with using it in the following: Dim fcList As List(Of FoodComposition) = Nothing fcList = _ FoodComposition.GetNutrientTopN(foodCompositionList, _ NutrientType.Calcium, _ 10) Dim sb As New System.Text.StringBuilder For i As Integer = 0 To fcList.Count - 1 sb.AppendLine(fcList(i).FoodName & " | " & _ fcList(i).Calcium.ToString(UnitOfMeasure.ReturnValue.FullName, 1)) If i < fcList.Count - 1 Then sb.AppendLine() sb.AppendLine("----------") sb.AppendLine() End If Next MessageBox.Show(sb.ToString, "Top Ten, Calcium") Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    You should probably have a look at the method in the class and you can do that by going to line number 2744. In that you'll see how it's set up.

    You can give it any positive value for the quantity to return - it will return UP TO that many; obviously it can't return more than there are.

    Note also the optional parameter:

    Public Shared Function GetNutrientTopN(ByVal fcList As List(Of FoodComposition), _ ByVal type As NutrientType, _ ByVal qtyToReturn As Integer, _ Optional ByVal includeZeroValue As Boolean = True) _ As List(Of FoodComposition)


    By default it will return all of the foods (up to the top N) including those which have a value of zero for that particular nutrient. You can optionally set that to False and it will skip those which have a value of zero.

    When you get back to this, let me know if this is helpful please? The worst that could happen is that I leave it in there and you don't use it. ;-)


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 23, 2014 4:53 PM
  • Hi Frank
    We have been thinking about the TopN idea and we are certain that we will use it.  It really proves great command over all the data.  In the very first program on the Acorn platform (ever heard of Acorn?) we had a section called "Top20".  In truth it provided students with the tools to find an answer to their own question "If my diet is low in iron what foods are a good source of iron?" etc. etc.   The information was presented graphically - please see the description below.  That was about 20-25 years ago when processors were very slow.  My mile of VB6 code to find and bubble sort made things slower.  Your complete command of the data using the new "GetNutrientTopN" method can be put to good use.  Thanks for making the number of finds a user configurable parameter.


    Winchestermili

    Tuesday, December 23, 2014 8:05 PM
  • Keith,

    Sorry for the delay - still dealing with some computer issues here but what you showed has given me another thought. I'm glad that it'll be helpful. :)

    More tomorrow though...


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 24, 2014 12:48 AM
  • Keith,

    First, to answer your question, no I can't say that I've ever heard of Acorn.

    *****

    Reading the text of your scan, I see that the old one could produce a CSV file so that gave me an idea. I've now overloaded that method ("GetNutrientTopN"). The original one is a function and this one is a sub:

    Public Shared Sub GetNutrientTopN(ByVal fcList As List(Of FoodComposition), _ ByVal type As NutrientType, _ ByVal qtyToReturn As Integer, _ ByVal filePath As String, _ ByVal fileType As FileTypeIs, _ Optional ByVal includeZeroValue As Boolean = True)

    By giving it a valid file path and telling it whether to write it out as CSV or XML, it will then call the original method and when that returns, it will create instances of a new PRIVATE class:

    Private Class NutrientRankingData Public Sub New(ByVal _name As String, _ ByVal _nutrientName As String, _ ByVal _nutrientValueString As String, _ ByVal _nutrientUnit As String) FoodName = _name.Trim NutrientName = _nutrientName.Trim NutrientValueString = _nutrientValueString NutrientUnitFullName = _nutrientUnit End Sub Public FoodName As String Public NutrientName As String Public NutrientValueString As String Public NutrientUnitFullName As String Public Overrides Function ToString() As String Dim sb As New System.Text.StringBuilder sb.Append(Chr(34) & FoodName & Chr(34) & ","c) sb.Append(Chr(34) & NutrientName & Chr(34) & ","c) sb.Append(NutrientValueString & ",") sb.Append(NutrientUnitFullName) Return sb.ToString End Function End Class

    As you can see, that private class is pretty simple; it has four public fields:

    • FoodName
    • NutrientName
    • NutrientValueString
    • NutrientUnitFullName

    I can, of course, put in anything you want there but not knowing what you'd want to keep up with, I started with what you see above. Let me know if you'd like it to include other information.

    *****

    To use it, you'll need the latest version of the library which is here and following shows two new subs for your test project:

    Private Sub Example6a() Try Dim desktop As String = _ My.Computer.FileSystem.SpecialDirectories.Desktop Dim csvFilePath As String = _ Combine(desktop, "Example CSV File.csv") FoodComposition.GetNutrientTopN(foodCompositionList, _ NutrientType.Iron, _ 20, _ csvFilePath, _ FileTypeIs.CSV) Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub Private Sub Example6b() Try Dim desktop As String = _ My.Computer.FileSystem.SpecialDirectories.Desktop Dim csvFilePath As String = _ Combine(desktop, "Example XML File.xml") FoodComposition.GetNutrientTopN(foodCompositionList, _ NutrientType.Iron, _ 20, _ csvFilePath, _ FileTypeIs.XML) Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    Note also that you'll need to add one more imports statement at the top:

    Imports System.IO.Path

    Give that a go and let me know your thoughts. :)


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 24, 2014 1:40 PM
  • Frank

    Please could you check that we have the latest library to download OR do you want me to "cut and paste" the new subs into that existing library.

    Example6a and 6b fail because "FileTypeIs.XML" is "not declared"

    Many thanks for all your interesting work.  Things are shaping up very well.

    I have been looking at serialisation and saving a ListView.  I was thinking of basing the approach on:  http://vbcity.com/blogs/xtab/archive/2011/10/17/how-to-serialize-and-deserialize-listview-data.aspx  Is there an easier way to save the FoodList Class?

    Very Best Wishes

    Have a Very Happy Christmas and Best Wishes for the New Year.

    Keith and Margaret

    Winchester, UK


    Winchestermili

    Wednesday, December 24, 2014 3:18 PM
  • Frank

    Please could you check that we have the latest library to download OR do you want me to "cut and paste" the new subs into that existing library.

    Example6a and 6b fail because "FileTypeIs.XML" is "not declared"

    I did that last night and I bet I got confused on which "version" I uploaded.

    Try this one please:

    http://www.fls-online.com/VBNet_Forum/12-24-14/NutritionData_V2.zip

    Sorry about that. I'll get back to your other questions briefly, but I wanted to get this to you. Please let me know if I goofed again?


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 24, 2014 3:25 PM
  • I have been looking at serialisation and saving a ListView.  I was thinking of basing the approach on:  http://vbcity.com/blogs/xtab/archive/2011/10/17/how-to-serialize-and-deserialize-listview-data.aspx  Is there an easier way to save the FoodList Class?

    Very Best Wishes

    Have a Very Happy Christmas and Best Wishes for the New Year.

    Keith and Margaret

    Winchester, UK


    Winchestermili

    I assume you're talking about for your users' data? Before I answer it, I want to be sure that I understand the perspective.

    *****

    Happy holidays to you two also! :)


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 24, 2014 3:30 PM
  • I have been looking at serialisation and saving a ListView.  I was thinking of basing the approach on:  http://vbcity.com/blogs/xtab/archive/2011/10/17/how-to-serialize-and-deserialize-listview-data.aspx  Is there an easier way to save the FoodList Class?

    Keith,

    I read the article that you posted a link to, at least briefly, and I’d like to make some comments about.

    First, his endorsement of using an ArrayList is precisely opposite my view on it. Sometimes using an ArrayList is unavoidable – as, for example, when serializing to SOAP (which is just a form of XML). An example of SOAP data is shown here.

    Since XML (and thus, SOAP xml) doesn’t support generics, then the only way to serialize the data to any sort of XML file was through an ArrayList.

    An ArrayList is, intentionally, NOT type-safe. That might sound like a good thing – hey you can toss anything in there that you want to! – but losing the type safety is a dangerous prospect so use it with extreme caution and even then only if that’s the single one way you can do it (in my opinion, obviously).

    I’m not casting aspersions here – in his example it actually *is* the only way to do that but a better way would have been to create a serializable class (all but one of the classes I’ve been working on for this project will eventually be serializable, I’m just not up to that point yet) and then serialize a collection of that class.

    With nothing else to use though, the ArrayList was really the only way he could do that.

    Do understand something though: He’s not serializing the ListView, he’s serializing the data in the ListView. You can’t serialize a Windows control for one simple reason: They were never set up to be serializable. We have no way to change that.

    *****

    Even though I’m not up to that point yet, if you’ll look at the code for the class library, at the end of it all is a NotInheritable class named “Utilities” and this shows an excerpt of it.

    Notice that all along I’ve had that in there and intend to use it in two ways:

    Serializing The Collections Of The Classes

    When I set up the program for the adding/editing/deleting (which should be pretty soon), once it has the original data from the online XML file, it won’t go back to that online version ever again. Instead, that data will be held on your computer as a binary file.

    One single binary file will contain all of the data for all of the instances of all of the classes. Say that three times quickly. ;-)

    It will be updated anytime you make a change whether that’s to add something new, modify something existing, or remove something.

    Creating An Instance Of The Main Class Using Deep Cloning

    The fact that a class is a reference type (as opposed to a value type), and further, the main class uses instances of other classes, means that a single instance will be changed immediately if a change happens anywhere in the chain; it’s a reference type so, obviously, a change to the underlying data is automatically reflected in the instance of the main class.

    That’s good! That means that if you change something in one of the smaller underlying classes, that’s automatically reflected in the large main class for any which use that instance.

    …but that’s also an issue when trying to edit things. I’ll explain:

    When I set things up in the program to allow for editing, I’ll show some of it modally; that is, in a form which has to be dismissed before the calling code can continue. I will typically have an “OK” and a “Cancel” button.

    If you look at the methods in the classes, let’s say that I pass in the instance that you’re trying to edit and you make a number of changes then decide … “nah, never mind” … and you click the “Cancel” button.

    Well too late now! You made those changes! Look at the code in the class and you see that it’s unavoidable because you told it to make those changes and the methods of the classes did as you told it to.

    So how can you get around that?

    One way is by using deep cloning. Per class, I’ll have a “GetDeepClone” method which will hand you back an identical copy of the instance with all of the references intentionally broken.

    I can do that using [binary] serialization.

    So when I hand that instance to the modal form, you’re not working with the “real” instance at all; you’re working with a clone of it. If you make the changes and click “OK”, then my code will update the real one based on your changes. If you click on “Cancel” instead – no harm done.

    *****

    Serialization of your users’ data may or may not be the best way to do it, but we’ll talk more about the pro’s and con’s of it when we get that far along. :)


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 24, 2014 5:14 PM
  • Hi Frank

    The new Library worked perfectly.  "Example" XML and CSV Files were created.  The whole issue of presentation of this "TopN" data needs a lot of throught because it will be misleading for 11-16 year old stuydents dealing with it for the first time.  Not sure where we can use the saved XML or CSV files but the CSV file was very "readable" in Excel.  I will discuss with Margaret.

    The serialization is intended for the User created Food_List - the list where a daily diet is created for Analysis.  The User will save their food selections for later modification and comparison of the Analysis for one FoodList against another FoodList.  Previously I used a ListBox and created a string of STR(food_name & Mass).  However, a program array held the food_number and food_mass. In this version a ListView looks a better way - simply with 2 columns.  Therefore the serialisation of the ListView will be the User's List ready for reloading.  Previously saved with a FileType ".nut".  The VBCity link seems quite straightforward.

    Regards
    Keith


    Winchestermili

    Wednesday, December 24, 2014 5:14 PM
  • Just a quick thought.  With the graphical display we are thinking that we could link the 100gram amount with the "Portion Size".  The primary use for the dreaded "#19" "Portion Size" information was when a food is selected then the student is required to input the amount eaten or proposed to be eaten.  The Portion Size was information under the Input Amount dialogue box.  BUT we could use it again at "TopN".  A lot of foods have a range of mass for the portion size - not a simple number - but the User could use the "Portion Size" as a guide to what effect the addition or subtraction will make.  We could use the Portion Size as a "Tool Tip" comment..........

    Winchestermili

    Wednesday, December 24, 2014 5:28 PM
  • Just a quick thought.  With the graphical display we are thinking that we could link the 100gram amount with the "Portion Size".  The primary use for the dreaded "#19" "Portion Size" information was when a food is selected then the student is required to input the amount eaten or proposed to be eaten.  The Portion Size was information under the Input Amount dialogue box.  BUT we could use it again at "TopN".  A lot of foods have a range of mass for the portion size - not a simple number - but the User could use the "Portion Size" as a guide to what effect the addition or subtraction will make.  We could use the Portion Size as a "Tool Tip" comment..........

    Winchestermili

    I'm not sure that I'm following that. Actually I know I'm not. ;-)

    Didn't you say that the nutrient values all of the foods are based on some given amount of it (I think you said 100 grams)? I assumed that all along.


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 24, 2014 5:33 PM
  • Frank

    All the Energy, Nutrients and Vitamin values for every food in the database are based on 100 grams of that food.

    That must be borne in mind when using the TopN data.  Good sources of Iron are:  thyme, herbs, curry powder and pepper but no-one will eat 100 grams of those foods.  But we could show the "Typical Portion Size" information as a "Tool Tip" e.g. for thyme "1 level teaspoon = 1g"

    Now, "Special K" cereal has one fifth of the iron content but the "Typical Portion Size" is about "30 grams".  Conclusion:  Forget the "TopN" (thyme) and eat more "Special K"

    Then by choosing "Special K" the student will notice that the Sodium level has shot up because it is laced with lots of salt..........

    Hovering a pointer over the name could give the "Typical Portion Size" to suggest a suitable selection.

    Keith


    Winchestermili

    Wednesday, December 24, 2014 5:59 PM
  • Frank

    All the Energy, Nutrients and Vitamin values for every food in the database are based on 100 grams of that food.

    That must be borne in mind when using the TopN data.  Good sources of Iron are:  thyme, herbs, curry powder and pepper but no-one will eat 100 grams of those foods.  But we could show the "Typical Portion Size" information as a "Tool Tip" e.g. for thyme "1 level teaspoon = 1g"

    Now, "Special K" cereal has one fifth of the iron content but the "Typical Portion Size" is about "30 grams".  Conclusion:  Forget the "TopN" (thyme) and eat more "Special K"

    Then by choosing "Special K" the student will notice that the Sodium level has shot up because it is laced with lots of salt..........

    Hovering a pointer over the name could give the "Typical Portion Size" to suggest a suitable selection.

    Keith


    Winchestermili

    Ok, but I'm confused on the relevance here. Your notes already show that information I thought?

    *****

    By the way, a small modification here and this is the latest version.

    I've changed the sub which reads the XML file to a function instead. You can still use it exactly the same way but if you use it as a function, you can then get the DateTime of the version. Modify one of your subs in the test project as shown below:

    Private Sub GetNutritonData(ByVal url As String) Try Dim dt As DateTime = _ Utilites.ReadXML(drvList, _ catList, _ lnList, _ foodCompositionList, _ uomList, _ url, _ NutritionData.Utilites.FileStringType.URL) MessageBox.Show(dt.ToLongDateString & " " & dt.ToLongTimeString) Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub

    Yours will show a different time - that's dotNet knowing that the format of the string included an offset from GMT so it automatically adjusts it to yours.

    I thought perhaps you might want to include this in your program's Help>>About section (or other suitable place).

    :)


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 24, 2014 6:18 PM
  • Keith,

    Something to consider here. Once again, I can always leave it there and you just not use it.

    The new version is here and this is the new sub to try it in your test program:

    Private Sub Example7() Try Dim comparison As FoodNutrientComparison = Nothing comparison = FoodComposition.GetFoodComparison(foodCompositionList, _ "savoury rice", _ "bread, rye") MessageBox.Show(comparison.ToString, "Food Nutrient Comparison") Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    Something to consider anyway. :)


    Still lost in code, just at a little higher level.

    :-)

    Friday, December 26, 2014 12:41 AM
  • Hi Frank

    We hope that you had a great Christmas.  Many thanks for your last couple of posts.

    Returning the Date/Time stamp when using the “GetNutritonData" is going to be essential since we can then check the existing file in the User ProgramData folder and update if necessary.

    Thinking about the function called "GetNutrientValue" it will be a very useful method to get very quickly at the numerical data for each food.  If you have time please could you add methods for:

    "GetTypicalPortionComments" - there are 2 or 3 places where that will be useful and the program will benefit from the speed of access.  These are the two "typort" columns in the Excel file (Columns X & Y)

    "GetLabelComments" - Again quick access would be appreciated to the last two columns in the Excel file  (Columns Z and AA called "Label Name" and "LabNote") 

    Both could be Functions and will be very similar.

    The idea of a "Comparison" has great potential.  Previous attempts at something similar proved to be far too slow.  We will try a few schools with a draft outline for their comment.  We are thinking that it could be displayed as a vertical reference line with horizontal bars showing % values to the RHS for greater and to the LHS for less than values.  Can you please consider this as a Function  so that the numerical value is returned so that it can be used to draw a simple graphic??  We would also like to suppress zero values.  Ideally, the function could specify the mineral or vitamin. We could have a check box for all the vitamins and minerals so the Function would specify which vitamin or mineral and return the numerical difference.  We will also show the numerical value; probably as a column on the RHS.

    Many thanks for the notes regarding the serialisation.  If we can use that approach then fine.  However, it is not a huge problem to empty a ListView into a datafile.  I tries using your library of procedures to serialise the ListView of the food_names and masses of each food.  The program halted because “’SaveBinaryData’ is not declared.  It may be inaccessible due to its protection level”.  Is that part of the library protected?

    Very Best Wishes

    Keith


    Winchestermili

    Saturday, December 27, 2014 3:26 PM
  • Hi Keith,

    I'm not out of the woods on my computer issues yet.

    I'm not known for brevity so I'll spare you the details (unless you just want to know), but it'll likely be the end of this next week before I'll be back to normal.

    For right now, everything that I try to do is painstakingly slow and difficult (my computer is not only interminably slow but every few minutes it just "goes stupid" and freezes for about a minute or so, then pops back to life).

    *****

    On to the matter at hand though, this is the latest library build and I feel sure that I probably still don't quite have it like you want, but I'll step through the changes:

    Private Sub Example7() Try Dim comparison As FoodNutrientComparison = Nothing comparison = FoodComposition.GetFoodComparison(foodCompositionList, _ "savoury rice", _ "bread, rye") MessageBox.Show(comparison.ToString, "Food Nutrient Comparison") ' To get the the actual values of the nutrients ' (both the one compared from and the one compared ' to), you can do, for example: Dim comparedFrom As Double = _ comparison.Calcium_Comparison.NutrientValueCompareFrom Dim comparedTo As Double = _ comparison.Calcium_Comparison.NutrientValueCompareTo ' When the program gets to "Stop" below, you might ' want to hover your mouse over the variable named ' "comparison" and expand a few of those. You can ' then see how things are laid out in that instance. Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    The screenshot shows that the .ToString method isn't showing data for any which were zero. The data IS still in there, so do be aware that's only done in the .ToString override. When the program gets to "Stop", hover your mouse over the instance of FoodNutrientComparison called "comparison" and expand a few of those. I think that'll give you insight as to what's going on.

    Also be sure to expand some of the nutrient comparisons that aren't shown in the .ToString - like I said, they are there, but they one or both of the values (that is, compareTO and compareFROM) is zero.

    In the method that creates those, I have it specifically looking for either of those conditions. An excerpt is shown below:

    If Double.IsPositiveInfinity(compEnergy) OrElse Double.IsNaN(compEnergy) Then compEnergy = 0 End If


    I've said in this forum before: "Can you divide a number by zero" and of course most here say "no, that's undefined". They're wrong: You can provided that the numerator isn't zero. The problem is that we can't handle the answer which is either positive or negative infinity!

    0/0 is undefined though (NaN which is "Not a Number"), so that checks for either condition and sets the comparison value to zero. In the class that creates it (what you'll see shown when you expand those), if it sees zero as the comparison value, the comparison text is just set to an empty string.

    All of that will make more sense when you expand that instance and have a look around.

    *****

    In both of the requested new functions, you didn't really tell me what you wanted to returned. You did but -- not really. Currently I have it simply returning a single string but if you want it to return a value such that you can specifically get to either of the two strings, I can do that, but like I said, you didn't specify so I was guessing:

    Private Sub Example8() Try Dim s As String = _ FoodComposition.GetTypicalPortionComments(foodCompositionList, _ "custard powder") MessageBox.Show(s, "GetTypicalPortionComments") s = _ FoodComposition.GetLabelComments(foodCompositionList, _ "custard powder") MessageBox.Show(s, "GetLabelComments") Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    Let me know if you want that changed.

    *****

    About serialization, keep in mind that I don't yet have any of the classes tagged to be serializable. When I do, I'll also create methods to save whatever is needed. That said though, depending on your intended use, it might not be the best approach (for a number of reasons).

    I encourage you to remember that right now I'm still working on the "data" and at a point later in time, I'll then help with what's needed for the user program.


    Still lost in code, just at a little higher level.

    :-)

    Saturday, December 27, 2014 5:38 PM
  • Many thanks for the notes regarding the serialisation.  If we can use that approach then fine.  However, it is not a huge problem to empty a ListView into a datafile.  I tries using your library of procedures to serialise the ListView of the food_names and masses of each food.  The program halted because “’SaveBinaryData’ is not declared.  It may be inaccessible due to its protection level”.  Is that part of the library protected?

    I thought that as an aside, I'd create something which uses the binary serialization/deserialization so that you can see how it works. I have the code for it (it's the test project's code but it's a good many lines now) shown on a page of my website here.

    Don't copy from the formatted text that you'll see there - instead, click the link at the top and it will open the code as a plain text file. Use that to copy from.

    You'll see a new serializable class below Form1's class:

    <Serializable()> _ Public Class SimpleClassWithSharedMethods Private _colorToBeUsed As Color Private _nameToDisplay As String Private _dateExample As Nullable(Of DateTime) Private Sub New(ByVal c As Color, _ ByVal name As String) _colorToBeUsed = c _nameToDisplay = name.Trim End Sub Private Sub New(ByVal c As Color, _ ByVal name As String, _ ByVal d As DateTime) _colorToBeUsed = c _nameToDisplay = name.Trim _dateExample = d End Sub Public ReadOnly Property ColorToBeUsed() As Color Get Return _colorToBeUsed End Get End Property Public ReadOnly Property DateExample() As Nullable(Of DateTime) Get Return _dateExample End Get End Property Public ReadOnly Property NameToDisplay() As String Get Return _nameToDisplay End Get End Property Public Shared Sub AddNew(ByRef simpleList As List(Of SimpleClassWithSharedMethods), _ ByVal c As Color, _ ByVal name As String) Try ' I should do validation here but for ' this I'm going to skip it... simpleList.Add(New SimpleClassWithSharedMethods(c, name)) Catch ex As Exception Throw End Try End Sub Public Shared Sub AddNew(ByRef simpleList As List(Of SimpleClassWithSharedMethods), _ ByVal c As Color, _ ByVal name As String, _ ByVal d As DateTime) Try ' I should do validation here but for ' this I'm going to skip it... simpleList.Add(New SimpleClassWithSharedMethods(c, name, d)) Catch ex As Exception Throw End Try End Sub Public Shared Sub Save(ByVal simpleList As List(Of SimpleClassWithSharedMethods), _ ByVal filePath As String) Try ' I should do validation here but for ' this I'm going to skip it... Utilites.SaveBinaryData(simpleList, filePath) Catch ex As Exception Throw End Try End Sub Public Shared Sub Load(ByRef simpleList As List(Of SimpleClassWithSharedMethods), _ ByVal filePath As String) Try ' I should do validation here but for ' this I'm going to skip it... With simpleList .Clear() .TrimExcess() End With simpleList = DirectCast(Utilites.LoadBinaryData(filePath), _ List(Of SimpleClassWithSharedMethods)) Catch ex As Exception Throw End Try End Sub End Class


    I have a new sub set up in the test project:

    Private Sub Example9() Try ' I'm going to create a few new instances of the ' simple class as shown below. Feel free to modify ' these, add to them, remove some - whatever you ' want to do. ' ' The purpose here is to show that the binary ' serialization works: SimpleClassWithSharedMethods.AddNew(exampleList, _ Color.Red, _ "The Grapes Of Wrath") SimpleClassWithSharedMethods.AddNew(exampleList, _ Color.Red, _ "War And Peace") SimpleClassWithSharedMethods.AddNew(exampleList, _ Color.Red, _ "The Catcher in the Rye", _ Today) SimpleClassWithSharedMethods.AddNew(exampleList, _ Color.Red, _ "To Kill a Mockingbird", _ #1/1/1974#) ' Now I'm going to use the "Save" method that I ' put in that class to save the collection (that ' is, the list named "exampleList") to a binary ' file which will be put on your computer's ' desk Dim desktop As String = _ My.Computer.FileSystem.SpecialDirectories.Desktop Dim binaryFilePath As String = _ Combine(desktop, "BinaryFile.bin") SimpleClassWithSharedMethods.Save(exampleList, _ binaryFilePath) Stop ' When the code gets here, please confirm two ' things: ' ' - First, scroll back up top and and hover your ' mouse over (then expand) the list named ' "exampleList". Confirm that everything is in ' there. ' ' - Secondly, look on your desktop and you should ' see the file. Right-click that file and choose ' "Open With" and choose Notepad or any text ' editor. Have a look at the contents of the file ' for your edification. ' ' Notice that it stores strings as simple readable ' strings, but the color and the nullable are ' stored as true binary representations. ' ' ALSO note that it includes, near the top, the ' assembly information. That's its "identity" ' which it will use when deserializing. ' Now I'm going to clear the list entirely: exampleList.Clear() Stop ' At this point, please confirm that the list is ' empty by hovering your mouse over "exampleList" ' at the top of this code. It should show a count ' of zero. ' Finally then, prove that it works by "loading" ' the data back from the binary file: SimpleClassWithSharedMethods.Load(exampleList, _ binaryFilePath) Stop ' Confirm that your list ("exampleList") is now ' back intact, just as though I'd never cleared ' it. ' ' :) Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    Hopefully that might provide some insight into what it does and how it works. :)


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Saturday, December 27, 2014 7:18 PM ...goofed with some of the code that I posted.
    Saturday, December 27, 2014 7:10 PM
  • Hi Frank

    We are sorry to hear about Your hard drive issues.  We will be pleased to supply a new one.

    There are three matters - so apologies for distracting you away from the vital data handling.

    Regarding the Comparison procedure.  I completely understand the issue regarding the division by zero.  The problem comes when you have extremes of comparison.  "Savoury rice" and "bread, rye" is a sensible comparison but if you have a more "extreme" comparison say "Savoury rice" and "oranges" then it APPEARS that "oranges" have zero "Vitamin C".  I appreciate that you are busy with handling the data  but we might have to return to this and add the information "whilst the value is zero in one food that vitamin does appear in the food with which it is being compared".  So we might look at a pointer hovering over a full list of energy, minerals and vitamins and have a 2 bar chart showing the relative levels in each.  The final result will only be known after trails with quite young students. 

    Not only is the "division by zero" a challenge but in the "extreme" case when "Savoury rice" and "oranges" are compared this generates massive numbers e.g. Sodium; as expected is a poor comparison because it returns a value of 28700%.  That is only complicated by the reverse comparison "oranges" vs. "Savoury rice" when more tangible results appear to be displayed. 

    Regarding the Functions for "GetTypicalPortionComments" and "GetLabelComments" the intention is to access the comments individually for each cse - i.e. two sets of two separate lines.  That way the individual lines can be used in a Label.Text OR can be sent to a printer OR can be sent to a cell in a spreadsheet.  These functions could have a "1" or "2" parameter to access each line?

    We appreciate that you are busy with the data but thank you for the interesting comments about serialization.  Having the data "not easily readable" is actually an advantage to stop interference.  The procedure that you set up worked fine and the list was cleared and re-loaded without problems.  It is a valuable insight into the way that the data can be saved.  Many thanks.

    Best Wishes

    Keith


    Winchestermili

    Sunday, December 28, 2014 11:03 AM
  • Hi Keith,

    Once I'm over the hill with this problem this next Thursday - at least I'm hoping it will be resolved - then I'll explain all of it in detail. For now I'll just keep trying to work anyway.

    *****

    Last part first, this is the latest build.

    I have two new nested classes for these: LabelData and TypicalPortionData. Unlike something I did a while back, these are nested but they're public, not private (otherwise I couldn't expose them publicly). They each have two (2) string properties so that you can access either of them in either of the classes as shown below:

    Private Sub Example8() Try Dim tpd As _ FoodComposition.TypicalPortionData = Nothing tpd = _ FoodComposition.GetTypicalPortionComments(foodCompositionList, _ "custard powder") MessageBox.Show(tpd.ToString, _ "GetTypicalPortionComments") Dim ld As _ FoodComposition.LabelData = Nothing ld = _ FoodComposition.GetLabelComments(foodCompositionList, _ "custard powder") MessageBox.Show(ld.ToString, "GetLabelComments") Stop ' Hover your mouse over "tpd" and then "ld" and ' expand them. For each, you'll see two string ' properties so that's how you can access either ' of them. Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    Let me know if that's what you want or not please.

    *****

    As for the other, I do see your points. The actual values of each are there now though, so I'm not sure what I could do on my end to help with that. I have thought before about a little different approach but I don't know how feasible it is:

    Is there any sort of "standard" that it could be evaluated against - as opposed to evaluating two food, evaluate the nutrients of a food against that standard maybe?


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 28, 2014 3:27 PM
  • Hi Frank
    Excellent.  The "Typical_portion_tpd" and the "LabelData_ld" comments are separate and can be used in a flexible way as needed to suit the output required (labels, printing Excel etc).  Many thanks.

    The issue of drawing "Comparisons" is not easy and every person in the Educational World has at least one opinion.  In the last 20 years we have not managed to find two people to agree which is the best approach.  However, you have provided the tools to draw comparisons in both absolute terms (e.g. milligrams) and in relative terms (expressed as a <> percentage).  One other issue that I cannot get people to agree about is "should salt be shown as a red or a green bar chart".  Too much  is not "recommended" but you still need some in a balanced diet.  Our Comparison is based on 100 grams which does not help the matter when Sodium is found in a wide range of foods - see a typical food list below for a "Teenager"... Only one food does NOT contain Sodium.

    In your reply you refer to a "Standard".  That is really where this is all headed because the objective is to Analyse a Diet and compare it against the Dietary Reference Value. A daily List of Foods might contain about 30+ food sources. Each food on the list needs to be modified for the mass consumed and then the individual energies, proteins, minerals and vitamins need to be summated.  Then those totals compared against the DRV.  Therefore the "TopN" approach is valuable because it will allow students to identify TYPES of foods that they are interested in (e.g. ones high in Sodium) and then modify their Daily Food List to reach the desired DRV for their age group.  The "Investigate" feature that I created for the VB6 program is shown below:

    Many thanks for all Your help.

    Best Wishes (and keep off the salty bread rolls)
    Keith


    Winchestermili

    Sunday, December 28, 2014 5:56 PM
  • Keith,

    I'm working on another idea - it may be something useful or maybe not - but I'll show you when I get done. At this snail's pace (computer issues), it'll definitely be tomorrow your time before I can show you though.

    Stay tuned... ;-)


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 28, 2014 6:05 PM
  • Keith,

    This is what I have. First, the latest build is here.

    I've changed some things around as shown below:

        Private Sub Example7()
    
            Try
                Dim comparison As FoodNutrientComparison = Nothing
    
                comparison = FoodComposition.GetFoodComparison(foodCompositionList, _
                                                               "savoury rice", _
                                                               "bread, rye")
    
                MessageBox.Show(comparison.ToString, "Food Nutrient Comparison")
    
                ' To get the the actual values of the nutrients
                ' (both the one compared from and the one compared
                ' to), you can do, for example:
    
                Dim comparedFrom As Double = _
                    comparison.Calcium_Comparison.NutrientValueCompareFrom.Value
    
                Dim comparedTo As Double = _
                    comparison.Calcium_Comparison.NutrientValueCompareTo.Value
    
                ' When the program gets to "Stop" below, you might
                ' want to hover your mouse over the variable named
                ' "comparison" and expand a few of those. You can
                ' then see how things are laid out in that instance.
    
                Stop
    
                ' ***** NEW AS OF 28 Dec, 2014 *****
                ' 
                ' Notice above that I changed how to get the
                ' values. It's now a type "Nutrient" where
                ' previously it was a type "Double". I added the
                ' ".Value" to get the value (as a type double).
                ' 
                ' Also notice that the .ToString won't show you
                ' much! I've modifed that as shown in the
                ' following:
    
                MessageBox.Show(comparison.ToString(FoodNutrientComparison.ValuesToDisplay.ComparisonPercentOnly), _
                                "Food Nutrient Comparison")
    
                Stop
    
                ' Note that there's an enum being used in the
                ' overloaded version of .ToString.
                ' 
                ' Please try the others also:
    
                MessageBox.Show(comparison.ToString(FoodNutrientComparison.ValuesToDisplay.ComparisonValuesOnly), _
                               "Food Nutrient Comparison")
    
                Stop
    
                MessageBox.Show(comparison.ToString(FoodNutrientComparison.ValuesToDisplay.PercentAndValues), _
                              "Food Nutrient Comparison")
    
                Stop
    
                ' Note also that you can optionally tell it how
                ' many decimal places to show (only applicable to
                ' the two enums which show values, obviously).
                ' 
                ' It defaults to one decimal place.
                ' 
                ' You can set to a value between 0 and 5,
                ' inclusive. If you set it for some other value,
                ' it will ignore you and use its default of one
                ' decimal place:
    
                MessageBox.Show(comparison.ToString(FoodNutrientComparison.ValuesToDisplay.PercentAndValues, _
                                                    2), _
                                                    "Food Nutrient Comparison")
    
                Stop
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub

    You might wonder why I spent so much on the overridden .ToString method. After all, that's just for testing things, not for actual use in your program -- right?

    Well, not necessarily. If I get it to show exactly what you want it to show (for example, in a read-only TextBox with a vertical scrollbar), then why not use it as is?

    Something to consider anyway.

    The new method that I added is shown below:

        Private Sub Example7b()
    
            Try
                ' This is the new method that I added today (28
                ' Dec, 2014).
                ' 
                ' It's very similar to the one above - in fact
                ' it's identical to it other than rather than
                ' comparing the nutrient values of two foods, it
                ' compares the nutrient values of a food with the
                ' DietaryReferenceValues for some stated group
                ' name:
    
                Dim comparison As FoodNutrientComparison = Nothing
    
                ' I'll use a little LINQ here to get the name of
                ' the group:
    
                Dim groupName As String = _
                    (From drv As DietaryReferenceValue In drvList _
                         Where drv.SexAndAgeGroup.ToLower.Contains("man") AndAlso _
                             drv.SexAndAgeGroup.ToLower.Contains("51") _
                                 Select drv.SexAndAgeGroup).FirstOrDefault
    
                comparison = _
                    FoodComposition.GetFoodComparisonForDRV(foodCompositionList, _
                                                            drvList, _
                                                            groupName, _
                                                            "specialk")
    
                ' Using the same methods for the .ToString used in
                ' the other one:
    
                MessageBox.Show(comparison.ToString(FoodNutrientComparison.ValuesToDisplay.ComparisonPercentOnly), _
                               "Food Nutrient Comparison")
    
                MessageBox.Show(comparison.ToString(FoodNutrientComparison.ValuesToDisplay.ComparisonValuesOnly), _
                               "Food Nutrient Comparison")
    
                MessageBox.Show(comparison.ToString(FoodNutrientComparison.ValuesToDisplay.PercentAndValues), _
                              "Food Nutrient Comparison")
    
    
                Stop
    
                ' Be sure to hover your mouse over and expand
                ' "comparison" as it's now changed from what it
                ' was. I has more data - that's how it's able to
                ' display the units now.
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub


    Your thoughts please?


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Sunday, December 28, 2014 8:26 PM ...oops, wrong screenshot!
    Sunday, December 28, 2014 8:13 PM
  • Keith,

    I don't know how I managed to look right at a mistake and not see it - but anyway,this is the fixed one.

    For the enum in the .ToString method to show values only, it wasn't showing what was being compared! I guess the fact that I knew what they each were, I initially didn't "see" the names not being there.

    Sorry about that...


    Still lost in code, just at a little higher level.

    :-)

    Sunday, December 28, 2014 9:07 PM
  • Hi Frank

    Apologies for the short delay but we have been thinking about the Comparisons. We have contacted a couple of colleagues who are responsible for teaching "Food and Nutrition".

    The general census is that there is too much information by giving all the nutrients.  So, if you were comparing bread,rye and savoury rice then you would not be interested in levels of fat and saturated fat.  Secondly it is not the absolute value contained in those foods BUt it is the contribution to that diet.  Therefore in the Sodium Investigation above the levels of Sodium are the same for both "donuts" and "pasteurised milk"  BUT you only have 60g of donuts and 250grams of milk.  Four times the mass of milk contributes the same a the donuts - therefore the consideration of mass is essential. 

    We need to examine all the options with the Teachers and the Users.  It is not easy satisfying all the people all the time.

    The general consensus also is that you should only examine one Nutrient/Mineral/Vitamin at a time.

    However, being able to access "ComparedFrom" and "ComapredTo" is taking us back full circle to the Method to quickly find the Value of a Nutrient using "GetNutrientValue".

    I think that an improved version of the "Investigate" screen coupled with the "TopN" might be the best way ahead in the short term.  I am still interested in the idea of choosing two foods and hovering over a Nutrient to give a comparison - that way it will reduce the rather daunting list of information and hone-in on the Nutrient of interest.  The actual masses of the separate foods being compared will have to be taken into account.

    Best Wishes

    Keith


    Winchestermili

    Monday, December 29, 2014 8:53 PM
  • Keith,

    I'm confused on whether this is a directive for me to do/change something or not?

    *****

    My problem with all of this, for which I don't have a proposed solution, is this:

    If someone were to say "That has nine milligrams of calcium in it", my reaction would be: "Ok, what's your point? Is that good or bad?"

    All of this is missing some sort of context - nothing to really gauge those number by, do you know what I mean here?


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 29, 2014 9:00 PM
  • Hi Frank,

    Please do not change anything because we have a wide range of Methods to handle the data.  It will take a while to get all concerned to agree a way to improve a diet.  Then we can used a combination of the methods that you have proposed.

    The general consensus is that it is multi-dimensional.  1000 foods and all the selections within a diet have diffrerent masses and a range of Nutrients.   The purpose of this Educational Software is to show the User where their diet stands against the Daily Reference Value.  Then at that comparison the User is expected to think of the wide range of alternatives that are possible.  The "TopN" is very useful provided mass is taken into account.

    We will discuss further with Users so I think we should hold off the "Comparison" at this stage.  I hope this has not proved to be too large a distraction from Your goal of dealing with the data.

    Best Wishes

    Keith


    Winchestermili

    Monday, December 29, 2014 9:14 PM
  • Hi Frank,

    Please do not change anything because we have a wide range of Methods to handle the data.  It will take a while to get all concerned to agree a way to improve a diet.  Then we can used a combination of the methods that you have proposed.

    The general consensus is that it is multi-dimensional.  1000 foods and all the selections within a diet have diffrerent masses and a range of Nutrients.   The purpose of this Educational Software is to show the User where their diet stands against the Daily Reference Value.  Then at that comparison the User is expected to think of the wide range of alternatives that are possible.  The "TopN" is very useful provided mass is taken into account.

    We will discuss further with Users so I think we should hold off the "Comparison" at this stage.  I hope this has not proved to be too large a distraction from Your goal of dealing with the data.

    Best Wishes

    Keith


    Winchestermili

    The biggest distraction right now is my damned computer issues!

    *****

    Speaking of the TopN though, I thought of something the other day and that's this:

    Currently it makes no distinction - it's all of the foods in the database (well, maybe not an appropriate term, but in a sense, it actually is).

    What about foods which are tagged as "TakeAway" and/or what about foods tagged as "ReadyMeal"? Obviously those are really different than a food like, for example, "Rice, Brown, Whole Grain".

    It's hardly a fair comparison don't you think? Should it deal with those separately somehow? Not include them or ONLY include them or ... some combination thereof?


    Still lost in code, just at a little higher level.

    :-)

    Monday, December 29, 2014 9:23 PM
  • Hi Frank Ummmmmm. At the intended level of education not everything is ideal. This will be the first time that some students will have encountered diet analysis. It is more of an introduction than a scientific tool. However, take away and Ready Meals are considered as A food in this exercise. A "black box" portion contains nutrients, vitamins and minerals. Another very relevant question is "what is a pizza". Margaret's pizza is quite different to the cheesy bits of cardboard that you can buy as a frozen frisbee. In educational terms one good exercise given to students is to select 450grams of a Ready Meal and analyse that choice. Then the Student designs their own Idential meal. What are the differences using fresh produce? The Student learns that ready meals have very high salt to give flavour, high cheap saturated fats, low vitamin C due to cooking and re- heating. There are significant differences which the Student must identify. The base Ready Meal upon which the data is based is questionable but still has educational values. The "design" of a meal is also part of the curriculum as is the packaging and labelling. Best wishes (beware high sodium and low vitamin C) Keith

    Winchestermili

    Monday, December 29, 2014 10:14 PM
  • Hi Frank Ummmmmm. At the intended level of education not everything is ideal. This will be the first time that some students will have encountered diet analysis. It is more of an introduction than a scientific tool. However, take away and Ready Meals are considered as A food in this exercise. A "black box" portion contains nutrients, vitamins and minerals. Another very relevant question is "what is a pizza". Margaret's pizza is quite different to the cheesy bits of cardboard that you can buy as a frozen frisbee. In educational terms one good exercise given to students is to select 450grams of a Ready Meal and analyse that choice. Then the Student designs their own Idential meal. What are the differences using fresh produce? The Student learns that ready meals have very high salt to give flavour, high cheap saturated fats, low vitamin C due to cooking and re- heating. There are significant differences which the Student must identify. The base Ready Meal upon which the data is based is questionable but still has educational values. The "design" of a meal is also part of the curriculum as is the packaging and labelling. Best wishes (beware high sodium and low vitamin C) Keith

    Winchestermili

    Point made.

    Tomorrow I'll start putting together what's needed to build the program that you'll use for editing, so I'll let you know the progress of that soon.


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 30, 2014 12:27 AM
  • Hi Frank

    Thinking about useful shortcuts - is there a way to access a class of the Nutrient Type for the Main FoodComposition and DRV Nutrients (which are slightly different)?  What I am thinking about is that there may be instances where Combo or ListBoxes may need to be filled with:

    FoodComposition.NutrientType()

    Energy
    Protein
    Fat
    Saturated fat
    Carbohydrate
    Sugar
    Sodium 
    Calcium
    Iron
    Vitamin A
    Vitamin B1
    Vitamin B2
    Niacin
    Vitamin C
    Vitamin D
    Fibre


    DRV - DietaryReferenceValue.NutrientType()

    Energy
    Protein
    Sodium 
    Calcium
    Iron
    Vitamin A
    Vitamin B1
    Vitamin B2
    Niacin
    Vitamin C
    Vitamin D

    Please let me know if that short cut is built in for easy access.

    I hope that your hard drive issues are not causing too much problem.  We will be pleased to pay for a decent new hard drive.  I have my own problem - the glass panel of our Bosch oven has literally fallen out - it was bonded in with high temperature mastic.  The oven took quite a hammering over Christmas.

    Very Best Wishes for a Happy and Prosperous New Year

    Keith and Margaret


    Winchestermili

    Tuesday, December 30, 2014 11:17 AM
  • Hi Frank

    Thinking about useful shortcuts - is there a way to access a class of the Nutrient Type for the Main FoodComposition and DRV Nutrients (which are slightly different)?  What I am thinking about is that there may be instances where Combo or ListBoxes may need to be filled with:

    FoodComposition.NutrientType()

    Energy
    Protein
    Fat
    Saturated fat
    Carbohydrate
    Sugar
    Sodium 
    Calcium
    Iron
    Vitamin A
    Vitamin B1
    Vitamin B2
    Niacin
    Vitamin C
    Vitamin D
    Fibre


    DRV - DietaryReferenceValue.NutrientType()

    Energy
    Protein
    Sodium 
    Calcium
    Iron
    Vitamin A
    Vitamin B1
    Vitamin B2
    Niacin
    Vitamin C
    Vitamin D

    Please let me know if that short cut is built in for easy access.

    I hope that your hard drive issues are not causing too much problem.  We will be pleased to pay for a decent new hard drive.  I have my own problem - the glass panel of our Bosch oven has literally fallen out - it was bonded in with high temperature mastic.  The oven took quite a hammering over Christmas.

    Very Best Wishes for a Happy and Prosperous New Year

    Keith and Margaret


    Winchestermili

    Hi Keith,

    I *think* I might have this computer hardware issue resolved. I can't prove a negative of course, but I think so.

    *****

    I'm not following what you mean by "shortcut" though. Try to explain more please?


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 30, 2014 3:01 PM
  • Hi Frank

    To be able to fill Combo boxes and ListBoxes with the names of the nutrients, vitamins and minerals then as far as I can see that would need to be line by line.  Have you a Class (or please can we have a Class) so that the ListBoxes can be filled with a Class rather that individual AddItems.  i.e. similar to the way that the Categories ListBoxes were filled.  Two similar Classes would be needed as described above.

    Regards

    Keith


    Winchestermili

    Tuesday, December 30, 2014 6:30 PM
  • Hi Frank

    To be able to fill Combo boxes and ListBoxes with the names of the nutrients, vitamins and minerals then as far as I can see that would need to be line by line.  Have you a Class (or please can we have a Class) so that the ListBoxes can be filled with a Class rather that individual AddItems.  i.e. similar to the way that the Categories ListBoxes were filled.  Two similar Classes would be needed as described above.

    Regards

    Keith


    Winchestermili

    I was already working on some additions (for the Administrator program), so I've added those two methods in now.

    This is the latest version and the following shows a test for it:

    Private Sub Example10() Try Dim drvNutrients() As String = Nothing drvNutrients = DietaryReferenceValue.GetAllNutrientNames Dim sb As New System.Text.StringBuilder For Each s As String In drvNutrients sb.AppendLine(s) Next If sb.Length > 0 Then MessageBox.Show(sb.ToString, "DRV Nutrient List") End If sb.Length = 0 Dim fcNutrients() As String = Nothing fcNutrients = FoodComposition.GetAllNutrientNames For Each s As String In fcNutrients sb.AppendLine(s) Next If sb.Length > 0 Then MessageBox.Show(sb.ToString, "Food Composition Nutrient List") End If Stop Catch ex As Exception MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _ "Program Error", MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub


    *****

    Also please try the following.

    Assuming it works (it should!), it will use Windows Explorer to open the folder where it's placed the binary file. The binary file that you'll then see there will be ALL instances of ALL classes*, all in that one binary file. If you feel like it, open that binary file with Notepad or similar and have a look around:

        Private Sub Example11()
    
            Try
                Utilites.SaveNutritionDataToBinaryFile(drvList, _
                                                       catList, _
                                                       lnList, _
                                                       foodCompositionList, _
                                                       uomList)
    
                If My.Computer.FileSystem.FileExists(Utilites.NutritionDataBinaryFilePath) Then
                    Process.Start(GetDirectoryName(Utilites.NutritionDataBinaryFilePath))
                End If
    
            Catch ex As Exception
                MessageBox.Show("An error occurred:" & vbCrLf & vbCrLf & ex.Message, _
                                "Program Error", MessageBoxButtons.OK, _
                                MessageBoxIcon.Warning)
            End Try
    
        End Sub

    * It does not contain the classes which use instance members only like, for example, "Nutrient". It only saves the collections of classes needed to reconstitute your lists whenever you make a change. This will be used ONLY in the Admin program - when changes are made.

    *****

    Have a look at the class diagram to date. I set it up to [try to] show how the associations are all interlinked. Per class which supports a collection, you'll also notice that there's a new method named "GetInstanceDeepClone".

    Try that and let me know your thoughts please. :)


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 30, 2014 7:17 PM
  • Hi Frank

    Very impressive speed that you manage to return these requests.  Both the "GetAllNutrientsName" return a useful string and I will try loading the values into a ListBox. 

    As with the "CategoryNames", when you get a minute, please can you arrange for a "Natural" order for both the "GetAllNutrientsName" lists?

    Example10 successfully opens the C:\ProgramData\Nutrients folder and saves a 610K Binary file (I am using Win8).  Thanks for the accurate notes about what your intentions are.

    I have spent time looking at the Class Diagram and it really makes sense in the way things are progressing.

    Many thanks

    Keith


    Winchestermili

    Tuesday, December 30, 2014 8:19 PM
  • ...and I will try loading the values into a ListBox.

    When you do that, but sure to use .AddRange to make it much easier. For example:

    ListBox1.Items.AddRange(DietaryReferenceValue.GetAllNutrientNames)

    As with the "CategoryNames", when you get a minute, please can you arrange for a "Natural" order for both the "GetAllNutrientsName" lists?

    Can you show me the way that you want it to appear then? Those are actually values of enums so that's not as easily done, but I can manage it. I just need to know the order you want.

    Enums are very useful but at a certain point they're "in the way" for things like this. I'll come up with something though.

    You can think of an enum (enumerator) as "an integer with a name associated with it". Like I said, they can come in quite handy but they can also be easily 'overused' and I've learned my lesson on that the hard way! ;-)


    Winchestermili



    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 30, 2014 8:29 PM
  • Hi Frank

    I looked closely at your method for the Food Categories and got the two "GetAllNutrientNames"  lists:

    Worked fine the first time and these methods will be very handy.  Ideally we would like the order that was given above in todays earlier post - the two long Nutrients lists (please scroll up).  Apologies for messing with the order.  We do not need the "retinol" nor the "carotene".

    Looking good

    Regards

    Keith


    Winchestermili

    Tuesday, December 30, 2014 8:39 PM
  • Hi Frank

    I looked closely at the method that you used to load the "Food Categories" into the list boxes.  The two GetAllNutrientNames loaded very easily using the same AddRange method.

    Please can you use the list order in todays earlier post for both the "GetAllNutrientNames" - please scroll up to the two long lists of NutreintTypes.  Please exclude "retinol" and "carotene".  Apologies for messing with the order.  Many thanks

    Looking Good

    Keith


    Winchestermili

    Tuesday, December 30, 2014 8:46 PM

  • Please can you use the list order in todays earlier post for both the "GetAllNutrientNames" - please scroll up to the two long lists of NutreintTypes.  Please exclude "retinol" and "carotene".  Apologies for messing with the order.  Many thanks

    Looking Good

    Keith


    Winchestermili

    Ah ok, I guess I was looking more to what you wanted and missing the fact that you showed how they're to be.

    *****

    How often will those nutrient names change? That is, will more be added or maybe some be removed and if so, how often would that occur?

    If it's not all *that* often then I'll take the easy way out (I'll show you what I mean) but it won't lend to modification without changing it and recompiling.


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 30, 2014 8:50 PM
  • Keith,

    How about try this one.

    I haven't tested it but I think it'll do what you want regarding the sort order.


    Still lost in code, just at a little higher level.

    :-)

    Tuesday, December 30, 2014 9:05 PM
  • Hi Frank

    Thank you - the DirectCast works exactly as expected.  We do not expect that the lists will vary.  If either do then it will be the DRV list because we have not received the new government guidelines for the DRV Groups.  No doubt a change will be made just to say that this government has "improved" over the last government - so, unfortunately, we might have to insert one or two.

    Many thanks

    Keith


    Winchestermili

    Wednesday, December 31, 2014 9:42 AM
  • Hi Frank

    Thank you - the DirectCast works exactly as expected.  We do not expect that the lists will vary.  If either do then it will be the DRV list because we have not received the new government guidelines for the DRV Groups.  No doubt a change will be made just to say that this government has "improved" over the last government - so, unfortunately, we might have to insert one or two.

    Many thanks

    Keith


    Winchestermili


    I'll continue working on it later today then.

    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 31, 2014 12:07 PM
  • Keith,

    I wanted to show you where I am with this in case you want me to change it.

    I started to put the program together using my Dev controls, but then I'd be the only one who could modify it (I'd have to send you the program installer, not the code). If you're interested in going with Dev Express controls, I'll explain more - but be forewarned: They're not cheap!

    That said though, for your user's program you could do everything in it. No spawning out to Word or Excel - everything you can do in those, you could do in with the Dev products.

    *****

    Given that I want you to have the ability to change things any way you choose to, I've instead set this up using the out-of-the-box standard controls. So far the UI looks like this:

    You can see that I have the "sections (classes which are in the lists)" as tab pages.

    Currently I'm tackling the first one: Food Composition. No doubt it'll be the big section to work on, probably the biggest of them, actually.

    With no data yet there's not much to see. The menu bar at the top will get you started:

    The top-most item shown there will connect you to my website (the same as the test program does) and download the data.

    Once that's done, it will then save the data to a binary file like I showed yesterday, and from that point forward (including subsequent times that you run the program), that menu bar item will be disabled.

    The button to add a new food will always be enabled, but the other two buttons that you see there will only be enabled when you've selected a food in the ListBox:

    When you select an item, the read-only TextBox to the right will show the properties (it uses the .ToString method).

    I'm only starting to work on the "Add A New Food" one but it will use the same form for for modification. Have a look at it and let me know your thoughts please?


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Wednesday, December 31, 2014 6:11 PM ...typos
    Wednesday, December 31, 2014 5:58 PM
  • Hi Frank

    We are both slightly lost for words.  The Interface is exactly what is needed and amazingly well presented.  You seem to have completely understood the way we wished to enter the data.  We have no comments, it looks superb. 

    Very Happy New Year

    Keith and Margaret


    Winchestermili

    Wednesday, December 31, 2014 7:35 PM
  • Hi Frank

    We are both slightly lost for words.  The Interface is exactly what is needed and amazingly well presented.  You seem to have completely understood the way we wished to enter the data.  We have no comments, it looks superb. 

    Very Happy New Year

    Keith and Margaret


    Winchestermili

    I've never heard of a vitamin named "fibre" (yea, a typo if you look again ;-) ... I'll change it).

    Ok, I'll continue on with it. This won't be a fast process but "to do it right", I need time to work on it and of course test it, then I'll ask you to "break it". I won't be amazed if you succeed! ;-)

    *****

    Happy New Year to you (plural) also! :)


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 31, 2014 7:40 PM
  • Keith,

    I have some questions about this. First, the "minimum required".

    As far as the actual minimum requirements go, a unique food name and a valid reference to a food category is all that's required. Everything else will work with the defaults (all of the nutrient values are assumed to be 0 unless there's a value in those TextBoxes and the LabelNote reference will be assumed to be the first one which is a blank string):

    Are there other requirements though? I realize that only you two will be adding them but if you 'think outside the box', what would you require to be the bare minimum for adding a new FoodComposition entry?

    *****

    Validation

    In order to ensure that the food name of a new (or modified, when I get there) entry isn't a duplicate, whenever the user leaves that TextBox, the program will perform a validation test:

    Do you want this done differently and/or worded differently?

    As for the nutrient values, two validation tests are performed:

    Are you ok with these so far?


    Still lost in code, just at a little higher level.

    :-)

    Wednesday, December 31, 2014 11:04 PM
  • Hi Frank
    Good morning and a Very Happy 2015 to You.

    Please leave "fibre" as the "correct" spelling "fibre".  I do not want to "entRE" a cultural issue but at the "centRE" of the matter the the program will be written in old fashioned English.   I must admit that I was impressed when you used "savOUry rice" but we relaxed into "donut" rather than "doughnut".   I appreciate that this might be a "grEy" area but I hope it is taken in the best of "humOUr". So our "favOUrite" spelling is "fibre" please. 

    Regarding your question "Are there other requirements though?"
    1.  The Food name used in the source data is very long and it was simplified in many cases.  However, we would like to have the option to have both the M&W full name and the M&W "number" (actually a text reference) so that we can cross reference back to the source data.  That would mean a second string under "Chemistry Data Reference" called "Chemistry Data Name".  Default to a null string.
    2.  The total number of foods will grow to about 1000; but we cannot see it ever growing to more than 1500.  We might make the data "user configurable"  where Admin rights are provided to show or hide certain foods.
    3.  We would like the option to add two more "Food Categories".  It is unlikely but it would give considerable flexibility; but naturally we do not know where they will appear in the list of categories.  If they are at the end after "Miscellaneous" that would be fine.  We would need to deal with the way those additional groups are presented from within the program.
    4.  As a safety net we would like two more "Nutrients" IF POSSIBLE.  Just under "Value of Fibre" and before "Typical Portion 1".  Default to a zero value please.

    The above are the ideal cases and caters for possible changes.  If the above is too onerous then please say so.

    Best Regards
    Keith and Margaret


    Winchestermili

    Thursday, January 1, 2015 10:54 AM
  • Keith,

    While waiting on your reply about the minimum requirements, I wanted to proceed as far as I could - obviously there's a lot to do.

    I've continued with the "Add A New Food" and that's when I discovered something interesting:

    If you recall, you wanted everything sorted in natural order - obviously adding something then adds it to end and that's the natural order. This gave me pause so I've added some things now:

    As you can see there, I've added a way to sort the list with the combo that's at the top, I've added a "find" TextBox, and I've added a way to change the natural order - which is what started me down this road earlier today.

    You can sort the list in any of the three ways that we discussed a few weeks ago:

    If an item is selected (it's set to allow only one selection, not multiple items), if you change the sort order it will maintain being selected as shown following:

    The Listbox will automatically scroll to wherever it needs to be to ensure that the selected item is visible.

    To show how the find works, I'll show you following. Note please that it's looking for the term that starts with (not contains) the text that you type. As an example, I'll look for a food that starts with the name "cheese":

    As for moving an item in the list (and if you click the button to commit the changes it will literally change them permanently), I'll show you following. Those buttons will only be enabled if the sort order is "natural":

    The "Undo" button doesn't take you back one step, it takes you ALL the way back - what it's doing is reloading the list from scratch so obviously it takes you all the way back as though you'd not moved anything.

    When you get back please let me know your thoughts on all of this.


    Still lost in code, just at a little higher level.

    :-)

    Thursday, January 1, 2015 6:42 PM
  • Hi Frank
    Good morning and a Very Happy 2015 to You.

    Please leave "fibre" as the "correct" spelling "fibre".  I do not want to "entRE" a cultural issue but at the "centRE" of the matter the the program will be written in old fashioned English.   I must admit that I was impressed when you used "savOUry rice" but we relaxed into "donut" rather than "doughnut".   I appreciate that this might be a "grEy" area but I hope it is taken in the best of "humOUr". So our "favOUrite" spelling is "fibre" please. 

    Regarding your question "Are there other requirements though?"
    1.  The Food name used in the source data is very long and it was simplified in many cases.  However, we would like to have the option to have both the M&W full name and the M&W "number" (actually a text reference) so that we can cross reference back to the source data.  That would mean a second string under "Chemistry Data Reference" called "Chemistry Data Name".  Default to a null string.
    2.  The total number of foods will grow to about 1000; but we cannot see it ever growing to more than 1500.  We might make the data "user configurable"  where Admin rights are provided to show or hide certain foods.
    3.  We would like the option to add two more "Food Categories".  It is unlikely but it would give considerable flexibility; but naturally we do not know where they will appear in the list of categories.  If they are at the end after "Miscellaneous" that would be fine.  We would need to deal with the way those additional groups are presented from within the program.
    4.  As a safety net we would like two more "Nutrients" IF POSSIBLE.  Just under "Value of Fibre" and before "Typical Portion 1".  Default to a zero value please.

    The above are the ideal cases and caters for possible changes.  If the above is too onerous then please say so.

    Best Regards
    Keith and Margaret


    Winchestermili

    I didn't realize that you'd replied - once again this didn't show up and I didn't get an e-mail. I'll try to address these things:

    First, where did I not use the word "fibre"? I thought I had throughout. Blame Noah Webster, not me! He actually wanted many more changes but most of them were rejected. At any rate, please let me know where I misspelled it and I'll change it.

    I'm not 100% following what you mean about the Chemistry reference. Currently it's a string - tell me what you want from there though?

    As for the additional nutrients, they'll need a name. Those aren't dynamic - it's coded in (and I can't see how to make them dynamic without rethinking the whole thing). What nutrient names do you want added?

    The other things you mention in this will be ones you can add/delete/modify at will. There's no limit for the number of foods, food categories, or DRV groups that you can have - provided the names of each of those are unique.


    Still lost in code, just at a little higher level.

    :-)

    Thursday, January 1, 2015 6:58 PM
  • This forum just ate my last message!

    Maybe posting this will resurrect it...


    Still lost in code, just at a little higher level.

    :-)

    Thursday, January 1, 2015 7:02 PM
  • Hi Frank

    The comment about "fibre" was in response to your comments about fibre in your post dated Wednesday, December 31, 2014 7:40 PM (which must be 1:40pm your time).  You wrote that you had not heard of a nutrient called "fibre" and you thought that there was a typo.

    The three options for the choice of order gives an ideal solution.  We completely follow what you are proposing and we think it is superb.  I have used your find a foodname in a similar dynamic search as a textbox and ListBox using:

    From fc As NutritionData.FoodComposition In foodCompositionList Where fc.FoodName.ToLower.Contains(tempstr)
    For i As Integer = 0 To qry1.Count - 1
        ListBox3.Items.Add(qry1(i).FoodName)
    Next (i)

    With so many foods to be checked in the database your "Find" procedure at the bottom of the UI will be very useful.

    A string is good for the Chemistry Data Reference.  It will be used as a reference back to the original data.  There are often several sets of data for a food product, for example fish fillets weighed with skin and bone or simply the edible portion of a fish fillet.  In order to simplify this for children, Margaret has selected the most appropriate data set.  When foods are re-analysed,  (for example pigs have been bred to produce leaner meat and new data is published) Margaret needs to cross check to make sure the correct data is used.  She will also use this for further annotation, for example the a reference to the update publication used.

    Please name the additional Nutrients 'Cholesterol' and 'Zinc' - these are the two most likely to be added.

    Thanks for the reassurance regarding number of foods, categories and DRV groups.  It is good to have flexibility over these.

    Best regards

    Keith and Margaret


    Winchestermili

    Thursday, January 1, 2015 10:08 PM
  • At least this message came through!

    The comment about "fibre" was in response to your comments about fibre in your post dated Wednesday, December 31, 2014 7:40 PM (which must be 1:40pm your time). You wrote that you had not heard of a nutrient called "fibre" and you thought that there was a typo.

    You misunderstood then.

    I was referring to my typo in the label as as shown here. If you'll notice, one of the labels for one of the TextBoxes shows "Value For Vitamin Fibre". Obviously there's no vitamin named Fibre! That's what I meant.

    A string is good for the Chemistry Data Reference. It will be used as a reference back to the original data. There are often several sets of data for a food product, for example fish fillets weighed with skin and bone or simply the edible portion of a fish fillet. In order to simplify this for children, Margaret has selected the most appropriate data set. When foods are re-analysed, (for example pigs have been bred to produce leaner meat and new data is published) Margaret needs to cross check to make sure the correct data is used. She will also use this for further annotation, for example the a reference to the update publication used.

    I'm still not clear on what you want me to change?

    Please name the additional Nutrients 'Cholesterol' and 'Zinc' - these are the two most likely to be added.

    I'll add these which will set me back a bit because I'll need to go back to my "Initial Data" to do that - write the XML then make sure it will read the XML. Before I do though, are these a part of "FoodComposition" or a part of "DieteryReferenceValue" or both?

    *****

    I don't think you ever did answer my question about minimum requirements. Are you ok with what I suggested being a unique (distinct) food name and a valid food category reference, then using the defaults for everything else?


    Still lost in code, just at a little higher level.

    :-)


    • Edited by Frank L. Smith Thursday, January 1, 2015 10:26 PM ...formatting
    Thursday, January 1, 2015 10:21 PM
  • Hi Frank

    Please add an additional field under the Chemistry Data Reference with the title 'Reference Number' - the data source gives each food a unique number (and this sometimes changes when data is updated).   These fields may be left blank for some foods. 

    Zinc and Cholesterol will have data for both 'Food Composition and Dietary Reference Values.

    Minimum requirements are as you have understood - the food name and category reference.  Defaults of 0 for numeric data (the nutrition data) and blank for text in the four bottom boxes. 

    Thanks

    Keith and Margaret


    Winchestermili

    Thursday, January 1, 2015 11:11 PM
  • Please add an additional field under the Chemistry Data Reference with the title 'Reference Number' - the data source gives each food a unique number (and this sometimes changes when data is updated).   These fields may be left blank for some foods.

    Is "ReferenceNumber" to be an actual number (and if so, what type), or a string?

    If it's to be a numeric type, it can't be null - all numeric types are value types which will default to 0.

    Should I change the name of the existing one (which is a string)?


    Still lost in code, just at a little higher level.

    :-)

    Thursday, January 1, 2015 11:16 PM
  • Let me somewhat correct myself with what I just said about numeric types not being able to be null.

    While my statement, as said, is true, I could use a Nullable<T> where the type is, for example integer.

    That will, by default, be null (nothing), but that leads to issues with writing out the XML so - it could get quite involved here! ;-)

    I just want to be sure that I understand the intentions.


    Still lost in code, just at a little higher level.

    :-)

    Thursday, January 1, 2015 11:33 PM
  • Frank Thank you for your post. We have been in conversation for some time now and perhaps the distance has prevented full appreciation of what we want to achieve. We are very aware of the time and patience that you have taken in dealing with this but now, after one month we need to bring this matter to a conclusion. We are sorry that we have been unable to explain ourselves and our objectives but New Year New Project. Thank you for all your time and effort. Keith and Margaret

    Winchestermili

    Friday, January 2, 2015 12:14 AM
  • Frank Thank you for your post. We have been in conversation for some time now and perhaps the distance has prevented full appreciation of what we want to achieve. We are very aware of the time and patience that you have taken in dealing with this but now, after one month we need to bring this matter to a conclusion. We are sorry that we have been unable to explain ourselves and our objectives but New Year New Project. Thank you for all your time and effort. Keith and Margaret

    Winchestermili

    I think I just got fired.

    So you just want to end it here then? At the very least, please close this thread by marking one or more posts as the answer please.


    Still lost in code, just at a little higher level.

    :-)

    Friday, January 2, 2015 12:48 AM
  • Keith,

    This is the project folder.

    I think you're being grossly unfair - but that's up to you. Let me know if you want to continue on this at a later point...


    Still lost in code, just at a little higher level.

    :-)

    Friday, January 2, 2015 1:00 AM