C# - Lambda Periodic Table Searcher
Overview
This article is intended to show two programming lessons for beginner programmers.
First, it shows how to combine object arrays, simple user-defined object classes, properties, and simple code, to create OOP (Object Oriented Programming) applications with Visual Studio.
Secondly, it shows how to use simple LINQ queries with Lambda functions, to quickly search a user-defined object array.
Arrays in VS can be arrays of primitive types (Integer, Byte, Boolean etc.), but it's possible to create an array of just about any type you can imagine. A user-defined class typically contains Properties and Public or sometimes Private Methods. In the case of the example programs there are two user-defined classes - ElementDetails, which contains (from each element) the AtomicNumber, the Symbol, the Element (name), the [Type] (the Element's group), and finally the Image Property, which actually returns a dynamic Bitmap created on the fly in the Property Getter. The [Type] Property could have been a String representing the name of the group, but it was advantageous to store two Properties related to the Group - the name, and a color. So, the return type of the Type Property is ElementType, which is the second of the core classes used.
LINQ combined with Lambda gives great results from minimal code. It is possible to query the user-defined array on any of the Properties to retrieve either one element or a group of elements.
The searchForm code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Lambda_Periodic_Table_Searcher_cs.core;
using Lambda_Periodic_Table_Searcher_cs.gui;
namespace Lambda_Periodic_Table_Searcher_cs
{
public partial class searchForm : Form
{
ElementType[] types = { new ElementType("Alkali metal", 255, 101, 101),
new ElementType("Alkaline earth metal", 255, 222, 174),
new ElementType("Lanthanide", 255, 188, 253),
new ElementType("Actinide", 255, 150, 201),
new ElementType("Transition metal", 255, 190, 191),
new ElementType("Post-transition metal", 203, 203, 203),
new ElementType("Metalloid", 203, 204, 154),
new ElementType("Polyatomic nonmetal", 159, 255, 196),
new ElementType("Diatomic nonmetal", 230, 255, 148),
new ElementType("Noble gas", 190, 255, 255),
new ElementType("Unknown chemical properties", 231, 231, 231) };
ElementDetails[] elements = new ElementDetails[118];
bool ignore = false;
public searchForm()
{
InitializeComponent();
string [] lines = Properties.Resources.elements.Split( new string[] { Environment.NewLine }, StringSplitOptions.None);
for (int x = 0; x <= 117; x++)
{
elements[x] = new ElementDetails(types, lines[x].Split('|'));
}
}
private void NumericUpDown1_ValueChanged(object sender, EventArgs e)
{
updateFields(0, elements.FirstOrDefault(el => el.AtomicNumber() == ( int )NumericUpDown1.Value));
}
private void TextBox1_TextChanged(object sender, EventArgs e)
{
updateFields(1, elements.FirstOrDefault(el => el.Symbol().Equals(TextBox1.Text)));
}
private void TextBox2_TextChanged(object sender, EventArgs e)
{
updateFields(2, elements.FirstOrDefault(el => el.Element().Equals(TextBox2.Text)));
}
private void Button1_Click(object sender, EventArgs e)
{
if (Button1.Text != "")
{
ElementDetails[] group = elements.Where(el => el.Group().Name().Equals(Button1.Text)).ToArray();
listForm frm = new listForm(Button1.Text, group);
frm.ShowDialog();
}
}
private void updateFields(int exclude, ElementDetails current)
{
if (ignore)
return ;
ignore = true ;
switch (exclude)
{
case 0:
if (current != null)
{
TextBox1.Text = current.Symbol();
TextBox2.Text = current.Element();
Button1.BackColor = current.Group().Color();
Button1.Text = current.Group().Name();
}
else
{
clearFields(exclude);
}
break ;
case 1:
if (current != null)
{
NumericUpDown1.Value = current.AtomicNumber();
TextBox2.Text = current.Element();
Button1.BackColor = current.Group().Color();
Button1.Text = current.Group().Name();
}
else
{
clearFields(exclude);
}
break ;
case 2:
if (current != null)
{
NumericUpDown1.Value = current.AtomicNumber();
TextBox1.Text = current.Symbol();
Button1.BackColor = current.Group().Color();
Button1.Text = current.Group().Name();
}
else
{
clearFields(exclude);
}
break ;
}
ignore = false ;
}
private void clearFields(int exclude)
{
ignore = true ;
switch (exclude)
{
case 0:
NumericUpDown1.Value = 0;
TextBox2.Text = "" ;
Button1.BackColor = SystemColors.Control;
Button1.Text = "" ;
break ;
case 1:
NumericUpDown1.Value = 0;
TextBox2.Text = "" ;
Button1.BackColor = SystemColors.Control;
Button1.Text = "" ;
break ;
case 2:
NumericUpDown1.Value = 0;
TextBox1.Text = "" ;
Button1.BackColor = SystemColors.Control;
Button1.Text = "" ;
break ;
}
ignore = false ;
}
}
}
The ElementDetails Class code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using Lambda_Periodic_Table_Searcher_cs.gui;
namespace Lambda_Periodic_Table_Searcher_cs.core
{
public class ElementDetails
{
private int _atomicNumber;
private string _symbol;
private string _element;
private ElementType _type;
public int AtomicNumber()
{
return this._atomicNumber;
}
public string Symbol()
{
return this._symbol;
}
public string Element()
{
return this._element;
}
public ElementType Group()
{
return this._type;
}
public Bitmap Image()
{
Bitmap img = new Bitmap(120, 80);
Graphics g = Graphics.FromImage(img);
g.Clear( this .Group().Color());
g.DrawRectangle(Pens.Black, 0, 0, 119, 79);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
Font smallFont = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Regular);
g.DrawString( this .AtomicNumber().ToString(), new Font(smallFont.FontFamily, 12, FontStyle.Bold), Brushes.Black, new Rectangle(0, 0, 120, 25), sf);
g.DrawString( this .Symbol(), new Font(smallFont.FontFamily, 12, FontStyle.Bold), Brushes.Black, new Rectangle(0, 27, 120, 25), sf);
g.DrawString( this .Element(), smallFont, Brushes.Black, new Rectangle(0, 52, 120, 25), sf);
return img;
}
public ElementDetails(ElementType[] elementTypes, string[] fields)
{
this ._atomicNumber = Convert.ToInt32(fields[0].Trim());
this ._symbol = fields[1].Trim();
this ._element = fields[2].Trim();
this ._type = elementTypes.Where(x => fields[3].Trim().Equals(x.Name())).First();
}
}
}
Conclusion
This article teaches good programming practice through encapsulation, and composition, which are essential elements of good OOP Programming. Using Class objects, arrays and LINQ it's easy to create concise and effective programs in minutes, and your code will be readable industry standard code.
Other Resources
Download here... VB.Net / C#
See Also