|
Example Application: Solo Music Store |
|
|
This application applies the concept of implementing a
collection class using the techniques of the .NET Framework. It is a
fictitious company that sells musical instruments such as keyboards, pianos,
drums, and related accessories (books, software, hardware, etc).
|
.
Practical
Learning: Creating the Application
|
|
- Start Microsoft Visual Studio
- Create a new Windows Application
named SoloMusicStore1
- To save the project, on the Standard toolbar, click the Save All
button
- Accept all options and click Save
- To create a dialog box, on the main menu, click Project -> Add
Windows Form...
- Set the name to ItemCategory and click Add
- Design the form as follows:
|
Control |
Text |
Name |
Other Properties |
Label |
&Category: |
|
|
TextBox |
|
txtCategory |
Modifiers: Public |
Button |
OK |
btnOK |
DialogResult: OK |
Button |
Cancel |
btnCancel |
DialogResult: Cancel |
|
Form Property |
Value |
FormBorderStyle |
FixedDialog |
Text |
Category Editor |
StartPosition |
CenterScreen |
AcceptButton |
btnOK |
CancelButton |
btnCancel |
MaximizeBox |
False |
MinimizeBox |
False |
ShowInTaskbar |
False |
- To create a dialog box, on the main menu, click Project -> Add
Windows Form...
- Set the name to ItemType and click Add
- Design the form as follows:
|
Control |
Text |
Name |
Other Properties |
Label |
&Item Type: |
|
|
TextBox |
|
txtItemType |
Modifiers: Public |
Button |
OK |
btnOK |
DialogResult: OK |
Button |
Cancel |
btnCancel |
DialogResult: Cancel |
|
Form Property |
Value |
FormBorderStyle |
FixedDialog |
Text |
Type Editor |
StartPosition |
CenterScreen |
AcceptButton |
btnOK |
CancelButton |
btnCancel |
MaximizeBox |
False |
MinimizeBox |
False |
ShowInTaskbar |
False |
- To create a dialog box, in the Solution Explorer, right-click
SoloMusic1 -> Add -> Windows Form...
- Set the name to ItemEditor and click Add
- Design the form as follows:
|
Control |
Text |
Name |
Other Properties |
Label |
&Item #: |
|
|
TextBox |
|
txtItemNumber |
|
Label |
&Category: |
|
|
ComboBox |
|
cbxCategories |
|
Button |
New C&ategory... |
btnNewCategory |
|
Label |
&Item Type: |
|
|
ComboBox |
|
cbxItemTypes |
|
Button |
New &Item Type... |
btnNewItemType |
|
Label |
Item &Name: |
|
|
TextBox |
|
txtItemName |
|
Label |
&Unit Price: |
|
|
TextBox |
0.00 |
txtUnitPrice |
TextAlign: Right |
Button |
Picture... |
btnPicture |
|
TextBox |
|
txtPicturePath |
|
PictureBox |
|
pbxPicturePath |
SizeMode: Zoom |
Button |
Create |
btnCreate |
|
Button |
Close |
btnClose |
DialogResult: Cancel |
OpenFileDialog |
(Name): dlgOpen Title:
Select Item Picture DefaultExt: jpg Filter: JPEG
Files (*.jpg,*.jpeg)|*.jpg|GIF Files
(*.gif)|*.gif|Bitmap Files (*.bmp)|*.bmp|PNG Files
(*.png)|*.png |
|
Form Property |
Value |
FormBorderStyle |
FixedDialog |
Text |
Musical Instrument Store - Item Editor |
StartPosition |
CenterScreen |
MaximizeBox |
False |
MinimizeBox |
False |
ShowInTaskbar |
False |
- Double-click the New Category button and implement it as follows:
private void btnNewCategory_Click(object sender, EventArgs e)
{
var editor = new ItemCategory();
if (editor.ShowDialog() == DialogResult.OK)
{
if (editor.txtCategory.Text.Length > 0)
{
var NewCategory = editor.txtCategory.Text;
// Make sure the category is not yet in the list
if (cbxCategories.Items.Contains(NewCategory))
MessageBox.Show(NewCategory + " is already in the list");
else
{
// Since this is a new category, add it to the combox box
cbxCategories.Items.Add(NewCategory);
// Just in case the user wanted to use this new category
// select it
cbxCategories.Text = NewCategory;
}
}
}
}
- Return to the Item Editor dialog box and double-click the New Item
Type button
- Implement the event as follows:
private void btnNewItemType_Click(object sender, EventArgs e)
{
var editor = new ItemType();
if (editor.ShowDialog() == DialogResult.OK)
{
if (editor.txtItemType.Text.Length > 0)
{
string NewType = editor.txtItemType.Text;
// Make sure the type is not yet in the list
if (cbxTypes.Items.Contains(NewType))
MessageBox.Show("The list already contains " +
NewType);
else
{
cbxTypes.Items.Add(NewType);
cbxTypes.Text = NewType;
}
}
}
}
- Return to the Item Editor dialog box and double-click the Picture
button
- Implement the event as follows:
private void btnPicture_Click(object sender, EventArgs e)
{
if (dlgPicture.ShowDialog() == DialogResult.OK)
{
txtPicturePath.Text = dlgPicture.FileName;
pbxStoreItem.Image = Image.FromFile(txtPicturePath.Text);
}
}
- In the Solution Explorer, right-click Form1.cs and click Rename
- Type MusicStore.cs and press Enter twice (to display the
form)
- Design the form as follows:
|
Control |
Text |
Name |
Other Properties |
Label |
|
Item Category: |
|
|
ComboBox |
|
|
cbxCategories |
|
Label |
|
Items Type: |
|
|
ComboBox |
|
|
cbxTypes |
|
Label |
|
Available Items |
|
|
Button |
|
New Store Item... |
btnNewStoreItem |
|
ListView |
|
|
lvwStoreItems |
View: Details FullRowSelect: True
GridLines: True |
Columns |
(Name) |
Text |
TextAlign |
Width |
colItemNumber |
Item # |
|
|
colItemName |
Item Name/Description |
|
320 |
colUnitPrice |
Unit Price |
Right |
|
|
PictureBox |
|
|
pbxStoreItem |
SizeMode: Zoom |
Label |
|
Selected Items |
|
|
DataGridView |
|
Item # |
|
|
Label |
|
Description |
|
|
Columns |
(Name) |
HeaderText |
Width |
ReadOnly |
dgvItemNumber |
Item # |
65 |
|
dgvItemName |
Item Name/Description |
220 |
|
dgvUnitPrice |
Unit Price |
70 |
|
dgvQuantity |
Qty |
40 |
|
dgvSubTotal |
Sub-Total |
80 |
True |
|
GroupBox |
|
Order Summary |
|
|
Label |
|
Items Total: |
|
|
TextBox |
|
0.00 |
txtItemsTotal |
TextAlign: Right |
Label |
|
Tax Rate: |
|
|
TextBox |
|
7.75 |
|
TextAlign: Right |
Label |
|
% |
|
|
Label |
|
Tax Amount: |
|
|
TextBox |
|
0.00 |
txtTaxAmount |
TextAlign: Right |
Label |
|
Order Total: |
|
|
TextBox |
|
0.00 |
txtOrderTotal |
TextAlign: Right |
Button |
|
Save |
btnSave |
|
Label |
|
Receipt #: |
|
|
TextBox |
|
0.00 |
txtReceiptNumber |
|
Button |
|
&Open |
btnOpen |
|
Button |
|
New Order |
btnNewOrder |
|
Button |
|
Close |
btnClose |
|
|
- Double-click the New Store Item button
- Implement the event as follows:
private void btnNewStoreItem_Click(object sender, EventArgs e)
{
var editor = new ItemEditor();
// Create a random number to get it ready for
// the user creating a new store item
var rndNumber = new Random();
editor.txtItemNumber.Text = rndNumber.Next(100000, 999999).ToString();
editor.ShowDialog();
}
- To create a new class, in the Class View, right-click
SoloMusicStore1 -> Add -> Class...
- Set the Name to StoreItem and press Enter
- Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SoloMusic1
{
[Serializable]
public class StoreItem
{
private string nbr;
private string cat;
private string tp;
private string nm;
private double prc;
public string ItemNumber
{
get { return nbr; }
set { nbr = value; }
}
public string Category
{
get { return cat; }
set { cat = value; }
}
public string Type
{
get { return tp; }
set { tp = value; }
}
public string ItemName
{
get { return nm; }
set { nm = value; }
}
public double UnitPrice
{
get { return prc; }
set { prc = value; }
}
public virtual bool Equals(StoreItem same)
{
if( (nbr == same.nbr) &&
(cat == same.cat) &&
(tp == same.tp) &&
(nm == same.nm) &&
(prc == same.prc))
return true;
else
return false;
}
public StoreItem()
{
nbr = "000000";
cat = "Accessories";
tp = "Accessories";
nm = "Unknown";
prc = 0.00;
}
public StoreItem(string itmNumber)
{
nbr = itmNumber;
cat = "Accessories";
tp = "Accessories";
nm = "Unknown";
prc = 0.00;
}
public StoreItem(string itmNumber, string category,
string type, string name, double price)
{
nbr = itmNumber;
cat = category;
tp = type;
nm = name;
prc = price;
}
public override string ToString()
{
return string.Format("Item #:\t{0}\nCategory:\t{1}\n" +
"Item Type:\t{2}\nItem Name:\t{3}\n" +
"Unit Price:\t{4}", nbr, cat, tp, nm, prc);
}
}
}
- To create a new class, in the Class View, right-click SoloMusic1
-> Add -> Class...
- Set the Name to SoldItem and press Enter
- Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SoloMusic1
{
[Serializable]
public class SoldItem
{
private string nbr;
private string nm;
private double prc;
private int count;
private double total;
public string ItemNumber
{
get { return nbr; }
set { nbr = value; }
}
public string ItemName
{
get { return nm; }
set { nm = value; }
}
public double UnitPrice
{
get { return prc; }
set { prc = value; }
}
public int Quantity
{
get { return count; }
set { count = value; }
}
public double SubTotal
{
get { return total; }
set { total = value; }
}
public virtual bool Equals(SoldItem same)
{
if( (nbr == same.nbr) &&
(nm == same.nm) &&
(prc == same.prc) &&
(count == same.count) &&
(total == same.total))
return true;
else
return false;
}
public SoldItem()
{
nbr = "000000";
nm = "Unknown";
prc = 0.00;
count = 0;
total = 0.00D;
}
public SoldItem(string itmNumber, string name,
double price, int qty,
double sub)
{
nbr = itmNumber;
nm = name;
prc = price;
count = qty;
total = sub;
}
public override string ToString()
{
return string.Format("Item #:\t{0}\nItem Name:\t{1}\n" +
"Unit Price:\t{2}\nQuantity:\t{3}\nSub-Total:\t{4}",
nbr, nm, prc, count, total);
}
}
}
- Save all
Practical
Learning: Starting an IList Implementation
|
|
- To create a new class, in the Class View, right-click
SoloMusicStore1 -> Add -> Class...
- Set the Name to StoreItems and press Enter
- Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MusicStore1
{
[Serializable]
public class StoreItems<T> : IList<T>
{
}
}
- In the Code Editor, right-click IList<>, position the mouse on
Implement Interface, and click Implement Interface
- Based on issues we have already studied, change the document as
follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MusicStore1
{
[Serializable]
public class StoreItems<T> : IList<T>
{
// This field will be used to keeep a count of
// the items as they are added or removed
int counter;
// This array holds the items of the collection
private T[] objects;
// The default constructor is used to initialize the collection
public StoreItems()
{
counter = 0;
objects = new T[10];
}
// This method makes it possible to have a collection whose size can increase.
// This method checks the size of the array.
// If it is too small, its size gets increase.
private void CheckToIncreaseSize()
{
if (counter >= objects.Length)
Array.Resize<T>(ref objects, objects.Length + 5);
}
#region IList<T> Members
// This method is used to check whether the item passed as
// argument exists in the collection. If so, it returns its index
public int IndexOf(T item)
{
throw new NotImplementedException();
}
// This method can be used to insert an item at
// a certain position inside the collection
public void Insert(int index, T item)
{
throw new NotImplementedException();
}
// This method is used to delete the item positioned
// at the index passed as argument
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
// This indexed property is used to represent an item based on its index
public T this[int index]
{
// The get accessor is used to access the item at a specific index
get
{
return objects[index];
}
// The set accessor can be used to replace the item at a specific index
// or to add a new item to the end of the collection
set
{
objects[index] = value;
}
}
#endregion
#region ICollection<T> Members
// This method is used to add a new item to the collection
public void Add(T item)
{
// Find out if the array is getting too small for the next item(s)
// If it is, increase its size by 5
CheckToIncreaseSize();
// Add the item at the end
this.objects[this.counter] = item;
// Increase the current number of items
this.counter++;
}
// This methods deletes all items from the collection
public void Clear()
{
throw new NotImplementedException();
}
// This method is used to find out whether the item
// passed as argument exists in the collection
public bool Contains(T item)
{
throw new NotImplementedException();
}
// This method is used to copy the items of this collection
// to another variable passed as argument
public void CopyTo(T[] array, int arrayIndex)
{
T[] values = new T[arrayIndex];
for (int i = 0; i < counter; i++)
values[i] = objects[i];
array = values;
}
// This read-only property holds
// the total number of items in the collection
public int Count
{
get { return counter; }
}
// This property indicates whether the collection can receive new items
public bool IsReadOnly
{
get { throw new NotImplementedException(); }
}
// This method first checks the existence of the item passed
// as argument. If the item exists, the method deletes it
public bool Remove(T item)
{
throw new NotImplementedException();
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
int number = 0;
while (number < Count)
{
yield return objects[number];
number++;
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
int number = 0;
while (number < Count)
{
yield return objects[number];
number++;
}
}
#endregion
}
}
- Save the file
Practical
Learning: Adding an Item to the Collection
|
|
- In the Class View, expand SoloMusicStore1 followed by
SoloMusicStore1. Double-click ItemEditor
- In the top section of the file, add the following:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
- In the Solution Explorer, double-click ItemEditor.cs
- On the form, double-click the Create button
- Implement the event as follows:
private void btnCreate_Click(object sender, EventArgs e)
{
FileStream stmStoreItem = null;
var item = new StoreItem();
var items = new StoreItems<StoreItem>();
var bfmStoreItem = new BinaryFormatter();
// If this directory doesn't exist, create it
Directory.CreateDirectory(@"C:\Solo Music Store");
// This is the file that holds the list of items
var Filename = @"C:\Solo Music Store\StoreItems.slm";
// Create a random number that will be used to identify the item
var rnd = new Random();
txtItemNumber.Text = rnd.Next(100000, 999999).ToString();
// Make sure the user had selected a category
if (cbxCategories.Text.Length == 0)
{
MessageBox.Show("You must specify the item's category");
cbxCategories.Focus();
return;
}
// Make sure the user had selected a type
if (cbxTypes.Text.Length == 0)
{
MessageBox.Show("You must specify the item's type");
cbxTypes.Focus();
return;
}
// Make sure the user had entered a name/description
if (txtItemName.Text.Length == 0)
{
MessageBox.Show("You must enter the name (or a " +
"short description) for the item");
txtItemName.Focus();
return;
}
// Make sure the user had typed a price for the item
if (txtUnitPrice.Text.Length == 0)
{
MessageBox.Show("You must enter the price of the item");
txtUnitPrice.Focus();
return;
}
// Before saving the new item, find out if there was
// already a file that holds the list of items
// If that file exists, open it and store its items
// in our StoreItems list
if (File.Exists(Filename))
{
stmStoreItem = new FileStream(Filename,
FileMode.Open,
FileAccess.Read,
FileShare.Read);
try
{
// Retrieve the list of items from file
items = (StoreItems<StoreItem>)bfmStoreItem.Deserialize(stmStoreItem);
}
finally
{
stmStoreItem.Close();
}
}
// Create the music item
item.ItemNumber = txtItemNumber.Text;
item.Category = cbxCategories.Text;
item.Type = cbxTypes.Text;
item.ItemName = txtItemName.Text;
item.UnitPrice = double.Parse(txtUnitPrice.Text);
// Call the Add method of our collection class to add the item
items.Add(item);
// Save the list
stmStoreItem = new FileStream(Filename,
FileMode.Create,
FileAccess.Write,
FileShare.Write);
try
{
bfmStoreItem.Serialize(stmStoreItem, items);
if (txtPicturePath.Text.Length != 0)
{
FileInfo flePicture = new FileInfo(txtPicturePath.Text);
flePicture.CopyTo(@"C:\Solo Music Store\" +
txtItemNumber.Text + flePicture.Extension);
}
// After saving the item, reset the form
txtItemNumber.Text = rnd.Next(100000, 999999).ToString();
cbxCategories.Text = "";
cbxTypes.Text = "";
txtItemName.Text = "";
txtUnitPrice.Text = "0.00";
txtPicturePath.Text = "";
pbxStoreItem.Image = null;
}
finally
{
stmStoreItem.Close();
}
}
- Save the file
Practical
Learning: Identifying this Item in the Collection
|
|
- In the Solution Explorer, double-click ItemEditor.cs
- Double-click an unoccupied area of the form to generate its Load
event/li>
- Implement the event as follows:
private void ItemEditor_Load(object sender, EventArgs e)
{
// Since all values seem ready, prepare to process the item
var item = new StoreItem();
var items = new StoreItems<StoreItem>();
var bfmStoreItem = new BinaryFormatter();
// This is the file that holds the list of items
var Filename = @"C:\Solo Music Store\StoreItems.slm";
if (File.Exists(Filename))
{
var stmStoreItem = new FileStream(Filename,
FileMode.Open,
FileAccess.Read,
FileShare.Read);
try
{
// Retrieve the list of items from file
items = (StoreItems<StoreItem>)bfmStoreItem.Deserialize(stmStoreItem);
// Display the categories in the combo box
for (var i = 0; i < items.Count; i++)
{
item = (StoreItem)items[i];
if (!cbxCategories.Items.Contains(item.Category))
cbxCategories.Items.Add(item.Category);
}
// Display the items types in the combo box
for (var i = 0; i < items.Count; i++)
{
item = (StoreItem)items[i];
if (!cbxTypes.Items.Contains(item.Type))
cbxTypes.Items.Add(item.Type);
}
}
finally
{
stmStoreItem.Close();
}
}
else
{
// Create a random number that will be used
// to identify the item
var rnd = new Random();
txtItemNumber.Text = rnd.Next(100000, 999999).ToString();
// Make sure the user had selected a category
cbxCategories.Text = "";
cbxTypes.Text = "";
}
}
- Execute the application to test it
- Access the Item Editor dialog box and create a few items as follows
(let the computer create the item numbers):
Category |
Type |
Item Name |
Unit Price |
Picture |
Guitars |
Electric |
Gibson Les Paul Vintage Mahogany
Electric Guitar |
745.95 |
Picture |
Bass |
Electric 4-String |
Epiphone Thunderbird IV Bass |
325.85 |
Picture |
Keyboards |
Synthesizers |
Alesis QS8.2 88 Key Synthesizer |
825.50 |
Picture |
Guitars |
Acoustic |
Gretsch Guitars G100 Synchromatic
Archtop Acoustic Guitar |
595.95 |
Picture |
Drums |
Drum Set |
Pulse Pro 5-Piece Drum Set with
Cymbals |
395.95 |
Picture |
Keyboards |
Pianos |
Roland RD-700SX Digital Piano |
2195.00 |
|
Accessories |
Cables |
Mogami Gold AES/EBU Interconnect
Cable with Neutrik XLR |
45.85 |
|
Guitars |
Acoustic-Electric |
Ibanez V Series V70CE Dreadnought
Cutaway Acoustic-Electric Guitar |
225.50 |
|
Guitars |
Electric |
Schecter C-1 Hellraiser Electric
Guitar |
650.00 |
Picture |
Keyboards |
Synthesizers |
Roland V Synth GT Elastic Audio
Synthesizer Keyboard |
2895.50 |
Picture |
Bass |
Electric 5-String |
Fender Jazz Bass 24 V 5-String Bass
Guitar |
825.50 |
Picture |
Guitars |
Electric |
Fender Standard Stratocaster
Left-Handed Electric Guitar |
425.85 |
Picture |
- Close the forms and return to your programming environment
- In the Solution Explorer, right-click MusicStore.cs and click View
Code
- Make the following changes:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace SoloMusic1
{
public partial class MusicStore : Form
{
StoreItems<StoreItem> items;
int iFilename;
bool IsNewCustomerOrder;
public MusicStore()
{
InitializeComponent();
}
private void btnNewStoreItem_Click(object sender, EventArgs e)
{
var editor = new ItemEditor();
// Create a random number to get it ready for
// the user creating a new store item
var rnd = new Random();
editor.txtItemNumber.Text = rnd.Next(100000, 999999).ToString();
if (editor.ShowDialog() == DialogResult.Cancel)
LoadMusicStore();
}
internal void LoadMusicStore()
{
// Since all values seem ready, prepare to process the item
items = new StoreItems<StoreItem>();
var bfmStoreItem = new BinaryFormatter();
// This is the file that holds the list of items
var Filename = @"C:\Solo Music Store\StoreItems.slm";
if (File.Exists(Filename))
{
FileStream stmStoreItem = new FileStream(Filename,
FileMode.Open,
FileAccess.Read,
FileShare.Read);
try
{
// Retrieve the list of items from file
items = (StoreItems<StoreItem>)bfmStoreItem.Deserialize(stmStoreItem);
// Display the categories in the combo box
for (int i = 0; i < items.Count; i++)
{
StoreItem item = (StoreItem)items[i];
if (!cbxCategories.Items.Contains(item.Category))
cbxCategories.Items.Add(item.Category);
}
}
finally
{
stmStoreItem.Close();
}
}
}
}
}
- In the Solution Explorer, double-click MusicStore.cs to open the
form
- On the form, double-click the Item Category combo box
- Implement the SelectedIndexChanged event as follows:
private void cbxCategories_SelectedIndexChanged(object sender, EventArgs e)
{
cbxTypes.Items.Clear();
cbxTypes.Text = "";
lvwStoreItems.Items.Clear();
pbxStoreItem.Image = null;
// If the current store inventory is empty, don't do anything
if (items.Count == 0)
return;
// Get the item selected in the combo box
var strCategory = (string)cbxCategories.SelectedItem;
// Before doing anything, remove everything from the Types combo box
// This eliminates the possibility of adding the same item(s) that
// would exist already in the combo box
cbxTypes.Items.Clear();
// Check each item from the store inventory
for (var i = 0; i < items.Count; i++)
{
// Get the current item from the store inventory
var item = (StoreItem)items[i];
// If that item is the same as the one selected in the combo box...
if (item.Category == strCategory)
{
// ... get ready to add its corresponding type
// But check first that the type is not
// already in the Types combo box
// If it's not yet there, then add it
if (!cbxTypes.Items.Contains(item.Type))
cbxTypes.Items.Add(item.Type);
}
}
}
- Return to the Music Store form
- Double-click the Item Type combo box
- Implement the SelectedIndexChanged event as follows:
private void cbxTypes_SelectedIndexChanged(object sender, EventArgs e)
{
cbxTypes.Text = "";
pbxStoreItem.Image = null;
// If the current store inventory is empty, don't do anything
if (items.Count == 0)
return;
// Get the item selected in the Categories combo box
string strCategory = (string)cbxCategories.SelectedItem;
// Get the item selected in theTypes combo box
string strType = (string)cbxTypes.SelectedItem;
// Empty the Available Items list view because
// we are about to (re)populate it
lvwStoreItems.Items.Clear();
// Check each item from the store inventory
for (int i = 0; i < items.Count; i++)
{
// Get the current item from the inventory
StoreItem item = (StoreItem)items[i];
// If the category of that item is the same as the one
// selected in the combo box and the type of that item is
// the same as the one selected in the Types combo box...
if ((item.Category == strCategory) &&
(item.Type == strType))
{
// ... then display it in the Available Items list view
ListViewItem lviStoreItem =
lvwStoreItems.Items.Add(item.ItemNumber);
lviStoreItem.SubItems.Add(item.ItemName);
lviStoreItem.SubItems.Add(item.UnitPrice.ToString("F"));
}
}
}
- Return to the Music Store form
- On the form, double-click the Available Items list view
- Implement its SelectedIndexChanged event as follows:
private void lvwStoreItems_SelectedIndexChanged(object sender, EventArgs e)
{
StoreItem item = new StoreItem();
if ((lvwStoreItems.SelectedItems.Count == 0) ||
(lvwStoreItems.SelectedItems.Count > 1))
return;
string strItemNumber =
lvwStoreItems.SelectedItems[0].SubItems[0].Text;
for (int i = 0; i < items.Count; i++)
{
StoreItem itm = (StoreItem)items[i];
if (itm.ItemNumber == strItemNumber)
item = itm;
}
// Make a list of the picture files
string strDirectory = @"C:\Solo Music Store";
DirectoryInfo dirStoreItems = new DirectoryInfo(strDirectory);
FileInfo[] PictureFiles = dirStoreItems.GetFiles("*.jpg");
// Look for a file that holds the same name as the item number
foreach (FileInfo fle in PictureFiles)
{
// Get the name of the file without its extension
string fwe = Path.GetFileNameWithoutExtension(fle.FullName);
if (fwe == strItemNumber)
pbxStoreItem.Image = Image.FromFile(strDirectory +
"\\" + item.ItemNumber + ".jpg");
}
}
- Return to the Music Store form and click the list view under
Available Items if necessary
- In the Properties window, click the Events button and double-click
DoubleClick
- Implement the event as follows:
internal void CalculateOrder()
{
double itemsTotal = 0.00D, taxRate = 0.00D,
taxAmount = 0.00D, orderTotal = 0.00D;
// Check each row of the data grid view.
// Get the sub-total values and add them
for (int i = 0; i < dgvSelectedItems.Rows.Count - 1; i++)
itemsTotal += double.Parse(dgvSelectedItems.Rows[i].Cells[4].Value.ToString());
// Display the total in the Items Total text box
txtItemsTotal.Text = itemsTotal.ToString("F");
// Get the tax rate
taxRate = double.Parse(txtTaxRate.Text);
// Calculate the tax
taxAmount = itemsTotal * taxRate / 100;
// Add the tax amount to the items total to get the total of the order
orderTotal = itemsTotal + taxAmount;
// Display the amount collected for taxes
txtTaxAmount.Text = taxAmount.ToString("F");
// Display the order total
txtOrderTotal.Text = orderTotal.ToString("F");
}
private void lvwStoreItems_DoubleClick(object sender, EventArgs e)
{
// Get a reference to the row that was double-clicked
ListViewItem lviMusicItem = lvwStoreItems.SelectedItems[0];
// If no item exists or no row was double-selected, don't do anything
if (lvwStoreItems.SelectedItems.Count == 0)
return;
// If a row was double-clicked, transfer its values to the data grid view
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[0].Value = lviMusicItem.Text;
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[1].Value = lviMusicItem.SubItems[1].Text;
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[2].Value = lviMusicItem.SubItems[2].Text;
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[3].Value = "1";
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[4].Value = lviMusicItem.SubItems[2].Text;
string[] recMusicItem = { lviMusicItem.Text,
lviMusicItem.SubItems[1].Text,
lviMusicItem.SubItems[2].Text, "1",
lviMusicItem.SubItems[2].Text };
int r = dgvSelectedItems.Rows.Add(recMusicItem);
// Reset the lastly added row to get it ready to receive another record
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[0].Value = "";
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[1].Value = "";
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[2].Value = "";
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[3].Value = "";
dgvSelectedItems.Rows[dgvSelectedItems.Rows.Count - 1].Cells[4].Value = "";
CalculateOrder();
}
- Return to the Music Store form
- Click the data grid view under Selected Items
- In the Events section of the Properties window, double-click
CellLeave
- Implement the event as follows:
private void dgvSelectedItems_CellLeave(object sender, DataGridViewCellEventArgs e)
{
decimal unitPrice = 0.00M;
int quantity = 0;
decimal subTotal = 0.00M;
// Find out if the user was changing the quantity value on the row that has focus
if (e.ColumnIndex == 3)
{
// Get the unit price of the current row
unitPrice = decimal.Parse(dgvSelectedItems.Rows[e.RowIndex].Cells[2].EditedFormattedValue.ToString());
// Get the quantity value of the current row
quantity = int.Parse(dgvSelectedItems.Rows[e.RowIndex].Cells[3].EditedFormattedValue.ToString());
// Calculate the sub-total
subTotal = unitPrice * quantity;
// Display the sub-total on the current row
dgvSelectedItems.Rows[e.RowIndex].Cells[4].Value = subTotal.ToString();
// Update the calculations
CalculateOrder();
}
}
- Return to the Music Store form
- On the form, click the Tax Rate text box
- In the Events section of the Properties window, double-click Leave
- Implement the event as follows:
private void txtTaxRate_Leave(object sender, EventArgs e)
{
CalculateOrder();
}
- Return to the Music Store form
- Double-click the New Order button and implement its event as
follows:
private void btnNewCustomerOrder_Click(object sender, EventArgs e)
{
// We will store our files in the following folder
var strDirectory = @"C:\Solo Music Store\Receipts";
var dirInfo = Directory.CreateDirectory(strDirectory);
// Get the list of files, if any, from our directory
var fleList = dirInfo.GetFiles();
var Filename = "";
// If there is no file in the directory,
// then we will use 1000 as the first file name
if (fleList.Length == 0)
{
iFilename = 1000;
}
else // If there was at least one file in the directory
{
// Get a reference to the last file
var LastFile = fleList[fleList.Length - 1];
// Get the name of the last file without its extension
var fwe = Path.GetFileNameWithoutExtension(LastFile.FullName);
// Increment the name of the file by 1
iFilename = int.Parse(fwe) + 1;
}
// Update our global name of the file
Filename = strDirectory + "\\" + iFilename.ToString() + ".its";
txtReceiptNumber.Text = iFilename.ToString();
// Reset the form
cbxCategories.Text = "";
cbxTypes.Text = "";
lvwStoreItems.Items.Clear();
dgvSelectedItems.Rows.Clear();
txtItemsTotal.Text = "0.00";
txtTaxRate.Text = "7.75";
txtTaxAmount.Text = "0.00";
txtOrderTotal.Text = "0.00";
}
- Return to the Music Store form
- Double-click the Save button and implement the event as follows:
private void btnSave_Click(object sender, EventArgs e)
{
if (dgvSelectedItems.Rows.Count == 0)
{
MessageBox.Show("There is no customer order to save.");
return;
}
// We will store our files in the following folder
var strSelectedItems = @"C:\Solo Music Store\Receipts\Selected Items";
var strTotals = @"C:\Solo Music Store\Receipts\Totals";
var dirSelectedItems = Directory.CreateDirectory(strSelectedItems);
var dirTotals = Directory.CreateDirectory(strTotals);
// Get the list of files, if any, from our directory
FileInfo[] fleSelectedItems = dirSelectedItems.GetFiles();
var FilenameSelectedItem = "";
var FilenameTotal = "";
// If this is a new customer order,
// get ready to create a name for the file
if (IsNewCustomerOrder == true)
{
// If there is no file in the directory,
// then we will use 1000 as the first file name
if (fleSelectedItems.Length == 0)
{
iFilename = 1000;
}
else // If there was at least one file in the directory
{
// Get a reference to the last file
var LastFile = fleSelectedItems[fleSelectedItems.Length - 1];
// Get the name of the last file without its extension
var fwe = Path.GetFileNameWithoutExtension(LastFile.FullName);
// Increment the name of the file by 1
iFilename = int.Parse(fwe) + 1;
}
// Update our global name of the file
FilenameSelectedItem = strSelectedItems + "\\" + iFilename.ToString() + ".its";
FilenameTotal = strTotals + "\\" + iFilename.ToString() + ".ttl";
txtReceiptNumber.Text = iFilename.ToString();
IsNewCustomerOrder = false;
} // If a cleaning order was already opened, we will simply update it
else
{
FilenameSelectedItem = @"C:\Solo Music Store\Receipts\Selected Items\" +
txtReceiptNumber.Text + ".its";
FilenameTotal = @"C:\Solo Music Store\Receipts\Totals\" +
txtReceiptNumber.Text + ".ttl";
}
StoreItems<SoldItem> lstSelectedItems = new StoreItems<SoldItem>();
using (FileStream fsSelectedItems = new FileStream(FilenameSelectedItem, FileMode.Create))
{
// Get the items of each row and write its values to the selected items file
for (int i = 0; i < dgvSelectedItems.Rows.Count - 1; i++)
{
SoldItem si = new SoldItem();
si.ItemNumber = dgvSelectedItems.Rows[i].Cells[0].Value.ToString();
si.ItemName = dgvSelectedItems.Rows[i].Cells[1].Value.ToString();
si.UnitPrice = double.Parse(dgvSelectedItems.Rows[i].Cells[2].Value.ToString());
si.Quantity = int.Parse( dgvSelectedItems.Rows[i].Cells[3].Value.ToString());
si.SubTotal = double.Parse(dgvSelectedItems.Rows[i].Cells[4].Value.ToString());
lstSelectedItems.Add(si);
}
BinaryFormatter bfSelectedItems = new BinaryFormatter();
bfSelectedItems.Serialize(fsSelectedItems, lstSelectedItems);
}
using (StreamWriter wrtTotals = new StreamWriter(FilenameTotal))
{
wrtTotals.WriteLine(txtItemsTotal.Text);
wrtTotals.WriteLine(txtTaxRate.Text);
wrtTotals.WriteLine(txtTaxAmount.Text);
wrtTotals.WriteLine(txtOrderTotal.Text);
}
// Reset the form
btnNewCustomerOrder_Click(sender, e);
}
- Return to the Music Store Form
- Double-click the Open button and implement its event as follows:
private void btnOpen_Click(object sender, EventArgs e)
{
var strDirSelectedItems = @"C:\Solo Music Store\Receipts\Selected Items";
var strFileSelectedItems =
@"C:\Solo Music Store\Receipts\Selected Items\1000.its";
var strDirTotals = @"C:\Solo Music Store\Receipts\Totals";
var strFileTotals = @"C:\Solo Music Store\Receipts\Totals\1000.ttl";
if (txtReceiptNumber.Text == "")
return;
else
{
strFileSelectedItems = strDirSelectedItems +
"\\" + txtReceiptNumber.Text + ".its";
if (File.Exists(strFileSelectedItems))
{
using (FileStream fsSavedItems =
new FileStream(strFileSelectedItems, FileMode.Open))
{
BinaryFormatter bfSaveItems = new BinaryFormatter();
StoreItems<SoldItem> lstSavedItems =
(StoreItems<SoldItem>)bfSaveItems.Deserialize(fsSavedItems);
dgvSelectedItems.Rows.Clear();
for(int i = 0; i < lstSavedItems.Count; i++)
{
dgvSelectedItems.Rows.Add();
SoldItem si = (SoldItem)lstSavedItems[i];
dgvSelectedItems.Rows[i].Cells[0].Value = si.ItemNumber;
dgvSelectedItems.Rows[i].Cells[1].Value = si.ItemName;
dgvSelectedItems.Rows[i].Cells[2].Value =
si.UnitPrice.ToString();
dgvSelectedItems.Rows[i].Cells[3].Value = si.Quantity;
dgvSelectedItems.Rows[i].Cells[4].Value = si.SubTotal;
}
}
strFileTotals = strDirTotals + "\\" + txtReceiptNumber.Text + ".ttl";
try
{
var rdrTotals = new StreamReader(strFileTotals);
try
{
txtItemsTotal.Text = rdrTotals.ReadLine();
txtTaxRate.Text = rdrTotals.ReadLine();
txtTaxAmount.Text = rdrTotals.ReadLine();
txtOrderTotal.Text = rdrTotals.ReadLine();
IsNewCustomerOrder = false;
}
finally
{
rdrTotals.Close();
}
}
catch (FileNotFoundException)
{
MessageBox.Show("There is no customer order " +
"with that receipt number");
}
}
}
}
- Return to the Music Store form
- Double-click an unoccupied area of the form
- Implement the event as follows:
private void MusicStore_Load(object sender, EventArgs e)
{
btnNewCustomerOrder_Click(sender, e);
LoadMusicStore();
IsNewCustomerOrder = true;
}
- Return to the Music Store form
- Double-click the Close and implement its Click event as follows:
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}
- Execute the application
- Access the Item Editor dialog box and create a few more items as
follows (let the computer create the item numbers):
Category |
Type |
Item Name |
Unit Price |
Picture |
Recording |
Microphone |
MXL V63M Studio Condenser Microphone |
72.95 |
Picture |
Guitars |
Acoustic |
Yamaha FD01S Acoustic Folk Guitar |
185.95 |
|
Book/CD/DVD |
Instructional |
Hal Leonard Amazing Phrasing - Alto
Sax (Book/CD) |
18.00 |
|
Guitars |
Classical & Nylon |
Alvarez Artist Series AC60S
Classical Acoustic Guitar |
275.95 |
Picture |
Guitars |
Acoustic |
Washburn D100DL Acoustic Guitar |
150.50 |
Picture |
Drums |
Electronic Percussion |
Boss DR-670 Dr. Rhythm Drum Machine |
275.85 |
Picture |
Recording |
Microphone |
Shure SM58 Mic |
95.95 |
Picture |
Accessories |
Cables |
Live Wire HPE325 Headphone and
Extension Cable |
10.95 |
Picture |
Bass |
Acoustic Fretted |
Ibanez AEB10E Acoustic-Electric Bass
Guitar with Onboard Tuner |
350.00 |
Picture |
Drums |
World Percussion |
Latin Percussion Conga 3-Pack with
Bongos |
595.95 |
Picture |
Keyboards |
Synthesizers |
Roland JUNO-D 61-Key Synthesizer |
595.95 |
Picture |
Drums |
World Percussion |
Latin Percussion Aspire Conga Set
with Bongos and Stand |
425.50 |
Picture |
Recording |
Microphone |
AKG Perception 200 Condenser
Microphone |
160.00 |
Picture |
- Create a few customers' orders and click Save then New Order each
time. Here are examples:
- Close the form and return to your programming environment
|
|