VB.Net - JSON Currency Converter
Overview
This is a currency converter application, that gets rates from the online daily updated JSON file at http://www.floatrates.com/daily/eur.json
The raw JSON data is deserialized to a Dictionary(Of String, currencyDetails). The Dictionary stores all of the details about each currency, including an Overridden ToString method which returns the three character currency code, a hyphen, and the official currency name. Two Arrays derived from the Dictionary serve as DataSources for the From and To ComboBoxes. The ComboBoxes display the currencies and are sorted ASC.
In Form_Load after the JSON is deserialized, a Table Class containing a Shared Array is called to create the Array used to store all of the currency rates used by the converter. This is also arranged ASC, so the correct Array indices will be the From and To ComboBox SelectedIndices, and converting any of 148 currencies to any other of the 148 currencies is easily achieved.
This example uses just one Class for the currencyDetails obtained from the JSON, and another Class to host the Shared Array. Other than setting up the DataSources, creating the Table, and converting the currencies, there's just several GUI handlers for ensuring the results Label is kept up to date, and there's some painting in the Form_Paint event.
SystemColors are used in the Form to create a contrasting appearance, which should work well, however, your current color scheme is set up.
The Code
The Form
The code here is annotated, explaining step by step...
Imports System.Net
Imports Newtonsoft.Json
Public Class Form1
Dim codes() As String
Dim rates() As Decimal
Dim inverse() As Decimal
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim client As New WebClient
Dim rawResponseString As String = client.DownloadString("http://www.floatrates.com/daily/eur.json")
'This is the Dictionary that, along with the table Array,
'creates the core of this application.
'The base currency for the rates obtained from the JSON is the Euro
Dim jsonResulttodict As Dictionary(Of String, currencyDetails) = JsonConvert.DeserializeObject(Of Dictionary(Of String, currencyDetails))(rawResponseString)
jsonResulttodict.Add("eur", New currencyDetails("EUR", "Euro", "1", jsonResulttodict("gbp").dateString, "1"))
'These are all used simply for creation of the 2D table Array
'that is used throughout this application
codes = jsonResulttodict.Select(Function(kvp) kvp.Value.code).ToArray
Dim tempCodes() As String = DirectCast(codes.Clone, String())
rates = jsonResulttodict.Select(Function(kvp) kvp.Value.rate).ToArray
inverse = jsonResulttodict.Select(Function(kvp) kvp.Value.inverseRate).ToArray
Array.Sort(codes, rates)
Array.Sort(tempCodes, inverse)
Table.createArray(codes, rates, inverse)
'These have two separately created Arrays. The Arrays are identical
'but using one single Array for both ComboBoxes wouldn't allow
'the ComboBoxes to work independently of each other...
cboFrom.DataSource = jsonResulttodict.Select(Function(kvp) kvp.Value).OrderBy(Function(cd) cd.ToString).ToArray
cboTo.DataSource = jsonResulttodict.Select(Function(kvp) kvp.Value).OrderBy(Function(cd) cd.ToString).ToArray
'To ensure conversion takes place ASAP
For Each ctrl As Control In Me.Controls
If ctrl Is nudAmount Then Continue For
AddHandler ctrl.Click, AddressOf ctrls_Click
Next
AddHandler Me.Click, AddressOf ctrls_Click
End Sub
Private Sub ctrls_Click(sender As Object, e As EventArgs)
If sender Is Me Then lblResults.Select()
DirectCast(sender, Control).Select()
End Sub
Private Sub inputs_ValuesChanged(sender As Object, e As EventArgs) Handles nudAmount.ValueChanged, cboFrom.SelectedIndexChanged, cboTo.SelectedIndexChanged,
nudAmount.Leave, cboFrom.Leave, cboTo.Leave
If cboFrom.SelectedIndex < 0 Or cboTo.SelectedIndex < 0 Or nudAmount.Value = 0D Then lblResults.Text = "" : Return
lblResults.Text = nudAmount.Value.ToString & " " & cboFrom.Text.Substring(0, 3) & Environment.NewLine &
"equals... " & Environment.NewLine & (Table.getValueAt(cboFrom.SelectedIndex, cboTo.SelectedIndex) * nudAmount.Value).ToString & " " & cboTo.Text.Substring(0, 3) &
Environment.NewLine & Environment.NewLine & "Currency rates updated - " & DirectCast(cboFrom.SelectedItem, currencyDetails).dateString
End Sub
'This just paints some contrasting borders, in
'keeping with the systemcolors contrasting theme
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
ControlPaint.DrawBorder(e.Graphics, New Rectangle(nudAmount.Left - 2, nudAmount.Top - 2, nudAmount.Width + 4, nudAmount.Height + 4), SystemColors.Control, ButtonBorderStyle.Solid)
ControlPaint.DrawBorder(e.Graphics, New Rectangle(cboFrom.Left - 2, cboFrom.Top - 2, cboFrom.Width + 4, cboFrom.Height + 4), SystemColors.Control, ButtonBorderStyle.Solid)
ControlPaint.DrawBorder(e.Graphics, New Rectangle(cboTo.Left - 2, cboTo.Top - 2, cboTo.Width + 4, cboTo.Height + 4), SystemColors.Control, ButtonBorderStyle.Solid)
ControlPaint.DrawBorder(e.Graphics, New Rectangle(lblResults.Left - 3, lblResults.Top - 3, lblResults.Width + 6, lblResults.Height + 6), SystemColors.Control, ButtonBorderStyle.Solid)
End Sub
End Class
The Table Class
Public Class Table
Private Shared values()() As Decimal
Public Shared Sub createArray(codes() As String, rates() As Decimal, inverse() As Decimal)
'When complete, each cell of the table contains the value
'for one 'From' unit's value in 'To' units
ReDim values(codes.GetUpperBound(0))
For x As Integer = 0 To codes.Length - 1
ReDim values(x)(codes.GetUpperBound(0))
values(x)(0) = rates(x)
values(0)(x) = inverse(x)
values(x)(x) = 1D
Next x
For c As Integer = 1 To codes.Length - 1
For r As Integer = 1 To codes.Length - 1
values(r)(c) = CDec(values(0)(c) / values(0)(r))
Next
Next
End Sub
Public Shared Function getValueAt(c As Integer, r As Integer) As Decimal
Return values(r)(c)
End Function
End Class
The currencyDetails Class
Public Class currencyDetails
Public Property code As String
Public Property name As String
Public Property rate As Decimal
Public Property dateString As String
Public Property inverseRate As Decimal
Public Sub New(code As String, name As String, rate As String, [date] As String, inverseRate As String)
Me.code = code
Me.name = name
Me.rate = CDec(rate)
Me.dateString = [date]
Me.inverseRate = CDec(inverseRate)
End Sub
Public Overrides Function ToString() As String
Return Me.code & " - " & Me.name
End Function
End Class
Conclusion
The NuGet package Newtonsoft.Json makes working with raw JSON a simple task. It's easy to deserialize the JSON string into a Dictionary (in this case Of String, currencyDetails).
Working with currency rates that are updated every day as raw JSON can make creating a simple currency converter an easy task.