KEMBAR78
C# Projects For Beginners | PDF | Method (Computer Programming) | Programming
0% found this document useful (0 votes)
565 views127 pages

C# Projects For Beginners

This book, written by Lynn Smith, is designed to guide beginners in C# programming through problem-based learning, using real-world tasks inspired by the author's experience tutoring a former customer service specialist. It includes a series of missions that cover fundamental programming concepts, such as creating applications, handling user input, using lists, and saving data to text files. The structured approach aims to help readers develop practical skills in software development, ultimately leading to the creation of a simple library management system.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
565 views127 pages

C# Projects For Beginners

This book, written by Lynn Smith, is designed to guide beginners in C# programming through problem-based learning, using real-world tasks inspired by the author's experience tutoring a former customer service specialist. It includes a series of missions that cover fundamental programming concepts, such as creating applications, handling user input, using lists, and saving data to text files. The structured approach aims to help readers develop practical skills in software development, ultimately leading to the creation of a simple library management system.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 127

C# PROJECTS FOR

BEGINNERS
Problem-based Learning
LYNN SMITH
Copyright © 2020 Lynn Smith
All rights reserved.

ISBN: 9798662670174

ABOUT THE BOOK


This book is the product of tutoring Josh.
Josh was a customer service specialist at my business. After receiving a
psychology degree from a local university, Josh wanted to become a software
developer. To help him reach his goal, I assigned him learning tasks on a
daily basis. He completed most of the tasks with help from the internet.
Occasionally, I gave him hints and tips. He took approximately one month to
complete all the missions in this book. Josh is a software developer at my
business now. This book is a collection of the first few lessons and tasks that
led Josh to his success.
I hope you can benefit from this book as well.

CONTENTS
Acknowledgments I
1 Get Ready 1
2 Your First Assignment 5
3 The Tiny Library Has a New Book 7
4 The Library Is Growing with More Books 10
5 Save Data Permanently in a Text File 14
6 Retrieve and Display the Books from a Text File 17
7 Organizing Statements by Methods 20
8 User Menu Displays Until Quit 26
9 Practice Makes Perfect 32
10A Book Has More Than Just a Title and Author 34
11Can We Have More Than One Author for a Book? 40
12Use the Book Class in the Tiny Library Program 44
13ENUM for Genre 49
14Graphical User Interface (GUI) 52
15Graphical User Interface (GUI) Continued 63
16Graphical User Interface (GUI) – Display All 68
Books
17Graphical User Interface (GUI) – Dropdown Menu 71
18Graphical User Interface (GUI) – Update a Book 75
19Graphical User Interface (GUI) – Delete a Book 87
20Graphical User Interface (GUI) – Check Out a 94
Book
21Graphical User Interface (GUI) – Return a Book 102
22Print a Receipt for Checking Out a Book 110
23Don’t Repeat Yourself (DRY) 114
24Practice, Practice, Practice 121

ACKNOWLEDGMENTS
This book is impossible without the support of my family.
MISSION 1: GET READY
Programming is writing instructions for computers to follow. Before you can
learn how to write the instructions, you need an application in which to write
your instructions. This book uses Visual Studio as such application. You will
be able to write and test instructions on Visual Studio.
Your task for this mission is to install Visual Studio and test one instruction
on it.
Search the Internet for “Visual Studio download”. Most likely, you will come
to the following site:
https://visualstudio.microsoft.com/downloads/
Find “Community” edition and click on “Free Download”.
After the download is completed, double click on the downloaded file to
install. The installer will prompt you to pick which component(s) to install.
Make sure you check the “.NET desktop development”.

Follow the screen prompt to complete the installation.


After restarting the computer, you may now launch Visual Studio. On the
first screen, click on “Create a new project” button.
The “Create a new project” window will display. In this window, search for
“Console App (.NET Framework) C#”.

Select the one that has all the terms (most likely the first one) and click on the
“Next” button on the bottom right of the window.
On the “Configure your new project” window, type in a project name, say
Mission1. Click on the “Create” button on bottom right to create the project.
You should not put any spaces in the project name.

You will see the Mission1 project displayed:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mission1
{
class Program
{
static void Main( string [] args)
{
}
}
}

You can ignore the first five lines of “using” for now. You may notice the
three pairs of curly braces. Think of each pair as a container. It is how C#
organizes the code. The largest, outer most container is a namespace called
Mission1. Anything inside that pair of curly braces is part of the Mission1
namespace. One of the components of Mission1 is a class called Program.
Similarly, components of that class should be inside the pair of curly braces.
Further inside the class container is a method container called Main(). All
content of the method should be inside its pair of curly braces. Think of a
method as a function. Right now, there is no instructions in this method.
All your instructions for the computers to follow should be inside the Main()
method, or inside the inner most pair of the curly braces in the above code
template.
Let’s add one line of instruction to the Mission1 project so the screen looks
like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mission1
{
class Program
{
static void Main( string [] args)
{
Console.ReadKey();
}
}
}
Save and run the program. Click on the “Start” icon on the menu to run the
program.

A blank console screen will pop up. Push any key on the keyboard. The
console closes.
The line of instruction you added tells the computer to receive any keystroke
from the console. If you don’t touch the keyboard, the console screen will
always be there waiting for a key press. After you press any key on the
keyboard, the program receives it and the computer has no more instructions
to follow and thus closes the console window. If you remove this line and run
the program, you will see the console window opens and closes immediately.
Congratulations! You are ready to have fun in C#.
MISSION 2: YOUR FIRST
ASSIGNMENT
A tiny library has only one book, The Old Man and the Sea by Ernest
Hemingway. Develop an application to display the book information to the
user.
Your task is to write instructions for displaying the book title and author on
the computer console screen.
Start a new C# Console .Net framework project called Mission2. Add the
following code in bold inside the Main() method (We include the method
header and the pair of curly braces for your convenience. Do not make your
code in Visual Studio bold. ):
static void Main( string [] args)
{
Console.WriteLine( "***** Tiny Library Book List *****" );
Console.WriteLine( "The Old Man and the Sea by Hemingway" );
Console.ReadKey();
}

Save and run the program by clicking on the “Start” button. You should see
the only book from the library displayed on a console screen. Then, press any
key on the keyboard to close the window.
In this mission, you have learned how to display a string on the console
screen with Console.WriteLine() method. Put that string inside the method’s
pair of parentheses. The string you want to display must be inside a pair of
quotation marks. The pair of quotation marks indicates the content is a string
literal.
Console is a prebuilt class that is part of System namespace. That is why at
the top of the program, you have the using System directive.
The WriteLine() method is part of the Console class. It is prebuilt. You just
use it.
Finally, every statement must terminate with a semicolon “;”.
Phenomenal! You have completed the first day’s job for the Tiny Library.
You have learned how to display a string text to a console window.
Take a break to cool down the computer before you continue on Mission 3.
MISSION 3: THE TINY
LIBRARY HAS A NEW
BOOK
The owner of the library was very happy with your application and decided to
buy a new book, The Adventures of Tom Sawyer by Mark Twain.
Your task in this mission is to develop an application that allows the owner of
the library to enter this new book into the system.
Start a new C# Console .Net framework project called Mission3. Add the
following code in bold inside the Main() method:
static void Main ( st r ing [] args)
{
Console.Writ eLi ne("Enter a new book title and author: " );
string newBook = Console.ReadLine();
Console.WriteLine("***** Tiny Library Book Li s t *****" );
Console.WriteLine("The Old Man and the Sea by Hemingway" );
Console.WriteLine(new Book);
Console.ReadKey();
}

Save and run the program.


When the prompt to enter a new book appears on the console, type, The
adventures of Tom Sawyer by Mark Twain, and push “Enter” key. The
following content will be displayed on console window following the new
book you just entered.

********* Tiny Library Book List *********


The Old Man and the Sea by Hemingway
The adventures of Tom Sawyer by Mark Twain
To prompt a user to enter something is the same as displaying a message to
the user you learned in the last mission. In this mission, you learn how to
capture that “something” the user typed on the keyboard. The statement for
the computer to capture user input is:
Console.ReadLine()

Similar to Console.WriteLine(), ReadLine() is another prebuilt method inside


the Console class. You just use it with Console.ReadLine().
You need a container to hold the user entered content. You use a variable to
store a user inputs.
A variable is like a container that can be used to store a value. To declare a
variable, you need a data type, followed by a variable name, like this:
string newBook;

After this line, the variable newBook can be used to hold any text string.
The keyword “string” is a data type in C#. Anything a user enters from
keyboard is a string, even a number. You will learn other data types later on.
The newBook is a programmer named variable name. There are simple rules
for naming a variable: 1) begin with a letter, an underscore, or @ symbol.
The remaining part of the name can contain letters, digits and underscore
symbol; 2) whitespaces are not allowed; 3) cannot be a C# keyword, such as
static, Main, or string; 4) case-sensitive, meaning newBook and newbook are
two different names.
The statement Console.ReadLine() receives a line of user input from the
keyboard.
And, string newBook = Console.ReadLine(); receives a line of user input and
assigns the value to the variable newBook. The “=” sign is used to assign a
value to a variable.
The above line of statement can also be broken up into two lines like this:
string newBook;
newBook = Console.ReadLine();

After this, the variable newBook holds the new title and author from the user.
As a result, you can display the content of the variable back on console
screen like displaying a string of text:
Console.WriteLine(newBook);

Note that you don’t use quotation marks around newBook because it is a
string variable, not a string literal value itself.
Great job! You now know how to get user input and display something to the
user.
Take a break to cool down the computer before you continue on Mission 4.
MISSION 4: THE LIBRARY
IS GROWING WITH MORE
BOOKS
The owner of the library is so happy with your application that she decides to
buy more books.
You learned how to add one new book to the system. How difficult could it
be to add more books? To handle multiple books, you can copy and paste the
following two lines of code multiple times.
Console.WriteLine( "Enter the new book title and author: " );
string newBook = Console.ReadLine();

However, you don’t know how many books the library will buy and thus
don’t know how many times you need to copy and paste. Every time, the
owner buys a new book, you have to add two lines of code to the application.
How realistic is that?
A solution is to use a list type to hold as many titles as needed. Unlike a
variable that can hold only one value at a time, a list can hold many values at
a time. You can think of a list as a container that can hold many smaller
containers at once.
Your task in this mission is to enhance the program so that it can ask a user
for many books, one at a time, and display them all.
Start a new C# Console .Net framework project called Mission4 with the
following code inside the Main() method:
List< string > allBooks = new List< string >();
Console.WriteLine( "Enter the new book title and author: " );
string newBook = Console.ReadLine();
while (newBook != "" )
{
allBooks.Add(newBook);
Console.WriteLine( "Enter new book title and author: " );
newBook = Console.ReadLine();
}
Console.WriteLine( "***** Tiny Library Book List *****" );
Console.WriteLine( "The Old Man and the Sea by Hemingway" );
foreach ( string aBook in allBooks)
{
Console.WriteLine(aBook);
}

Console.ReadKey();

Save and run the program.


When prompted to enter a new book, type, The Adventures of Tom Sawyer
by Mark Twain, and push “Enter” key on the keyboard.
After the prompt to enter a new book appears again, type, Gone with the
Wind by Margaret Mitchell, and push “Enter” key on the keyboard.
Assuming you do not have any more new books. Press the “Enter” key
without typing in anything. The console screen will display:

********* Tiny Library Book List *********


The Old Man and the Sea by Ernest Hemingway
The adventures of Tom Sawyer by Mark Twain
Gone with the Wind by Margaret Michell
The program can handle more than just two new books without modifying
the code.
Let’s see what is new in this mission.
The following line of code declares and initializes a list type called allBooks:
List<string > allBooks = new List<string >();
Compared to the statement of declaring and initializing a string variable
called newBook:
string newBook = “”;
The allBooks list can now be used to hold a group of string type values. That
is exactly what we need.
Additionally, the following line of code adds a book to the allBooks list.
allBooks.Add(newBook);

To add an element to a list variable, you use the Add() method of the list
type.
Next, take a look at the following code:
while (newBook != "" )
{
allBooks.Add(newBook);
Console.WriteLine( "Enter new book title and author: " );
newBook = Console.ReadLine();
}

This is a while loop. It will repeat the block of statements inside the curly
braces {} again and again until the condition after the keyword “while” is no
longer true. In other words, as long as the newBook is not an empty string,
the block of statements will be executed. That is why after you enter the first
book, the program prompts for the second book. After you enter the second
book, it prompts for the third book. For the third book, instead of entering a
title, you just push the “enter” key, which is an empty string. The while loop
stops looping and the program execution continues after the loop.
A while loop is defined with a keyword “while” followed by a Boolean
condition (true or false). Followed by a pair of curly braces. All statements
that you want to repeat should be inside the pair of curly braces.
The next new statements are the following code:
foreach ( string aBook in allBooks)
{
Console.WriteLine(aBook);
}

This is another type of loop. The foreach loop is often used together with a
list. It is able to loop through every element in a list. Here, the code takes out
one element from the allBooks list at a time and displays it with the
Console.WritelIne() method.
The foreach loop terminates when all elements of the list are read.
Well done! You now know how to use a list type to hold multiple values and
how to use a while loop to add multiple values to a list and use a foreach loop
to display the content of a list.
Take a break to cool down the computer before you continue on Mission 5.
MISSION 5: SAVE THE
BOOK DATA
PERMANENTLY IN A
TEXT FILE
The owner of the library tries to run the application by herself while you are
out for a cup of coffee. She realizes that all books she entered are gone once
the program completes the execution. Is there a way to keep the book data
she enters?
Your task in this mission is to save the book data in an external text file.
Start a new C# Console .Net framework project called Mission5 with the
following code inside the Main() method (the new code statements for saving
the data are displayed in bold):
List< string > allBooks = new List< string >();
Console.WriteLine( "Enter the new book title and author: " );
string newBook = Console.ReadLine();
while (newBook != "" )
{
allBooks.Add(newBook);
Console.WriteLine( "Enter new book title and author: " );
newBook = Console.ReadLine();
}
Console.WriteLine( "***** Tiny Library Book List *****" );
Console.WriteLine( "The Old Man and the Sea by Hemingway" );
foreach ( string aBook in allBooks)
{
Console.WriteLine(aBook);
}
using (StreamWriter sw = File.AppendText( "books.txt" ))
{
foreach ( string aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
Console.ReadKey();

You need to add the following directive to the group of using statements at
the top of the program in order to use the prebuilt StreamWriter and File
classes.
using System.IO;

Save and run the program as you did in Mission 4. The only difference
between this mission and Mission 4 is the book data is now also saved to a
text file in your computer.
Let’s go to find the “books.txt” file and see if our books are saved.
You can search your computer for the Mission5 folder. Then, the bin folder
inside it. Finally, the debug folder inside the bin folder. The “books.txt” file
should be inside the debug folder.
You can open the file with any text editor, but do not modify it. You should
see the two books you entered are saved in the file as two separate lines.
The following statements are new in this mission:
using (StreamWriter sw = File.AppendText( "books.txt" ))
{
foreach ( string aBook in allBooks)
{
sw.WriteLine(aBook);
}
}

The first line allows you to save the content to a file called books.txt. This is
similar to displaying the content to console. You use a foreach loop to write
every element in the allBooks list to the books.txt file.
The prebuilt AppendText() method of the File class makes it possible to
append text to a file. If the file books.txt does not exit, a new file with that
name will be created. If the file already exists, new records will be added to
the end of the file.
Way to go! You now know how to save data to a text file for later use.
Take a break to cool down the computer before you continue on Mission 6.
MISSION 6: RETRIEVE
AND DISPLAY THE BOOKS
FROM A TEXT FILE
After learning how to save data to a text file, your next goal is to learn how to
retrieve the data from the text file.
Your task in this mission is to retrieve and display all books from the
books.txt file.
Start a new C# Console .Net framework project called Mission6 with the
following code inside the Main() method
List< string > allBooks = new List< string >();

using (StreamReader sr = new StreamReader( "books.txt" ))


{
string aBook;
while ((aBook = sr.ReadLine()) != null )
{
allBooks.Add(aBook);
}
}

Console.WriteLine( "***** Tiny Library Book List *****" );


foreach ( string aBook in allBooks)
{
Console.WriteLine(aBook);
}
Console.ReadKey();

Also add using Sytem.IO; statement to the directive group on top of the program.
This is required because the statements inside the Main() method include the
prebuilt class StreamReader.
Copy the books.txt file from Mission5\bin\debug folder to
Mission6\bin\debug folder.
Save and run the program. You should see the two books you saved in the
previous lesson from the text file are displayed on console screen.
The new code used in this mission to retrieve data from the text file is:
using (StreamReader sr = new StreamReader( "books.txt" ))
{
string aBook;
while ((aBook = sr.ReadLine()) != null )
{
allBooks.Add(aBook);
}
}

The code is similar to the statements for writing data to a text file. Instead of
using StreamWriter class, this time you use the StreamReader class.
Whenever you use StreamWriter or StreamReader classes, you need to add
using System.IO directive.
The following code inside the while loop condition: aBook = sr.ReadLine() reads a
line from the text file and assign it to a variable called aBook. Then, (aBook =
sr.ReadLine()) != null, compares the retrieved value to a special value called
“null”. If aBook is not null, the condition is true and the statement block
inside the while loop will be executed. In other words, the book will be added
to the list as long as there are more lines of record in the text file.
The “null” is a special value that actually indicates no value. The != is a
comparison if two values are NOT the same. If two values are not the same,
the result is true. Otherwise, it is false.
When StreamReader.ReadLine() reads a line, it puts a mark at the end of the
line (or the beginning of the next line to be more accurate.). The next time,
ReadLine() is called, the reading will continue from the mark. This is similar
to a bookmark we use when reading a book.
Very good! You now know how to retrieve data from a text file and add the
retrieved data to a list type. From there, you can display it to the console
screen.
Take a break to cool down the computer before you continue on Mission 7.
MISSION 7: ORGANIZING
STATEMENTS BY
METHODS
Your code is getting more complicated. You cannot ask the owner of the
library to run two programs: one to save the data and the other to retrieve the
data. You want to put two features in one application.
Your task in this mission is to add a menu to the application for the user to
choose whether to save or retrieve the data. Then execute corresponding code
based on the user choice.
=== Menu (SELECT A TASK BY NUMBER) ===
1. Add new books.
2. Display all books.
3. Quit the program.

Start a new C# Console .Net framework project called Mission7 with the
following code inside the Main() method
Console.WriteLine( "=== Menu (SELECT A TASK BY NUMBER) ===" );
Console.WriteLine( "1. Add new books." );
Console.WriteLine( "2. Display all books." );
Console.WriteLine( "3. Quit the program." );
string menuSelection = Console.ReadLine();
switch (menuSelection)
{
case "1" :
AddNewBooks();
Console.WriteLine( "The books have been added." );
break ;
case "2" :
DisplayBooks();
Console.WriteLine( "****** End of the list ******" );
break ;
default :
Console.WriteLine( "Thank you for using the system" );
break ;
}

Console.ReadKey();

You may notice that the AddNewBooks() and DisplayBooks() are red
squiggly underlined. These are method calls. A method is a container for a
group of statements. You need to define the two methods to make the
program work. You can think of a method as a smaller container inside a
class container.
Next, add the following code outside of the closing curly brace for the Main()
method, but inside the Program class closing curly brace. The code declares
two methods: AddNewBooks() and DisplayBooks():

static void AddNewBooks()


{
List< string > allBooks = new List< string >();
Console.WriteLine( "Enter new book title and author: " );
string newBook = Console.ReadLine();
while (newBook != "" )
{
allBooks.Add(newBook);
Console.WriteLine( "Enter new book title and author: " );
newBook = Console.ReadLine();
}
using (StreamWriter sw = File.AppendText( "books.txt" ))
{
foreach ( string aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
}

static void DisplayBooks()


{
List< string > allBooks = new List< string >();

using (StreamReader sr = new StreamReader( "books.txt" ))


{
string aBook;
while ((aBook = sr.ReadLine()) != null )
{
allBooks.Add(aBook);
}
}

Console.WriteLine( "***** Tiny Library Book List *****" );


foreach ( string aBook in allBooks)
{
Console.WriteLine(aBook);
}
}

Save and run the program.


When the user menu appears on the console screen, type 1 (cannot select 2 at
first run) and then press “Enter” key. Type a couple of books. Press “Enter”
after every book. When no more books to enter, just press “Enter” to end new
book data entry.
Run the program again. Type 2 on the menu choice and then press “Enter”
key to see all books in the text file.
Run the program one more time. Type 3 on the menu and press “Enter” key
to quit without the program doing anything.
The following code is a switch case statement:
switch (menuSelection)
{
case "1" :
AddNewBooks();
Console.WriteLine( "The books have been added." );
break ;
case "2" :
DisplayBooks();
Console.WriteLine( "***** End of the list *****" );
break ;
default :
Console.WriteLine( "Thank you for using the system" );
break ;
}

A switch statement evaluates an expression inside the parentheses after the


keyword “switch”. Based on the result of the evaluation, it will choose a
single case section to execute from a list of candidate case sections.
In the above example, based on the value of the menuSelection, the program
will determine which case block to execute. A case block starts with the
keyword “case”, followed by a possible evaluation value, and ends with the
keyword “break”. Note the different punctuation of colon and semicolon. The
former is used after each case value and the latter is used to terminate every
statement.
If the menuSelection is “1”, the program will call the AddNewBooks()
method. If the menuSelection is “2”, the program will call the
DisplayBooks() method, and so on.
A method is a container for a group of statements. The AddNewBooks()
method is defined in the following code:
static void AddNewBooks()
{
List< string > allBooks = new List< string >();
Console.WriteLine( "Enter new book title and author: " );
string newBook = Console.ReadLine();
while (newBook != "" )
{
allBooks.Add(newBook);
Console.WriteLine( "Enter new book title and author: " );
newBook = Console.ReadLine();
}
using (StreamWriter sw = File.AppendText( "books.txt" ))
{
foreach ( string aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
}

The above method definition includes five parts:


1. static declares the type of method is static. A static method is required here
because the method is used inside the Main() method that is static. The
general rule is that only a static method can be used inside a static method.
2. void is the method return type. This method does not return anything, so
the return type is void. You will learn other return type in future missions.
3. AddNewBooks is the method name. The rules for naming a method is the
same as the rules for naming a variable. By convention, a public method is
often started with a capital letter.
4. The pair of parentheses () indicates the parameter list. It is used for any
input of the method. If a method needs one or more variables from outside,
they should be placed inside the parentheses.
5. The pair of curly braces {} indicates the method body. It includes all
instruction statements you want the method to execute.
One benefit of using a method is better organization of the code. Instead of
all the above statements in the switch statement, you just need one line
statement in the switch case statement. Such organization makes the code
easy to understand and maintain.
Another benefit of using a method is “write once, run anywhere”. If you need
to use the group of statement anywhere else, you just call the method with
one line of code.
Way to go! In this mission, you have learned how the switch statement works
with case and break. You have also learned how to refactor by grouping a
block of statements into a method.
Take a break to cool down the computer before you continue on Mission 8.
MISSION 8: USER MENU
DISPLAYS UNTIL QUIT
Mission 7 is good. However, you have to run the program twice if you want
to enter a new book and then check if the book is in the system.
Your task in this mission is to update the application so that it keeps running
until the user chooses to exit.
The following menu displays once the program runs and displays again after
every task is completed until the user picks 3 to exit:

=== Menu (SELECT A TASK BY NUMBER) ===


1. Add new books.
2. Display all books.
3. Quit the program.

If the user enters anything other than 1, 2, or 3, the menu keeps appearing.
Such tasks can be accomplished with a loop.
If the user enters 1 or 2, the program will execute the specific task and return
to the menu for next user selection. Another loop will accomplish this.
Specifically, if the user enters “1”, the instructions for adding new books will
execute. If the user enters “2”, all books saved in the text file will be
displayed. If the user enters “3”, the program will terminate. A switch case
statement fits the purpose.
Start a new C# Console .Net framework project called Mission8 with the
following code inside the Main() method:
int menuSelection;
do
{
DisplayMenu();
menuSelection = int .Parse(Console.ReadLine());
} while (menuSelection < 1 || menuSelection > 3);
bool menuFlag = true ;
while (menuFlag)
{
switch (menuSelection)
{
case 1:
AddNewBooks();
Console.WriteLine( "The books have been added." );
break ;
case 2:
DisplayBooks();
Console.WriteLine( "***** End of the list*****" );
break ;
default :
Console.WriteLine( "Thank you!" );
menuFlag = false ;
break ;
}
if (menuFlag)
{
DisplayMenu();
menuSelection = int .Parse(Console.ReadLine());
}
}

Console.ReadKey();

Next, outside the Main() method, but inside the Program class, add the
DisplayMenu(), AddNewBooks(), and DisplayBooks() methods:
static void DisplayMenu()
{
Console.WriteLine( "===Menu (SELECT A TASK BY NUMBER)===" );
Console.WriteLine( "1. Add new books." );
Console.WriteLine( "2. Display all books." );
Console.WriteLine( "3. Exit the program." );
}

static void AddNewBooks()


{
List< string > allBooks = new List< string >();
Console.WriteLine( "Enter new book title and author: " );
string newBook = Console.ReadLine();
while (newBook != "" )
{
allBooks.Add(newBook);
Console.WriteLine( "Enter new book title and author: " );
newBook = Console.ReadLine();
}
using (StreamWriter sw = File.AppendText( "books.txt" ))
{
foreach ( string aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
}
static void DisplayBooks()
{
List< string > allBooks = new List< string >();
using (StreamReader sr = new StreamReader( "books.txt" ))
{
string aBook;
while ((aBook = sr.ReadLine()) != null )
{
allBooks.Add(aBook);
}
}
Console.WriteLine( "***** Tiny Library Book List *****" );
foreach ( string aBook in allBooks)
{
Console.WriteLine(aBook);
}
}
Save and run the program (cannot pick 2 at first run).
The following line declares an integer type of variable.
int menuSelection;

Unlike a string type variable you used in earlier missions, an int variable
allows you to have arithmetic operations on it, e, g. you can compare if the
number is less than 1 (menuSelection <1). You cannot do the same with a
string variable.
We introduce a new type of loop, do while loop, in the following code:
do
{
DisplayMenu();
menuSelection = int .Parse(Console.ReadLine());
} while (menuSelection < 1 || menuSelection > 3);

The do while loop is very similar to while loop you learned in an earlier
mission. The while loop checks a condition before a loop starts. The do while
loop, on the other hand, checks a condition after a loop completes its loop. If
the condition is true, the loop will continue. The do while loop will execute
the block of statements at least once even though the condition may be fault.
The while loop may not execute the block of statements at all if the condition
is false before the first loop.
The next line of statement uses the prebuilt int.Parse() method to parse a
string to an integer. Anything a user enters in the keyboard is a string, even a
number.
menuSelection = int .Parse(Console.ReadLine());

Unfortunately, the int.Parse() method cannot convert a string like “two” to an


integer. It can only parse something like “2” to an int.
The above loop statement displays the menu and receives the user menu
selection. If the selection is between 1 and 3 inclusive, the loop will
terminate. Otherwise, it will display the menu again for selection. Such a loop
guarantees a valid selection from the user before the execution of the
statement after the loop continues. In other words, the execution continues
only after the user selection is 1, 2, or 3.
The following line of statement introduces still another type of variable, a
bool type. A bool type variable can hold only two possible values, true or
false. It is useful for controlling a loop.
bool menuFlag = true ;

You use the menuFlag variable to control the following while loop:
while (menuFlag)
{
switch (menuSelection)
{
case 1:
AddNewBooks();
Console.WriteLine( "The books have been added." );
break ;
case 2:
DisplayBooks();
Console.WriteLine( "***** End of the list *****" );
break ;
default :
Console.WriteLine( "Thank you for using the system" );
menuFlag = false ;
break ;
}
if (menuFlag)
{
DisplayMenu();
menuSelection = int .Parse(Console.ReadLine());
}
}

With this loop, you can have the menu appear after each task unless the user
selects “3” to exit the program.
The value of menuFlag is true so that the while loop can continue until its
value is set to false. The value is set to false when the user selects 3.
The switch statement is very similar to the one you learned in an earlier
mission. Note the difference between the following two lines
case “1”:
case 1:

The quotation around a number indicates the number is a string type of data.
A number without quotation marks indicates an int type of data.
A switch statement allows the execution of instructions to be selective based
on certain condition. Another similar statement is if statement. The following
code shows the use of an if statement:
if (menuFlag)
{
DisplayMenu();
menuSelection = int .Parse(Console.ReadLine());
}

The two lines of statement inside the curly braces is the body of an if
statement. If the condition is true, the block will be executed. Otherwise, the
program will ignore the block of code.
Superb! In this mission, you have learned the difference between the while
loop and the do while loop. Both are used for iterating. You also learned the
difference between a switch statement and an if statement. Both are used for
selective execution.
Take a break to cool down the computer before you continue on Mission 9.
MISSION 9: PRACTICE
MAKES PERFECT
You have accomplished a lot in the previous eight missions. In this mission,
we want you to develop a project alone.
We need a phone book to keep a record of all contacts with a name and a
phone number. The application will display a console menu to let the user
pick a task:
=== Menu (SELECT A TASK BY NUMBER) ===
1. Add new contacts.
2. Display all contacts.
3. Exit the program.
The contact data should be saved in an external text file called phonebook.txt.
Feel free to check the code in the previous missions. You don’t need to
memorize any of those statements. After you develop several projects, you
will use them like a tool you are familiar with.
Additionally, we recommend that you develop some projects that you can
use, such as keeping a shopping list, or keeping records of miles you walk
every day.
Remember, practice makes perfect.
A summary of the first nine missions: You have learned that an application is
made up of instructions for computers to follow. An application is organized
by namespace, class, and method. All instructions should be inside the
Main() method. Instructions are executed sequentially by default. You can
repeat a certain block of instructions many times by using a loop. You can
also selectively execute certain blocks by using switch or if statements.
Finally, an application is more maintainable by having your own custom
methods. You group a block of statements for the same purpose into a
method. Instructions in a custom method will not be executed until being
called. As a result, the sequence of instructions inside a method makes
different output while the sequence of methods inside a class does not
matter.
MISSION 10: A BOOK HAS
MORE THAN JUST A TITLE
AND AUTHOR
The owner of the library wants to keep more data about the books. For
example, a book has a publishing year, language, genre, the page number,
price purchased, copies purchased, and copies available, and most important,
ISBN (International Standard Book Number). One possible solution is to
duplicate the code for handling the book title and author as you did in the
earlier missions. However, the code will be messy and hard to work with. For
example, if you want to display all books published before the year 2000, it
will be a major challenge.
Another solution is to use “class”. You will create a custom class for book. It
is like a blueprint for buildings or a cookie cutter for cookies. You will have a
book class for books.
The book class defines all properties of the book of the Tiny Library.
Title
Author
ISBN
Language
Genre
Copyright Year
Pages
Price
Total Copies (Copies purchased)
Available Copies (Copies not checked out)
Your task in this mission is to create a class called Book that defines the
characteristics of a book owned by the Tiny Library.
Start a new C# Console .Net framework project called Mission10. In the
“Solution Explorer” window

Right click on “C# Mission10” (not Solution Mission10). In the context


menu, select “Add”. On the submenu, select “class”. On the popup window,
name this class “Book.cs” (without quotation marks). Then click on the
“Add” button on the bottom right to create an empty class called Book.
Similar to Program.cs, a window called Book.cs is open with the following
default content (if it is not shown by default, you can double click on the
Book.cs in the Solution Explorer window):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mission10
{
class Book
{
}
}
The default content includes a block of five “using” directives which can be
removed if you prefer (you may add them back as needed) or just leave them
alone. It also has a namespace called Mission10. Inside the namespace, it has
a class called Book. You will add content inside the Book class. First, add the
following lines inside the class.
public string Title { get ; set ; }
public string Author { get ; set ; }
public string ISBN { get ; set ; }
public string Language { get ; set ; }
public string Genre { get ; set ; }
public int CopyrightYear { get ; set ; }
public int Pages { get ; set ; }
public double Price { get ; set ; }
public int TotalCopies { get ; set ; }
public int AvailableCopies { get ; set ; }

These are called properties. A property starts with an access modifier that
restricts the accessibility of this property. The “public” access modifier
allows this property to be accessed anywhere. Next, comes a data type. Every
property has a data type much like a variable. Followed by the property
name. By convention, a property name starts with a capital letter and the
naming of a property follows the same naming rules for a variable. The last
part of a property is getter/setter, which allows this property to get the value
from a hidden variable or set the value to the hidden variable. You don’t need
to know anything about this hidden variable. You just need to know this
property.
For example, if you want to get the value from this hidden title variable and
store it in a variable called myTitle, do this:
string myTitle = Title;
If you want to set a value of “The Old Man and the Sea” to the hidden title
variable, do this:
Title = “The Old Man and the Sea”;
Next, still inside the class, add a constructor after the properties:
public Book ( string title, string author, string isbn,
string language, string genre, int copyrightYear, int pages, double price, int totalCopies,
int availableCopies)
{
Title = title;
Author = author;
ISBN = isbn;
Language = language;
Genre = genre;
CopyrightYear = copyrightYear;
Pages = pages;
Price = price;
TotalCopies = totalCopies;
AvailableCopies = availableCopies;
}

A constructor of a class is a method without the return data type. The purpose
of a constructor is to create an instance of the class by initializing its field
values. Similar to a cookie cutter that allows you to cut a cookie, a
constructor of a class allows you to create a book with initial values. The
class of the book defines the structure of books. An instance (often called an
object) of a book class is a specific book (e. g. The Old Man and the Sea with
purchase price of 9.99 etc.).
You have just created a custom class that can be used throughout the
application.
Let’s go to the Main() method of the Program.cs file as you have done in all
previous missions. Add the following lines inside the Main() method:
Book myFavoriteBook = new Book( "The Old Man and The Sea" , "Ernest Hemingway" , "123456789"
"English" , "Fiction" , 1952, 160, 19.99, 3, 3);
Console.WriteLine(myFavoriteBook);
Console.ReadKey();

The “new” keyword in the statement actually calls the constructor of the
Book class. So the arguments inside the pair of parentheses after new Book()
should match the constructor of the Book class. For example, the first
argument should match the first parameter in the constructor. If you pass
“19.99” as the first argument to the constructor, then this book’s title will be
19.99! If the data types do not match, you will see a compiler error.
If you save and run the program, you will see Mission10.Book appears on the
console screen. To make the real book information on the screen, you need to
modify the Book class by adding a ToString() method to the class. The
method will be automatically called when you print an object.
Go to the Book.cs file. Add the following code inside the Book class, after
the constructor (after the constructor’s closing curly brace).
public override string ToString()
{
string str;
str = $"Title: {Title} \nAuthor: { Author} \nISBN: {ISBN} " ;
str += $"\nLanguage: { Language} \nGenre: { Genre} " ;
str += $"\nYear: { CopyrightYear} \nPages: { Pages} " ;
str += $"\nPrice: { Price} \nTotal Copies: { TotalCopies} " ;
str += $"\nAvailable Copies: { AvailableCopies} " ;
return str;
}

The access modifier for this method is public that means it is available
anywhere. The “override” keyword means this method inherits from another
class with the same method name. You must provide specific format for the
data in the current class. The return data type for this method is “string”.
Inside the ToString() method, you return the book data well formatted. The $
sign is for string interpolation. An interpolated string is like a template string
with dynamic content inside a pair of burly braces. The “\n” indicates a line
break. The += operator is for string concatenation that combines strings into
one longer string.
Save and run the program. You will see the details of the book displayed on
the console screen.
Title: The Old Man and The Sea
Author: Ernest Hemingway
ISBN: 123456789
Language: English
Genre: Fiction
Year: 1952
Pages: 160
Price: 19.99
Total Copies: 3
Available Copies: 3

Terrific. You have created a custom class in this mission. A class is a way to
programming that simplifies the coding. Your Book class has a group of
properties, a constructor, and a ToString() method.
Take a break to cool down the computer before you continue on Mission 11.
MISSION 11: CAN WE
HAVE MORE THAN ONE
AUTHOR FOR A BOOK?
If you just add more authors to a book, it will be difficult for the computers to
know the name of each author. Most authors have first name and last name.
However, an author may have a middle name. In addition, you may not know
how many authors are in a book. All these make it difficult to handle the
authors of a book.
One solution is to make the Author property of the Book class a list type so
that you can add as many authors to the list as you need to and still be able to
distinct names in the author list.
Your task in this mission is to update the Author property of the Book class
and update all corresponding part in the constructor and the ToString()
method.
Start a new C# Console .Net framework project called Mission11. In the
“Solution Explorer” window, right click on “C# Mission11” (not Solution).
In the context menu, select “Add”. On the submenu, select “class”. On the
popup window, name this class “Book.cs” (without quotation marks). Then
click on the “Add” button on the bottom right to create an empty class called
Book.
Copy all content of the Book class (not the whole file because they have
different namespaces) from the previous mission to this class with the
following updates.
First, update the Author property
public string Author { get ; set ; }
to the following:
public List<string > Authors { get ; set ; }

This time, the type is no longer just a string, it is a list of strings. The
properties now look like (the difference is in bold font):
public string Title { get ; set ; }
public List< string > Authors { get ; set ; }
public string ISBN { get ; set ; }
public string Language { get ; set ; }
public string Genre { get ; set ; }
public int CopyrightYear { get ; set ; }
public int Pages { get ; set ; }
public double Price { get ; set ; }
public int TotalCopies { get ; set ; }
public int AvailableCopies { get ; set ; }

Second, copy and update the constructor to the following (the difference is in
bold font):
public Book ( string title, List< string > authors , string isbn,
string language, string genre, int copyrightYear, int pages, double price, int totalCopies,
availableCopies)
{
Title = title;
Authors = authors;
ISBN = isbn;
Language = language;
Genre = genre;
CopyrightYear = copyrightYear;
Pages = pages;
Price = price;
TotalCopies = totalCopies;
AvailableCopies = availableCopies;
}

The new constructor accepts a list of strings instead of just a string.


Third, copy and update the ToString() method:
public override string ToString()
{
string str;
str = $"Title: {Title} " ;
foreach ( string author in Authors)
{
str += string .Format( $"\nAuthor: {author} " );
}
str += $"\nISBN: {ISBN} " ;
str += $"\nLanguage: { Language} \nGenre: { Genre} " ;
str += $"\nYear: { CopyrightYear} \nPages: { Pages} " ;
str += $"\nPrice: { Price} \nTotal Copies: { TotalCopies} " ;
str += $"\nAvailable Copies: { AvailableCopies} " ;
return str;
}

You use a foreach loop to add each individual author to the output string.
Finally, you need to add the following statements to the Main() method of the
Program.cs file.
List< string > authors1 = new List< string >() { "Hemingway" };
Book myFavoriteBook1 = new Book( "The Old Man and The Sea" ,
authors1, "123456789" , "English" ,
"Fiction" , 1952, 160, 19.99, 3, 3);
Console.WriteLine(myFavoriteBook1);

List< string > authors2 = new List< string >() { "Alan Moore" ,
"Dave Gibbons" };
Book myFavoriteBook2 = new Book( "Watchmen" , authors2,
"223456789" , "English" , "Mystery" ,
2019, 416, 29.99, 3, 3);
Console.WriteLine(myFavoriteBook2);

Console.ReadKey();

The first book is almost the same as the code in the last mission. An author
cannot be directly added to a book constructor. You need to create a list and
put that author in the list and then use the list in the book. This is a little
difficult to understand. Even a single author must be put in a list because the
constructor wants a list.
To declare a list of string types:
List<string > authors1 = new List<string >()

To declare a list and initialize it:


List< string > authors1 = new List< string >() { "Hemingway" };

The second book starts with declaring a list and initialize it with two authors:
List<string > authors2 = new List<string >() { "Alan Moore" , "Dave Gibbons" };

Save and run the program. You should see the two books correctly displayed.
Terrific! In this mission, you have learned how to use a list in a class. Such
technique allows you to construct complex classes.
Take a break to cool down the computer before you continue on Mission 12.

.
MISSION 12: USE THE
BOOK CLASS IN THE TINY
LIBRARY PROGRAM
Using a class allows the program to handle more properties of a book.
Writing code to work with 10 properties of a book is almost the same as
handling one property thanks to the Book class.
Your task in this mission is to update the Tiny Library application you
created in Mission 8 with a custom Book class.
Copy the Mission 8 folder and name this new folder Mission12. Do not
rename any files inside. This way, if you make any errors, you still have a
working version. Open Mission12 project with Visual Studio by double
clicking on Mission8.sln file inside the Mission12 folder.
First, go to the “Solution Explorer” window. Add a class called Book.cs to
the project with the following content (Visual Studio generates the Book
class header and its pair of curly braces when you add the class, we include
them here for your comparison purpose):

class Book
{
public string Title { get ; set ; }
public List< string > Authors { get ; set ; }
public string ISBN { get ; set ; }
public string Language { get ; set ; }
public string Genre { get ; set ; }
public int CopyrightYear { get ; set ; }
public int Pages { get ; set ; }
public double Price { get ; set ; }
public int TotalCopies { get ; set ; }
public int AvailableCopies { get ; set ; }
public Book ( string title, List< string > authors, string
isbn, string language, string genre, int
copyrightYear, int pages, double price, int
totalCopies, int availableCopies)
{
Title = title;
Authors = authors;
ISBN = isbn;
Language = language;
Genre = genre;
CopyrightYear = copyrightYear;
Pages = pages;
Price = price;
TotalCopies = totalCopies;
AvailableCopies = availableCopies;
}

public override string ToString()


{
string str;
str = $"Title: {Title} " ;
foreach ( string author in Authors)
{
str += string .Format( $"\nAuthor: {author} " );
}
str += $"\nISBN: {ISBN} " ;
str += $"\nLanguage: { Language} \nGenre: { Genre} " ;
str += $"\nYear: { CopyrightYear} \nPages: { Pages} " ;
str += $"\nPrice: { Price} \nTotal Copies: { TotalCopies} " ;
str += $"\nAvailable Copies: { AvailableCopies} " ;
return str;
}
}

Next, update the AddNewBooks() method inside the Program.cs class with
the following code (We keep the old code as comment-out for your
comparison purpose. You add “ //” in front of a line to tell compiler to ignore
the statement.):

static void AddNewBooks()


{
//List<string> allBooks = new List<string>();
List<Book> allBooks = new List<Book>();
//Console.WriteLine("Enter the new book title and
// author: ");
Console.WriteLine( "Enter a new book title:" );
//string newBook = Console.ReadLine();
string title = Console.ReadLine();
//while (newBook != "")
while (title != "" )
{

List< string > authors = new List< string >();


int authorCount = 1;
string author;
do
{
Console.WriteLine( "Enter author no. " +
authorCount + ": " );
author = Console.ReadLine();
if (author != "" )
{
authors.Add(author);
authorCount++;
}
} while (author != "" );
Console.WriteLine( "Enter ISBN: " );
string isbn = Console.ReadLine();
Console.WriteLine( "Enter language: " );
string language = Console.ReadLine();
Console.WriteLine( "Enter genre: " );
string genre = Console.ReadLine();
Console.WriteLine( "Enter Copyright Year: " );
int copyRightYear =
int .Parse(Console.ReadLine());
Console.WriteLine( "Enter total pages: " );
int pages = int .Parse(Console.ReadLine());
Console.WriteLine( "Enter price: " );
double price =
double .Parse(Console.ReadLine());
Console.WriteLine( "Enter total copies: " );
int totalCopies =
int .Parse(Console.ReadLine());
Console.WriteLine( "Enter available copies: " );
int availableCopies =
int .Parse(Console.ReadLine());
Book newBook = new Book(title, authors, isbn,
language, genre, copyRightYear, pages,
price, totalCopies, availableCopies);
allBooks.Add(newBook);
//Console.WriteLine("Enter the new book title and
// author: ");
//newBook = Console.ReadLine();
Console.WriteLine( "Enter a new book title: " );
title = Console.ReadLine();
}
using (StreamWriter sw = File.AppendText( "books.txt" ))
{
//foreach (string aBook in allBooks)
foreach (Book aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
}

Save and run the program. When there are no more additional authors, just
push the “Enter” key to signal that there are no more authors. Similarly, when
there are no more new books, just push the “Enter” key to terminate the data
input.
In this updated AddNewBook() method, a user can enter more than one
author and enter as many books as desired.
A do while loop is used for author input. This allows multiple authors for a
book. Each author is now an element of the authors list. It is easy to access
each author.
do
{
Console.WriteLine( "Enter author no. " + authorCount + ": " );
author = Console.ReadLine();
if (author != "" )
{
authors.Add(author);
authorCount++;
}
} while (author != "" );

Wonderful! In this mission, you have learned how to use a custom class in an
application.
Take a break to cool down the computer before you continue on Mission 13
MISSION 13: ENUM FOR
GENRE
One problem with the book data entry is that users can enter incorrect data,
such as genre can be fiction or fictions, or other variations. To avoid such
errors and to limit the user choice for genre, you can use an Enum data type.
You can think of an enum type as a class which contains a group of
constants. A variable of an enum data type can only store one of those values.
Enum members cannot have an access modifier. It is always public.
Your task in this mission is to create an enum data type so that the genre of
the books in the Tiny Library can only be one of the following: Romance,
Mystery, Fantasy, Thriller, Fiction, Inspiration, and Biography.
Open Mission12 project in Visual Studio. Go to “Solution Explorer” window
and double click on Book.cs to open it. Add the following statements to
declare an enum data type. Add the code right inside the namespace, but
outside the Book class:

public enum BookGenre


{
Romance,
Mystery,
Fantasy,
Thriller,
Fiction,
Inspiration,
Biography
}

Then update the corresponding property of the Book class (we keep the old
code as comment-out for comparison purpose):
// public string Genre { get; set; }
public BookGenre Genre { get ; set ; }

The data type for Genre used to be string. Now it is the BookGenre type you
declared earlier.
Also update the Constructor of the Book class:
//public Book(string title, List<string> authors, string isbn,
// string language, string genre, int
// copyrightYear, int pages,
// double price, int totalCopies, int
// availableCopies)
public Book ( string title, List< string > authors, string isbn,
string language, BookGenre genre, int
copyrightYear, int pages,
double price, int totalCopies, int
availableCopies)

Finally, update the Main() method of the Program.cs class. Go to “Solution


Explorer” window and double click on the Program.cs file to open it. Inside
the AddNewBooks() method, update the following code (comment out the
two lines about genre and add the new code. Nothing else in the
AddNewBooks() method should be changed.):

//Console.WriteLine("Enter genre: ");


//string genre = Console.ReadLine();
BookGenre genre;
string genreString;
do {
Console.WriteLine( "Enter genre: " );
genreString = Console.ReadLine();

}while (!Enum.TryParse(genreString, out genre));

You use a prebuilt method of TryParse(). The method will do two things: 1)
Convert a string to a BookGenre enum type. 2) Return a Boolean value. If the
conversion is successful, the method will return a true value. Otherwise, it
will return a false value. You add a “!” in front of the method to turn the
Boolean value to an opposite value. “!” is an Boolean operator for NOT. If
the value is true, the NOT operator will turn it to false. If the value is false,
the NOT operator will turn it to true.
In our example, if the conversion is NOT successful, we will prompt the user
to enter the genre again. Otherwise, the execution will move on for
statements after the do while loop.
Save and run the program. Enter some spelling variations of a genre (note the
case of the characters) and see how the application works.
Wonderful! You have learned how to create an enum data type and how to
use it to limit the possible values for the genre of a book.
Take a break to cool down the computer before you continue on Mission 14.
MISSION 14: GRAPHICAL
USER INTERFACE (GUI)
Eventually, an application for our Tiny Library needs a graphical user
interface. Windows Forms Application is a quick way to develop such an
application.
Your task in this mission is to get familiar with Windows Forms Application
and design the main form, add the new book form, and add the author form to
replace the console application of the Tiny Library.
Start a new project the same way as you did for Console application, but on
the “Create a new project” window, search for “Windows Forms App (.NET
Framework)”.

You can double click on the “Windows Forms App (.NET Framework) panel
to move on to the next window or single click to select it and click on the
“Next” button to continue.
On the “Configure your new project” window, name the project “Mission14”
(no quotation marks) and click on the “Create” button to have a new
Windows Forms Application.
You will see a blank windows form on the screen.
You can add controls to the form. A control, such as a label control, a textbox
control, or a button control can be added to the form to make the form
interactive and event driven.
You can find all controls on the Toolbox window:

A toolbox is a window that should appear on the left side by default. If you
don’t see one, you can go to “View” on the menu, then toolbox, or just hit
control+Alt+x on keyboard.
Your tasks in this and the next few missions are to convert the Tiny Library
Program from a console application to a graphical user interface with
enhanced features.
Let’s add a button onto this first form. Go to the Toolbox and expand
“Common Controls”. Double clicking on the “Button” will add one button to
the Form (drag a control from toolbox to a form will also work).
By default, this button on the form should be selected. If not, click on the
button to select it. Then go to the Properties window (located on the bottom
right by default). If not found, you can right click on the button and select
property:

The properties window displays all available properties of a selected control.


Let’s first change the Text property from default “button1” to “Add a new
book”. You can click on button1 in the Properties window and delete the
content and type in a new value. You may need to resize the button so that all
text will show up. To resize a button, you can click to select it and then drag
the sides to change its size.
Next, have the button selected again and go to the properties window. Scroll
up in the properties window to see (Name) property. Change the default value
of the property from “button1” to “addNewBookButton”
When the program executes, you want a click on this button to open up a new
form that you can enter a new book.
Let’s add a new form to the project. This is very similar to adding a class to
the project you learned earlier. Go to the “Solution Explorer” window. Right
click on the “C# Mission14” project, then “Add”, and finally “Form
(Windows Forms)…”
In the popup “Add New Item – Mission 14” window, rename the form from
the default “Form2.cs” to “AddNewBookForm.cs”. Then, click on the “Add”
button to continue.
With this AddNewBookForm in design view, let’s add 11 label controls, 9
textbox controls, 1 listbox, and 4 buttons. Reorganize the controls by
dragging a control so that they look like this (You don’t see a textbox name
on the form. It is shown in the properties window when you drag a control.
The textboxes must be organized sequentially from 1 to 9 in order to match
the names in the property setting table you will read next.):
A label control allows you to display something to the user. A textbox control
can be used for collecting user inputs. A listbox control displays a list of
items. A button control introduces events.
Next, you need to set the properties of each control by following the values in
the table below (blank indicates no change is necessary):
Control Text property (Name) property
Label1 Add a New Book
Label2 Title
Label3 ISBN
Label4 Language
Label5 Genre
Label6 Year
Label7 Pages
Label8 Price
Label9 Total Copies
Label10 Available Copies
Label11 Authors
Textbox1 titleTextbox
Textbox2 isbnTextbox
Textbox3 languageTextbox
Textbox4 genreTextbox
Textbox5 yearTextbox
Textbox6 pagesTextbox
Textbox7 priceTextbox
Textbxo8 totalCopiesTextbox
Textbox9 availableCopiesTextbox
ListBox1 authorsListBox
Button1 Add Author addAuthorButton
Button2 Remove Author removeAuthorButton
Button3 Add Book addBookButton
Button4 Close Form and Save Books closeFormButton
The completed form should look like this:
Go to the “Solution Explorer” window. Add another windows Form to the
project. Name this new form AddAuthorForm. You will use this form to add
an author.
Add 2 label controls, 1 textbox control, and 2 button controls to the
AddAuthorForm.
Update the properties of each control by following the table below (empty
cell value indicates no change necessary):

Controls Text property (Name) property


Label1 Add an Author
Label2 Author Name
Textbox1 authorNameTextbox
Button1 Add Author addauthorButton
Button2 Close closeButton

The completed form looks like this:

Finally, add the button event handlers to make the program work.
Go to Form1 in design view. Double click on the “Add a New Book” button.
This will generate the button click event handler in the code view:
private void addNewBookButton_Click( object sender,
EventArgs e)
{

All the statements you want to execute when the user clicks on the button
should be inside this pair of curly braces. All you need is to open the
AddNewBookForm. Add two lines of statement inside (we show the method
header for your comparison convenience):
private void addNewBookButton_Click( object sender,
EventArgs e)
{
AddNewBookForm addNewBookForm = new AddNewBookForm();
addNewBookForm.ShowDialog();
}

The first line creates an instance/object of the AddNewBookForm.


AddNewBookForm is a class and you create an instance of it in order to use
it. The second line calls the prebuilt ShowDialog() method of the class. All
forms have a ShowDialog() method inherited from the prebuilt Form class.
Save and run the program. You will see the click on the button on Form1
open the Add New Book form.
Stop the execution by clicking on the red square on the menu bar. Go to Add
New Book Form in design view. Double click on “Add Author” button to
generate button event handler and add the following code in bold:
private void addAuthorButton_Click( object sender, EventArgs e)
{
AddAuthorForm addAuthorForm = new
AddAuthorForm( this .authorsListBox);
addAuthorForm.ShowDialog();
}

The above code will open the Add Author Form when the “Add Author”
button of the Add New Book Form is clicked at run time.
In addition to creating an instance of AddAuthorForm, you also pass the
“this.authorsListBox” object to the new form. The keyword “this” indicates
the current form which has a control called authorsListBox. You pass this
control to the new form so that items (author names) can be added to the
listbox on current form from the new form.
Go to the “AddAuthorForm.cs” in code view (in Solution Explorer window,
with the AddNewBookForm.cs selected, click on the <> icon to open a file in
code view).

Add a new property to hold the authorListBox passed from the


AddNewBookForm. You should also update the constructor of the
AddAuthorForm. The content of AddAuthorForm.cs partial class should now
look like this:
public ListBox ListBox { get ; set ; }
public AddAuthorForm ( ListBox listBox )
{
InitializeComponent();
ListBox = listBox;
}

You may want to read the above two paragraphs one more time. The
AddNewBookForm passes an authorListBox to the AddAuthorForm. The
latter needs a variable to hold it. The value is passed on through the
constructor.
Go to the AddAuthorForm in design view. Double click on the “Add Author”
button to create an event handler to add a new author to the authorListBox.

private void addAuthorButton_Click( object sender, EventArgs e)


{
ListBox.Items.Add(authorNameTextBox.Text);
authorNameTextBox.Clear();
authorNameTextBox.Focus();
}

Still have AddAuthorForm in design view. Double click on the “Close”


button to add a statement to close the form:
private void closeButton_Click( object sender, EventArgs e)
{
Close();
}

Save and run the program. You should be able to add one or more authors to
the AddNewBookForm. Nothing else works at this time.
Note: if you ever see “To prevent possible data loss before loading the
designer, the following errors must be resolved:” error, click on the “Go to
code” on top right of the window and comment out the error line.
Splendid! In this lesson, you have learned how to start a Windows Forms
application. You have learned how to add a new form to the project, how to
add controls to a form, and how to write simple statements to make a form
interactive.
Take a break to cool down the computer before you continue on Mission 15.
MISSION 15: GRAPHICAL
USER INTERFACE (GUI)
CONTINUED
Have the Mission14 project open in Visual Studio before continuing.
Your task in this mission is to make the “Remove Author” button, “Add
Book” button, and “Close Form and Save Books” button on the
AddNewBookForm work.
Go to “Solution Explorer” window, double click on AddNewBookForm.cs to
open it in design view. Double click on the “Remove Author” button to
generate the button event handler. Add code below (bold code only):
private void removeAuthorButton_Click( object sender,
EventArgs e)
{
if (authorsListBox.SelectedIndex != -1)
{
authorsListBox.Items
.Remove(authorsListBox.SelectedItem);
}
else
{
MessageBox.Show( "Select an author to remove." );
}
}

Save and run the program. You can now add an author and remove an author
as needed.
The authorsListBox.SelectedIndex != -1 checks if any item on the listbox is
selected. When nothing on a listbox is selected. The selectedIndex property
of the listbox will equal to -1.
Next, you are going to add a new book with the authors to a list.
First, go to the “Solution Explorer” window. Add a class called Book.cs to
the project with the following content:
class Book
{
public string Title { get ; set ; }
public List< string > Authors { get ; set ; }
public string ISBN { get ; set ; }
public string Language { get ; set ; }
public string Genre { get ; set ; }
public int CopyrightYear { get ; set ; }
public int Pages { get ; set ; }
public double Price { get ; set ; }
public int TotalCopies { get ; set ; }
public int AvailableCopies { get ; set ; }
public Book ( string title, List< string > authors, string
isbn, string language, string genre, int
copyrightYear, int pages, double price,
int totalCopies, int availableCopies)
{
Title = title;
Authors = authors;
ISBN = isbn;
Language = language;
Genre = genre;
CopyrightYear = copyrightYear;
Pages = pages;
Price = price;
TotalCopies = totalCopies;
AvailableCopies = availableCopies;
}

public override string ToString()


{
string str;
str = $"Title: {Title} " ;
foreach ( string author in Authors)
{
str += string .Format( $"\nAuthor: {author} " );
}
str += $"\nISBN: {ISBN} " ;
str += $"\nLanguage: { Language} \nGenre: { Genre} " ;
str += $"\nYear: { CopyrightYear} \nPages: { Pages} " ;
str += $"\nPrice: {Price} \nTotal Copies: {TotalCopies} " ;
str += $"\nAvailable Copies: { AvailableCopies} " ;
return str; }
}

Next, go to “Solution Explorer” window, open AddNewBookForm.cs in code


view (Select the file and click on the <> icon).
Add the following list as the first line right inside the AddNewBookForm
partial class, but outside any constructor or methods:
List<Book> allBooks = new List<Book>();

Back to the AddNewBookForm in design view. Double click the “Add


Book” button to generate the button event handler. Add the code below
(again showing the handler header and the pair of curly braces is for your
comparison. Do not copy them. This is true for all code in this book.):

private void addBookButton_Click( object sender, EventArgs e)


{
List< string > allAuthors = new List< string >();
foreach (var i in authorsListBox.Items)
{
allAuthors.Add(i.ToString());
}
bool allFieldsFilled = true ;
foreach (TextBox textBox in this .Controls.OfType<TextBox>())
{
if ( string .IsNullOrEmpty(textBox.Text.Trim()))
{
allFieldsFilled = false ;
}
}
if (authorsListBox.Items.Count < 1)
{
allFieldsFilled = false ;
}
if (allFieldsFilled)
{
Book newBook = new Book(titleTextBox.Text,
allAuthors, isbnTextBox.Text,
languageTextBox.Text, genreTextBox.Text,
int .Parse(yearTextBox.Text),
int .Parse(pagesTextBox.Text),
double .Parse(priceTextBox.Text),
int .Parse(totalCopiesTextBox.Text),
int .Parse(availableCopiesTextBox.Text));
allBooks.Add(newBook);
}
else
{
MessageBox.Show( "All fields must be filled." );
}
}

Save and run the code. You can add a new book with author(s) to the
allBooks list, but not to the books.txt file yet.
Finally, make the “Close Form and Save Books” button work.
Go to AddNewBookForm in design view. Double click on the “Close Form
and Save Books” button and add the code (Remember to add using
Systems.IO; in the directive group on top of the file because you use the
prebuilt StreamWriter class):
private void closeFormButton_Click( object sender, EventArgs e)
{
using (StreamWriter sw = File.AppendText( "books.txt" ))
{
//foreach (string aBook in allBooks)
foreach (Book aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
Close();
}

Save and run the program.


If you want to see what data is saved in the text file, go to “Mission14”
folder, then “bin” folder inside it, then “debug” folder inside the “bin” folder
to see books.txt file. Open the file to check if the books are saved. Remember
to close the file after viewing.
Brilliant! In this mission, you have completed the graphical user interface for
saving new book data to an external text file.
Take a break to cool down the computer before you continue on Mission 16.
MISSION 16: GRAPHICAL
USER INTERFACE (GUI) –
DISPLAY ALL BOOKS
Have the Mission14/15 project open to continue working on it.
Your task in this mission is to display all books from the books.txt file.
Open Form1 in design view by double click on it in the Solution Window.
Add a button with the (Name) property of “displayAllButton” and the Text
property of “Display All Books” to Form1.

Add a new windows form called DisplayAllForm to the project. Add a


ListBox and a button to the form. Set the (Name) property of the ListBox to
“displayAllListBox”. Set the (Name) property of the button to “closeButton”
and the Text property of the button to “Close”.
You want all books from the books.txt file to be displayed when the form
loads. Double click anywhere on DisplayAllForm in design view, but not on
any controls. This will generate a form load event handler. When the form
loads, all statements inside the handler will be executed. Add code for the
handler shown below (require using System.IO; directive):

private void DisplayAllForm_Load( object sender, EventArgs e)


{
List< string > allBooks = new List< string >();

using (StreamReader sr = new StreamReader( "books.txt" ))


{
string aBook;
while ((aBook = sr.ReadLine()) != null )
{
allBooks.Add(aBook);
}
}

Console.WriteLine( "*****Tiny Library Book List******" );


foreach ( string aBook in allBooks)
{
displayAllListBox.Items.Add(aBook);
}
}
There are three parts in the above code. First, declare a list to hold all books.
Second retrieve all lines from the books.txt file and add each line to the list.
Lastly, display all elements on listbox from the list.
Back to the DisplayAllForm in design view. Double click on the “Close”
button and add code to close the form.
private void closeButton_Click( object sender, EventArgs e)
{
Close();
}

Go back to the Form1 in design view. Double click on the “Display All
Books” button and add the following code in bold:
private void displayAllButton_Click( object sender, EventArgs e)
{
DisplayAllForm displayAllForm = new DisplayAllForm();
displayAllForm.ShowDialog();
}

Save and run the application.


Outstanding! You have learned how to retrieve all books from a text file and
display them in a windows form ListBox control.
Take a break to cool down the computer before you continue on Mission 17.
MISSION 17: GRAPHICAL
USER INTERFACE (GUI) --
ADD DROPDOWN MENU
FOR GENRE
Recall in an earlier mission, you limit the book genre selection by using the
enum type. For windows forms application, there is another option. You can
use a dropdown menu.
Your task in this mission is to replace the TextBox for genre with a
dropdown combobox in the AddNewBookForm. A combobox control allows
the users to pick an item from a list.
Open Mission14/15/16 in Visual Studio. In the “Solution Explorer” window,
double click on “AddNewBookForm.cs” to open the form in design view.
Click on the genreTextBox to select it. Hit the “delete” key on the keyboard
to remove it. Go to the ToolBox window, double click on “ComboBox” to
add it to the form. Drag it to the right position. Set its (Name) property to
“genreComboBox”. Still in the properties window, scroll down to the “Items”
property. Click on the “Items” property to have an ellipsis icon appear on the
right end of the same line. Click on the ellipsis icon to have a “String
Collection Editor” window popup. In the popup, enter the following lines:
Romance
Mystery
Fantasy
Thriller
Fiction
Inspiration
Biography
Click on the “OK” button to close the popup window.
Since you changed the textbox for genre to a ComboBox with a new name.
You need to change the corresponding code. You can double click on the
“Add Book” button on the AddNewBookForm to go to its event handler.
Inside the event handler, find the following line:
Book newBook = new Book(titleTextBox.Text, allAuthors,
isbnTextBox.Text, languageTextBox.Text, genreTextBox.Text,
int .Parse(yearTextBox.Text), int .Parse(pagesTextBox.Text),
double .Parse(priceTextBox.Text),
int .Parse(totalCopiesTextBox.Text),
int .Parse(availableCopiesTextBox.Text));

And change the genreTextBox.Text to genreComboBox.Text as follow:


Book newBook = new Book(titleTextBox.Text, allAuthors,
isbnTextBox.Text, languageTextBox.Text, genreComboBox.Text ,
int .Parse(yearTextBox.Text), int .Parse(pagesTextBox.Text),
double .Parse(priceTextBox.Text),
int .Parse(totalCopiesTextBox.Text),
int .Parse(availableCopiesTextBox.Text));

Finally, still inside the add book button click event handler, you need to make
sure the user selected a genre before the book can be added. This is similar to
checking if an author is added to a book. Add the following if statement right
after the code of checking if at least one author is added:
if (genreComboBox.SelectedIndex == -1)
{
allFieldsFilled = false ;
}

Save and run the program.


It is nice to give the user some feedback whether the book is added. Add the
following line after the book is added to the allBooks list:
MessageBox.Show("The book is added." );
You have made a few changes to the addBookButton event handler. If you
have any issues, compare your code to the code here:
private void addBookButton_Click( object sender, EventArgs e)
{
List< string > allAuthors = new List< string >();
foreach (var i in authorsListBox.Items)
{
allAuthors.Add(i.ToString());
}
bool allFieldsFilled = true ;
foreach (TextBox textBox in this .Controls.OfType<TextBox>())
{
if ( string .IsNullOrEmpty(textBox.Text.Trim()))
{
allFieldsFilled = false ;
}
}
if (authorsListBox.Items.Count < 1)
{
allFieldsFilled = false ;
}
if (genreComboBox.SelectedIndex == -1)
{
allFieldsFilled = false ;
}
if (allFieldsFilled)
{
Book newBook = new Book(titleTextBox.Text, allAuthors,
isbnTextBox.Text, languageTextBox.Text,
genreComboBox.Text , int .Parse(yearTextBox.Text),
int .Parse(pagesTextBox.Text),
double .Parse(priceTextBox.Text),
int .Parse(totalCopiesTextBox.Text),
int .Parse(availableCopiesTextBox.Text));
allBooks.Add(newBook);
MessageBox.Show( "The book is added." );
}
else
{
MessageBox.Show( "All fields must be filled." );
}
}

Splendid! In this mission, you have learned how to use ComboBox for a
dropdown menu in windows forms applications.
Take a break to cool down the computer before you continue on Mission 18
MISSION 18: GRAPHICAL
USER INTERFACE (GUI)
UPDATE A BOOK
You have successfully migrated the Tiny Library application from console to
windows forms. The owner of the library wants more functionalities. A user
may enter wrong data when adding a new book. There must be a way to
update an existing book in the system.
Your task in this mission is to add a feature to allow a user to update an
existing book.
Have the Mission14/15/16/17 project open before continuing.
Open the Form1 in design view. Add a button with the (Name) property set to
“updateBookButton” and the Text property set to “Update a book”.

In the “Solution Explorer” window, add a form named


“UpdateBookForm.cs” to the project.
On the UpdateBookForm in design view, add 11 label controls, 9 textbox
controls, 5 button controls, 1 comboBox control and 1 listbox control.
Set each control properties according to the below table (Empty cell indicates
using the default value and no changes necessary):
Controls Text property (Name) property
Label1 Enter an ISBN
Label2 Title
Label3 ISBN
Label4 Language
Label5 Genre
Label6 Year
Label7 Pages
Label8 Price
Label9 Total Copies
Label10 Available Copies
Label11 Author(s)
TextBox1 searchISBNTextBox
TextBox2 titleTextBox
TextBox3 isbnTextBox
TextBox4 languageTextBox
TextBox5 yearTextBox
TextBox6 pagesTextBox
TextBox7 priceTextBox
TextBox8 totalCopiesTextBox
TextBox9 availableCopiesTextBox
Button1 Search searchButton
Button2 Add Author addAuthorButton
Button3 Remove Author removeAuthorButton
Button4 Update Book updateBookButton
Button5 Close and Save closeFormButton
ComboBox1 genreComboBox
ListBox1 authorsListBox

The following figure shows the form after the properties are set.
Start coding.
Go to the “Solution Explorer” window and double click on Form1.cs to open
it in design view. Double click on the “Update a book” button on Form1 and
add the following code:
private void updateBookButton_Click( object sender, EventArgs e)
{
UpdateBookForm updateBookForm = new UpdateBookForm();
updateBookForm.ShowDialog();
}

Next, back to the “Solution Explorer” window, click to select


UpdateBookForm.cs and click on the code view icon (<>) to open the file in
code view.
You want to retrieve the books from the books.txt file and to be loaded into a
List when the form loads. This makes it easy to handle all the books. After
completing the update, you can save the list of books back to the text file
replacing all existing records in the books.txt file.
To add instructions to retrieve all books from the books.txt file to a list, you
need a list to hold them. Add the following line right after the constructor, but
inside the UpdateBookForm class.
List<Book> allBooks = new List<Book>();

To retrieve records from the text file and put them in the list, you need the
form load event handler. Go to the UpdateBookForm in design view, Double
click on any empty space on the form and add the code. Note the list
declaration is already in the file and thus should not be duplicated. We show
it here so that you can compare the code (you will need using System.IO
directive because the StreadReader class is used):
List<Book> allBooks = new List<Book>();
private void UpdateBookForm_Load( object sender, EventArgs e)
{
using (StreamReader sr = new StreamReader( "books.txt" ))
{
string title;
while ((title = sr.ReadLine()) != null )
{
title = getContent(title);
List< string > allAuthors = new List< string >();
string author = "" ;
while ((author = sr.ReadLine()).Substring(0, 6)
== "Author" )
{
author = getContent(author);
allAuthors.Add(author);
}
string isbn = getContent(author);
string language = getContent(sr.ReadLine());
string genre = getContent(sr.ReadLine());
int year = int .Parse(getContent(sr.ReadLine()));
int pages = int .Parse(getContent(sr.ReadLine()));
double price =
double .Parse(getContent(sr.ReadLine()));
int totalCopies =
int .Parse(getContent(sr.ReadLine()));
int availableCopies =
int .Parse(getContent(sr.ReadLine()));
Book newBook = new Book(title, allAuthors, isbn,
language, genre, year, pages,
price, totalCopies, availableCopies);
allBooks.Add(newBook);
}
}
}

private string getContent( string str)


{
int position = str.IndexOf( ": " );
return str.Substring(position + 2);
}

Use a method called getContent() to retrieve the part of text file with just the
content, not with the row header added. For example, the book title is “The
Old Man and the Sea”. The record saved in the books.txt file is “Title: The
Old Man and the Sea”. You don’t want to save the word “Title: “ in the list.
You use a prebuilt string.IndexOf() method of the string to find the position
number of a string. The counting starts from zero. Suppose you have the
following statements:
string message = “I love C#.”;
int position = message.IndexOf(“ve”);
The position value will be 4. The IndexOf() method returns an integer for the
location position of the first appearance of the string you search for. The
space also counts as a character.
You also use a prebuilt string.Substring() method to return a substring of a
given string with certain position requirements. If you pass only a number, it
will return the substring beginning on that position and to the end of the
string.
string message = “I love C#.”;
string substring = message.Substring(4);

The substring value will be “ve C#.”


If you pass two numbers to the Substring method, you will receive a
substring beginning on the first number position, and with the length of the
second number.
string message = “I love C#.”;
string substring = message.Substring(2, 4);

The substring value will be “love”. The number “2” indicates the beginning
position of 3rd character (remember, the position counting starts from 0). The
second number “4” indicates that the length of the substring is four
characters.
Note the list of allBooks is declared outside the event handler so that other
event handlers can use its values.
Next, you want to search a book by its ISBN.
Go to the “Solution Explorer” windows and double click on
UpdateBookForm.cs to open it in design view. Double click on the search
button of the UpdateBookForm and add the code:
private void searchButton_Click( object sender, EventArgs e)
{
foreach (Book book in allBooks)
{
if (book.ISBN == searchISBNTextBox.Text)
{
titleTextBox.Text = book.Title;
isbnTextBox.Text = book.ISBN;
languageTextBox.Text = book.Language;
genreComboBox.ResetText();
genreComboBox.SelectedText = book.Genre;
yearTextBox.Text =book.CopyrightYear.ToString();
pagesTextBox.Text = book.Pages.ToString();
priceTextBox.Text = book.Price.ToString();
totalCopiesTextBox.Text =
book.TotalCopies.ToString();
availableCopiesTextBox.Text =
book.AvailableCopies.ToString();
authorsListBox.Items.Clear();

authorsListBox.Items
.AddRange(book.Authors.ToArray());
}
}
}

Save and run the program.


In the above code, you first iterate through the allBooks list by using a
foreach statement. It retrieves one book at a time. If the book’s ISBN is the
same as the ISBN entered by the user, the details of the book will be
displayed in those textboxes ready for updates.
Note: only the last book that matches the ISBN will be displayed. If no book
found, the program does nothing. You may want to add an else block to send
feedback to the user (not coded).
Next, make the “Add Author” button on the UpdateBookForm work.
Go to UpdateBookForm in design view. Double click on the “Add Author”
button and add the following code:
private void addAuthorButton_Click( object sender, EventArgs e)
{
AddAuthorForm addAuthorForm = new
AddAuthorForm( this .authorsListBox);
addAuthorForm.ShowDialog();
}

You are using an existing form, AddAuthorForm for adding a new author.
You used the form in an earlier mission when you want to add a new book.
Then, make the “Remove Author” button on the UpdateBookForm work.
Keep UpdateBookForm in design view. Double click on the “Remove
Author” button and add the following code:
private void removeAuthorButton_Click( object sender,
EventArgs e)
{
if (authorsListBox.SelectedIndex != -1)
{
authorsListBox.Items
.Remove(authorsListBox.SelectedItem);
}
else
{
MessageBox.Show( "Select an author to remove." );
}
}

Save and run the program. You should see that authors can be added to or
removed from the book.
Next, make the “Update book” button work.
Still have the UpdateBookForm in design view. Double click on the “Update
book” button and add the following code:

private void updateButton_Click( object sender, EventArgs e)


{
List< string > allAuthors = new List< string >();
foreach (var i in authorsListBox.Items)
{
allAuthors.Add(i.ToString());
}
bool allFieldsFilled = true ;
foreach (TextBox textBox in
this .Controls.OfType<TextBox>())
{
if ( string .IsNullOrEmpty(textBox.Text.Trim()))
{
allFieldsFilled = false ;
}
}
if (authorsListBox.Items.Count < 1)
{
allFieldsFilled = false ;
}
if (genreComboBox.Text == "" )
{
allFieldsFilled = false ;
}
if (allFieldsFilled)
{
Book bookToUpdate = allBooks.Find(b => b.ISBN
== searchISBNTextBox.Text);
bookToUpdate.Title = titleTextBox.Text;
bookToUpdate.Authors = allAuthors;
bookToUpdate.ISBN = isbnTextBox.Text;
bookToUpdate.Language = languageTextBox.Text;
bookToUpdate.Genre = genreComboBox.Text;
bookToUpdate.CopyrightYear =
int .Parse(yearTextBox.Text);
bookToUpdate.Pages = int .Parse(pagesTextBox.Text);
bookToUpdate.Price= double .Parse(priceTextBox.Text);
bookToUpdate.TotalCopies =
int .Parse(totalCopiesTextBox.Text);
bookToUpdate.AvailableCopies =
int .Parse(availableCopiesTextBox.Text);
MessageBox.Show( "The book is updated." );
}
else
{
MessageBox.Show( "All fields must be filled." );
}
}

Save and run the program. You may not see the book being updated if you
close the form and go to display all books. This is because you only update
the books in the list. The list has not been saved back to the text file.
The major structure of the above code is similar to the “Add new book”
feature. We would like to further explain the following line from the code
above:
Book bookToUpdate = allBooks.Find(b => b.ISBN == searchISBNTextBox.Text);

It finds a book from the allBooks list that matches the given ISBN and
assigns the found book to the bookToUpdate variable.
The statement uses a C# technique called Lambda, with the symbol =>. It is a
shorthand way to write a method. On the left side of the => is like an input to
a method (parameter list). On the right side of the => is the output of the
method (method body). In the above Lambda expression, it will accept a
book from allBooks, one at a time, and return a Boolean value by comparing
the given book’s ISBN to the user typed in ISBN. If the two ISBNs match, it
returns the true value. Otherwise, return the false value. Based on the
Boolean value, the Find() method determines which value of the allBooks list
to keep.
Finally, make the “Close and Save” button on UpdateBookForm work.
Have the UpdateBookForm in design view. Double click on the “Close and
Save” button and add the following code:

private void closeFormButton_Click( object sender, EventArgs e)


{
using (StreamWriter sw = File.CreateText( "books.txt" ))
{
//foreach (string aBook in allBooks)
foreach (Book aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
Close();
}

Save and run the program. You can update any book. Use “display all books”
feature to check if the application works as expected.
Splendid. This is a long mission, but most statements are similar to the “Add
new book” feature. In this mission, you learned how to retrieve data from a
text file and put them into objects (books in our case) instead of just working
with a string as you learned in displaying all books mission. With all books in
a list of Book objects, it is much easier to handle them. You have also learned
Lambda expressions to find a book from the allBooks list. The concise code
of a Lambda maybe difficult to understand at first, but it will be your friend
when you become a developer.
Take a break to cool down the computer before you continue on Mission 19.
MISSION 19: GRAPHICAL
USER INTERFACE (GUI)
DELETE A BOOK
Sometimes it is necessary to delete a book from the system.
Your task in this mission is to add a feature that allows a user to delete a book
by its ISBN.
Open the project from the previous mission in Visual Studio to continue.
Go to “Solution Explorer” window. Double click on Form1.cs to open it in
design view. Add a button to the form. Set the (Name) property of the button
to “deleteButton” and the Text property of the button to “Delete a book”

Go to “Solution Explorer” window. Add a new form to the project. Name it


“DeleteBookForm.cs”.
Go to the DeleteBookForm in design view. Add 2 label controls, 1 textbox
control, 3 button controls, and 1 listBox control to the form.
Set properties by following the table below (Empty cell indicates no changes
necessary):

Controls Text property (Name) property


Label1 Enter an ISBN
Label2 Book details
TextBox1 searchISBNTextBox
Button1 Search SearchButton
Button2 Delete deleteButton
Button3 Close and Save closeButton
ListBox1 bookDetailsListBox

The completed form looks like this:


Start coding.
Go back to the Form1 in design view. Double click on the “Delete a book”
button to generate the button-click event handler and add the following code:
private void deleteButton_Click( object sender, EventArgs e)
{
DeleteBookForm deleteBookForm = new DeleteBookForm();
deleteBookForm.ShowDialog();
}

Next, go to the DeleteBookForm in design view. You want to retrieve the


book data from the text file into a list when the form loads. Double click any
empty space, but not on any controls, on the form to generate form loads
event handler. Add the following code (Note the List of allBooks is declared
outside the handler so that the list can be used in other handlers. Also don’t
forget using System.IO;):
List<Book> allBooks = new List<Book>();
private void DeleteBookForm_Load( object sender, EventArgs e)
{
using (StreamReader sr = new StreamReader( "books.txt" ))
{
string title;
while ((title = sr.ReadLine()) != null )
{
title = getContent(title);
List< string > allAuthors = new List< string >();
string author = "" ;
while ((author = sr.ReadLine()).Substring(0, 6)
== "Author" )
{
author = getContent(author);
allAuthors.Add(author);
}
string isbn = getContent(author);
string language = getContent(sr.ReadLine());
string genre = getContent(sr.ReadLine());
int year = int .Parse(getContent(sr.ReadLine()));
int pages = int .Parse(getContent(sr.ReadLine()));
double price =
double .Parse(getContent(sr.ReadLine()));
int totalCopies =
int .Parse(getContent(sr.ReadLine()));
int availableCopies =
int .Parse(getContent(sr.ReadLine()));
Book newBook = new Book(title, allAuthors, isbn,
language, genre, year, pages, price,
totalCopies, availableCopies);
allBooks.Add(newBook);
}
}
}
private string getContent( string str)
{
int position = str.IndexOf( ": " );
return str.Substring(position + 2);
}
The above code is the same as the one in UpdateBookForm.
Next, still with the DeleteBookForm in design view, double click on the
“Search” button to generate the button click event handler. Add the code
(Note a variable is declared outside the handler):
bool isFound = false ;
private void searchButton_Click( object sender, EventArgs e)
{
foreach (Book book in allBooks)
{
if (book.ISBN == searchISBNTextBox.Text)
{
isFound = true ;
bookDetailsListBox.Items.Clear();
bookDetailsListBox.Items.Add( "Title: " + book.Title);
foreach ( string author in book.Authors)
{
bookDetailsListBox.Items.Add( "Author:" +author);
}
bookDetailsListBox.Items.Add( "ISBN: " +book.ISBN);
bookDetailsListBox.Items.Add( "Language: " +
book.Language);
bookDetailsListBox.Items.Add( "Genre: " + book.Genre);
bookDetailsListBox.Items.Add( "Year: " +
book.CopyrightYear);
bookDetailsListBox.Items.Add( "Pages: " + book.Pages);
bookDetailsListBox.Items.Add( "Price: " + book.Price);
bookDetailsListBox.Items.Add( "Total Copies: " +
book.TotalCopies);
bookDetailsListBox.Items.Add( "Available Copies: " +
book.AvailableCopies);
}
}

if (!isFound)
{
bookDetailsListBox.Items.Clear();
bookDetailsListBox.Items.Add( "No book ISBN found." );
}
}

Again, the code is very similar to the one in UpdateBookForm corresponding


search feature. The added feature is to send feedback to the user if a search
fails to find a book with that ISBN. You may use the code to update the
UpdateBookForm search feature in the previous mission for practice.
Note that the following line is declared outside of the event handler because
the variable will be used in another event handler (the delete event handler
coming up next):
bool isFound = false ;

To make the “Delete” button work, double click on the “Delete” button and
add the following code:
private void deleteButton_Click( object sender, EventArgs e)
{
if (isFound)
{
allBooks.RemoveAll(b => b.ISBN ==
searchISBNTextBox.Text);
MessageBox.Show( "The book is deleted." );
bookDetailsListBox.Items.Clear();
isFound = false ;
}
else
{
MessageBox.Show( "No books to delete!" );
}
}

Another Lambda expression is used in the above code. The RemoveAll()


method of a list will remove all elements with the true value returned from
the Lambda expression.
Finally, you want to make the “Close and Save” button work. Double click
on the “Close and Save” button to generate the click event handler. Add the
following code:
private void closeButton_Click( object sender, EventArgs e)
{
using (StreamWriter sw = File.CreateText( "books.txt" ))
{
//foreach (string aBook in allBooks)
foreach (Book aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
Close();
}

Save and run the program.


Fabulous! In this mission, you have learned how to use a Boolean variable to
control the flow of statements. You have also seen another example of using
Lambda expression. Finally, you have learned how to use RemoveAll()
method to remove certain elements from a list.
Take a break to cool down the computer before you continue on Mission 20
MISSION 20: GRAPHICAL
USER INTERFACE (GUI)
CHECK OUT A BOOK
The application can add a new book, display all books, update a book, and
delete a book. Can you add a feature for checking out a book? When a user
checks out a book, the system should deduct the available copies of the book
by one.
Your task in this mission is to add a checkout feature to the application.
Have the project open in Visual Studio. Go to the “Solution Explorer”
window, double click on Form1.cs to open the file in design view. Add a
button to the form. Set the button’s (Name) property to checkoutButton and
the Text property to Checkout a book.

Go to the “Solution Explorer” window. Add a new form called


CheckoutForm.cs to the project.
Add two label controls, one textbox control, one listbox control, and three
button controls to the CheckoutForm.

Set properties for the controls by following the table below (Empty cell
indicates no changes necessary):

Controls Text property (Name) property


Label1 Enter title
Label2 Books contain the title
TextBox1 searchTitleTextBox
Button1 Search searchButton
Button2 Checkout checkoutButton
Button3 Close and Save closeButton
ListBox1 booksListBox

The completed form looks like this:


Note: If your booksListBox is not wide enough, not all book information may
be shown. You can add a horizontal scroll bar to the listbox by setting
HorizontalScrollBar property of the booksListBox control from the default
“false” to “true”. You can double click on the property “false” to
automatically change it to “true” (no difference shown in the form design
view. You will see the horizontal scroll bar at run time if your text is wider
than the provided space.).

Start coding.
Start from Form1.cs in design view. Double click on the “Checkout a book”
button and add the following code:
private void checkoutButton_Click( object sender, EventArgs e)
{
CheckoutForm checkoutForm = new CheckoutForm();
checkoutForm.ShowDialog();
}

When the CheckoutForm loads, you want to retrieve the books from the text
file and load them into a list.
Go to the CheckoutForm in design view. Double click on any empty space on
the form to generate the form loads event handler. Add the code below
(again, the allBooks list is declared outside the form load event handler):
List<Book> allBooks = new List<Book>();
private void CheckoutForm_Load( object sender, EventArgs e)
{
using (StreamReader sr = new StreamReader( "books.txt" ))
{
string title;
while ((title = sr.ReadLine()) != null )
{
title = getContent(title);
List< string > allAuthors = new List< string >();
string author = "" ;
while ((author = sr.ReadLine()).Substring(0, 6)
== "Author" )
{
author = getContent(author);
allAuthors.Add(author);
}
string isbn = getContent(author);
string language = getContent(sr.ReadLine());
string genre = getContent(sr.ReadLine());
int year = int .Parse(getContent(sr.ReadLine()));
int pages =
int .Parse(getContent(sr.ReadLine()));
double price =
double .Parse(getContent(sr.ReadLine()));
int totalCopies =
int .Parse(getContent(sr.ReadLine()));
int availableCopies =
int .Parse(getContent(sr.ReadLine()));
Book newBook = new Book(title, allAuthors, isbn,
language, genre, year, pages, price,
totalCopies, availableCopies);
allBooks.Add(newBook);
}
}
}
private string getContent( string str)
{
int position = str.IndexOf( ": " );
return str.Substring(position + 2);
}

The above code is the same as you see in earlier missions.


Back to the CheckoutForm in design view. Double click on the “Search”
button to generate the button click-event handler. This activity will search for
any books containing the search string. The result will be displayed in the
booksListBox below it on the form.
private void searchButton_Click( object sender, EventArgs e)
{
List<Book> booksFound = new List<Book>();
booksFound = allBooks.Where(b =>b.Title.ToUpper().
Contains(searchTitleTextBox.Text.ToUpper())).ToList();
booksListBox.Items.Clear();
foreach (Book book in booksFound)
{
string bookstring = book.ToString().Replace( "\n" , " " );
booksListBox.Items.Add(bookstring);
}
}

The above code is similar to the search code in previous missions. But this
time, you don’t search by ISBN. You search for any titles that contain the
search string. Both the search string and the book title are converted to all
upper case by the prebuilt ToUpper() method. As a result, you don’t need to
worry about the case.
In the above code, you also see a Where() method of list (IEnumerable to be
exact). For beginners, you can treat Where() the same as Find() method of a
list. It will return all elements that meet the condition.
Next, make the checkout button on CheckoutForm work.
Go to CheckoutForm in design view. Double click on the checkout button.
You want to deduct the available copy of the book by one if the number is
more than 0. Otherwise, display a message that no copies of the book are
available.
private void checkoutButton_Click( object sender, EventArgs e)
{
if (booksListBox.SelectedIndex != -1)
{
string selectedBook = booksListBox.SelectedItem.ToString();
int isbnStartPosition = selectedBook.IndexOf( "ISBN: " ) + 6;
int isbnEndPosition = selectedBook.IndexOf( "Language: " ) -2;
int isbnLength = isbnEndPosition - isbnStartPosition + 1;
string isbn = selectedBook.Substring(isbnStartPosition,
isbnLength);

int availableCopiesPosition =
selectedBook.IndexOf( "Available Copies: " );
int availableCopies =
int .Parse(selectedBook.Substring(availableCopiesPosition +
17));
if (availableCopies > 0)
{
Book bookToCheckout = allBooks.Find(b => b.ISBN == isbn);
bookToCheckout.AvailableCopies--;
MessageBox.Show( "Checkout completed." );
searchButton_Click( this , e);
}
else
{
MessageBox.Show( "No copies available" );
}
}
else
{
MessageBox.Show( "You must select a book to checkout." );
}
}

One business logic in the above code is to find the length of a string from a
certain position to another certain position in order to retrieve the number for
available copies.
Given the following string:
abcdefg
What is the length of the substring from position index of 2 to position index
of 5? Remember to count from zero. If we include the position of 5, the
answer is 4 (cdef). If you don’t include the position of 5, the answer is 3
(cde). The formula is ending position minus starting position plus 1.
Why does the following statement have a plus 6?
int isbnStartPosition = selectedBook.IndexOf( "ISBN: " ) + 6;

It is because the value from IndexOf is the position of “I” in “ISBN: “. Plus 6
to move the start position from “I” to the one right after the space in “ISBN:
“.
The following statement:
bookToCheckout.AvailableCopies--;

Decrease the AvailableCopies property value by 1. The -- is a decrement


operator. It is used after a variable will decrease the value of the variable by
1. This is a convenience way to reduce a variable value by 1. It is the same as
the following statement:
bookToCheckout.AvailableCopies =
bookToCheckout.AvailableCopies- 1;

Finally, make the “Save and Close” button on CheckoutForm work. Double
click on the “Save and Close” button to add code:
private void closeButton_Click( object sender, EventArgs e)
{
using (StreamWriter sw = File.CreateText( "books.txt" ))
{
foreach (Book aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
Close();
}
Save and run the program.
Fantastic! In this mission you have learned the Where() method of a list and
apply complex business logic into the application.
Take a break to cool down the computer before you continue on Mission 21.
MISSION 21: GRAPHICAL
USER INTERFACE (GUI)
RETURN A BOOK
Returning a book is very similar to checking out a book. The user interface is
the same except that the “checkout” button is replaced with a “return” button.
The user searches for a book by its title. All books contain the search string
are displayed in a listbox. Then the user selects a book from the listbox and
clicks on the “return” button to return it. The result of returning a book is to
increase the available copies by one. The available number copy should never
be greater than the total copies.
Your task in this mission is to allow a user to return a book.
Have the Tiny Library Windows Forms Application (Mission 20) open in
Visual Studio. Go to Form1 in design view. Add a button. Set its (Name)
property to returnBookButton and its Text property to “Return a book”. Add
another button. Set its (Name) property to exitButton and its Text property to
“Exit”. The Form1 now looks like this:
Go to “Solution Explorer” window. Add a form named “ReturnBookForm”.
Add two label controls, three button controls, one textbox, and one listbox to
the form.

Set properties for the controls by following the table below:

Controls Text property (Name) property


Label1 Enter title
Label2 Books contain the title
TextBox1 searchTitleTextBox
Button1 Search searchButton
Button2 Return book returnButton
Button3 Close and Save closeButton
ListBox1 booksListBox

The completed form looks like this:

Note: If your booksListBox is not wide enough, not all book information may
be shown. You can add a horizontal scroll bar to the listbox by setting its
HorizontalScrollBar property from the default “false” to “true”.

Start coding.
Start from Form1.cs in design view. Double click on the “Return a book”
button on Form1 and add the code below:
private void returnBookButton_Click( object sender,
EventArgs e)
{
ReturnBookForm returnBookForm = new ReturnBookForm();
returnBookForm.ShowDialog();
}
Still with Form1 in design view, double click on the “Exit” button and add
the code below:
private void exitButton_Click( object sender, EventArgs e)
{
Close();
}

Go to the ReturnBookForm in design view. Double click on any empty space


on the form. Add the following code. Note the allBooks List is outside the
event handler (Remember to add using System.IO; directive):

List<Book> allBooks = new List<Book>();


private void ReturnBookForm_Load( object sender, EventArgs e)
{
using (StreamReader sr = new StreamReader( "books.txt" ))
{
string title;
while ((title = sr.ReadLine()) != null )
{
title = getContent(title);
List< string > allAuthors = new List< string >();
string author = "" ;
while ((author = sr.ReadLine()).Substring(0, 6)
== "Author" )
{
author = getContent(author);
allAuthors.Add(author);
}
string isbn = getContent(author);
string language = getContent(sr.ReadLine());
string genre = getContent(sr.ReadLine());
int year = int .Parse(getContent(sr.ReadLine()));
int pages = int .Parse(getContent(sr.ReadLine()));
double price =
double .Parse(getContent(sr.ReadLine()));
int totalCopies =
int .Parse(getContent(sr.ReadLine()));
int availableCopies =
int .Parse(getContent(sr.ReadLine()));
Book newBook = new Book(title, allAuthors, isbn,
language, genre, year, pages, price,
totalCopies, availableCopies);
allBooks.Add(newBook);
}
}
}
private string getContent( string str)
{
int position = str.IndexOf( ": " );
return str.Substring(position + 2);
}

The above code is used in several previous missions for retrieving data from
a text file.
Still with ReturnBookForm in design view. Double click on the “Search”
button and add the following code:
private void searchButton_Click( object sender, EventArgs e)
{
List<Book> booksFound = new List<Book>();
booksFound = allBooks.Where(b => b.Title.ToUpper()
.Contains(searchTitleTextBox.Text.ToUpper())).ToList();
booksListBox.Items.Clear();
foreach (Book book in booksFound)
{
string bookstring = book.ToString().Replace( "\n" , " " );
booksListBox.Items.Add(bookstring);
}
}

The above code is the same as that in CheckoutForm search feature.


Save and run the program. On return book form, you should be able to search
for a title, But you cannot return a book yet.
Still within the return book form, double click on the “Return book” button
and add the following code:
private void returnButton_Click( object sender, EventArgs e)
{
if (booksListBox.SelectedIndex != -1)
{
string selectedBook = booksListBox.SelectedItem.ToString();
int isbnStartPosition = selectedBook.IndexOf( "ISBN: " ) + 6;
int isbnEndPosition = selectedBook.IndexOf( "Language: " )-2;
int isbnLength = isbnEndPosition - isbnStartPosition + 1;
string isbn = selectedBook.Substring(isbnStartPosition,
isbnLength);
int availableCopiesPosition =
selectedBook.IndexOf( "Available Copies: " );
int availableCopies =
int .Parse(selectedBook.Substring(availableCopiesPosition
+ 17));
int totalCopiesStartPosition =
selectedBook.IndexOf( "Total Copies: " ) + 14;
int totalCopiesEndPosition = availableCopiesPosition - 2;
int totalCopiesLength = totalCopiesEndPosition -
totalCopiesStartPosition + 1;
int totalCopies =
int .Parse(selectedBook.Substring(totalCopiesStartPosition,
totalCopiesLength));

if (availableCopies < totalCopies)


{
Book bookToCheckout = allBooks.Find(b => b.ISBN == isbn);
bookToCheckout.AvailableCopies++;
MessageBox.Show( "Return completed." );
searchButton_Click( this , e);
}
else
{
MessageBox.Show( "No copies are checked out." );
}
}
else
{
MessageBox.Show( "You must select a book to return." );
}
}

Compared to the corresponding code in CheckoutForm’s checkout feature,


there are only two differences: 1) make sure the availableCopies are less than
totalCopies before a return is possible; 2) The availableCopies increased by 1
when a book is returned.
bookToCheckout.AvailableCopies++;

Similar to the -- operator you learned in the last mission, the ++ is an


increment operator that increases a variable value by 1. The above statement
increases the AvailableCopies value by 1.
Finally, double click on the “Save and Close” button and add the code below.
using (StreamWriter sw = File.CreateText( "books.txt" ))
{
foreach (Book aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
Close();

Save and run the program.


Bravo! In this mission, you have learned the increment operator ++. The
feature of returning a book process is similar to the feature of checking out a
book. We hope you have a better understanding of the C# syntax by repeating
similar code.
Take a break to cool down the computer before you continue on Mission 22.
MISSION 22: PRINT A
RECEIPT FOR CHECKING
OUT A BOOK
When a user checks out a book, he or she may need a receipt for confirmation
purpose.
Your task in this mission is to allow a user to print a receipt for the books
checked out. All books checked out on the same checkout form before
closing can count as the same bunch by the same borrower. A receipt will
include all those books.
A receipt contains a header of “Tiny Library Receipt”, a current time stamp,
total copies checked out, and the list of ISBNs of the books.
Open the project in Visual Studio. Go to the CheckoutFomr.cs in design
view. Add a button to the form. Set the (Name) property of the button to
“printButton” and Text property of the button to “Print”. Add a
printDocument control from the ToolBox to the form. The control will not be
located as other controls on the form. It is on the bottom in the design view
window outside of the form. The area is called the component tray.

Double click on the “Print” button and add the one line code:
private void printButton_Click( object sender, EventArgs e)
{
printDocument1.Print();
}
The above statement calls the Print() method of printDocument1 control.
Before you can print the books receipt in this checkout, you need a list of
checked out books. To keep it simple, we assume all books checked out
before closing the current form are by the same borrower. Additionally, you
only list the ISBN of a book on the receipt. Add the following line (may go to
CheckoutForm in code view) anywhere inside the class, but outside any
methods. The checkoutBooks list is used to hold all books checked out in the
current form before closing the form.
List<string > checkoutBooks = new List<string >();

Then inside the checkout button click event handler, add the book isbn to the
checkoutBooks list. Right before the following line:
MessageBox.Show("Checkout completed." );

Add the statement:


checkoutBooks.Add(isbn);

Back to the designer window of the CheckoutForm, double click on the


“printDocument1” in the component tray. Inside its event handler, add the
code:

private void printDocument1_PrintPage( object sender, System.Drawing.Printing.PrintPageEventArgs e)


{
e.Graphics.DrawString( "Tiny Library Receipt" , new
Font( "Courier New" , 24, FontStyle.Bold), Brushes.Black,
200, 100);
e.Graphics.DrawString(DateTime.Now.ToString(), new
Font( "Courier New" , 18, FontStyle.Italic),
Brushes.Black, 240, 150);
int copies = checkoutBooks.Count;
e.Graphics.DrawString( "You have checked out " + copies +
(copies > 1? " books" : " book" ),
new Font( "Courier New" , 12, FontStyle.Regular),
Brushes.Black, 240, 200);
int x = 70, y = 220;
foreach ( string isbn in checkoutBooks)
{
e.Graphics.DrawString( "ISBN: " + isbn, new
Font( "Courier New" , 12, FontStyle.Regular),
Brushes.Black, x, y);
y += 15;
}
}

Save and run the program.


All printing is based on the Graphics.DrawString() method. The first
argument of the method is the string you want to print. The second argument
is the Font of your choice. The third argument is the color. The fourth
argument is the distance from the left margin you want to start the printing.
The fifth argument is the distance from the top margin you want to start the
printing.
When printing the content from a list, you use a foreach loop. Each element
prints on its own line. Do not forget to increase the y coordinate (distance
from the top of the print page) for a new line. In the example, we increase the
distance by 15 points for each new line for the font size of 12 points.
If you don’t have a printer connected or don’t want to waste paper, you may
install CutePDF Writer to serve as a printer.
Super job! In this mission, you have learned how to print data on a printer.
This is a useful technique for a real world project.
Take a break to cool down the computer before you continue on Mission 23.
MISSION 23: DON’T
REPEAT YOURSELF (DRY)
In previous missions, you may have noticed that many blocks of statements
are copied and pasted. This is easy and convenient to do, but can cause major
issues when it is time for software maintenance. For example, if you need to
make a minor change to the statements that are copied and pasted in many
places, you may not remember to update it in all locations and thus causes
some inconsistent issues that are difficult to fix.
Your task in this mission is to remove duplicated code.
To avoid messing up the application you worked so hard to develop, we
recommend that you make a copy of the Mission14 folder and rename it to
Mission23. Inside the Mission23 folder, double click on the Mission14.sln
file to open it. This way if anything goes wrong, you still have the original
Mission14 to find working code.
For most of the forms in the Tiny Library project, you need to retrieve data
from the books.txt file and put them into a list. This is the first code
duplication you may notice. The code can go into a common place and be
used many times. Such a process is often called refactoring.
First, you need to add a class to serve as this “common place”. Go to
“Solution Explorer” window. Right click on the project (C# Mission14).
Then select “Add” and finally select “Class…”.
In the “Add New Item – Mission14” popup window, name the class
“UtilityManager.cs”. Click on the “Add” button to add the class and close the
popup.
Go to the UtilityManager.cs. Add a method called RetrieveBooks with just
two lines in the method so the whole file now looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mission14
{
static class UtilityManager
{
public static List<Book> RetrieveBooks()
{
List<Book> allBooks = new List<Book>();
return allBooks;
}
}
}

Note the adding of “static” keyword to make both the class and method static.
A static method allows the use of the method without creating an instance.
This is convenient. A static class can only have static members and cannot be
instantiated. To access a member of a static class, you just use
ClassName.MemberName.
Open the “UpdateBookForm.cs” in file code view.
Go to “Solution Explorer” window, click on the UpdateBookForm.cs to
select it. Then on the top menu of the explorer window, find <> symbol and
click on it.
Cut all the code inside the UpdateBookForm_Load event handler. Paste the
code inside the RetrieveBooks() method of the UtilityManager.cs class
between the two existing lines of the statement.
List<Book> allBooks = new List<Book>();
// paste your code here.
return allBooks;

You will need the using System.IO; directive because the code includes the
prebuilt StreamReader class.
Next inside the UpdateBookForm.cs, cut the whole getContent() method and
paste it inside the UtilityManager.cs class, but outside the RetrieveBooks()
method. You may notice that the sequence of methods inside a class does not
matter because they are not executed like statements. A method has to be
called to execute all statements inside it.
After pasting getContent(), add a keyword “static” (no quotation marks) right
after the “private” keyword in the method header. This is because the
getContent() method is used in a static method RetrieveBooks(). Only a static
method can be used in another static method.
The completed UtilityManager.cs file now looks like this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mission14
{
static class UtilityManager
{
public static List<Book> RetrieveBooks()
{
List<Book> allBooks = new List<Book>();
using (StreamReader sr = new
StreamReader( "books.txt" ))
{
string title;
while ((title = sr.ReadLine()) != null )
{
title = getContent(title);
List< string > allAuthors = new
List< string >();
string author = "" ;
while ((author = sr.ReadLine())
.Substring(0, 6) == "Author" )
{
author = getContent(author);
allAuthors.Add(author);
}
string isbn = getContent(author);
string language =
getContent(sr.ReadLine());
string genre = getContent(sr.ReadLine());
int year =
int .Parse(getContent(sr.ReadLine()));
int pages =
int .Parse(getContent(sr.ReadLine()));
double price =
double .Parse(getContent(sr.ReadLine()));
int totalCopies =
int .Parse(getContent(sr.ReadLine()));
int availableCopies =
int .Parse(getContent(sr.ReadLine()));
Book newBook = new Book(title, allAuthors,
isbn, language, genre, year, pages,
price, totalCopies, availableCopies);
allBooks.Add(newBook);
}
}
return allBooks;
}
private static string getContent( string str)
{
int position = str.IndexOf( ": " );
return str.Substring(position + 2);
}
}
}

Go back to the UpdateBookForm.cs in code view. Add a line of code inside


the UpdateBookForm load event handler (Remember all code of the method
body was cut out earlier in this mission):
private void UpdateBookForm_Load( object sender, EventArgs e)
{
allBooks = UtilityManager.RetrieveBooks();
}

Save and run the program. You should not see any differences.
To call a static method, you just use classname.methodname as:
UtilityManager.RetrieveBooks();

You want to do the same for the DeleteBookForm.cs, because you already
created the RetrieveBooks() method. This time, you just delete the duplicated
code and use the RetrieveBooks() method in the DeleteBookForm.cs.
Go to the DeleteBookForm.cs in code view. Replace the content of the
DeleteBookForm load event handler with the following line:
private void DeleteBookForm_Load( object sender, EventArgs e)
{
allBooks = UtilityManager.RetrieveBooks();
}

Also remove the getContent() method in the DeleteBookForm.cs completely.


Save and run the program.
Can you see how much code is saved? More savings come up next.
Update the CheckoutForm.cs to take the advantage of existing
RetrieveBooks() method.
Go to the CheckoutForm.cs in code view. Replace the form load-event
handler content with a single line
allBooks = UtilityManager.RetrieveBooks();

And remove the getContent() method completely.


You can do the same for ReturnBookForm.cs. Go to the ReturnBookForm.cs
in code view. Do the same as you do with the CheckoutForm.cs.
Save and run the program.
Similarly, you can add a method called Save() to the UtilityManager.cs class.
Call the method from every form that saves a list of books to the text file.
Specifically, add the Save() method to the UtilityManager.cs with the
following statements (Inside the class but outside any other methods):
public static void Save(List<Book> allBooks)
{
using (StreamWriter sw = File.CreateText( "books.txt" ))
{
//foreach (string aBook in allBooks)
foreach (Book aBook in allBooks)
{
sw.WriteLine(aBook);
}
}
}

The content can be cut from UpdateBookForm.cs. Replace the content of


CloseFormButton click event hander in the UpdateBookForm.cs with the
following:
private void closeFormButton_Click( object sender, EventArgs e)
{
UtilityManager.Save(allBooks);
Close();
}

Do the same for DeleteBookForm.cs, CheckoutForm.cs, and


ReturnBookForm.cs.
Take a Bow! In this lesson, you have learned how to avoid duplicated code
by writing a static method. You write a method once and use it in four places.
If you explore the code in the project in greater detail, you may find other
places that you can reduce duplication and make the code easier to
understand.
Take a break to cool down the computer before you continue on Mission 24.
MISSION 24: PRACTICE,
PRACTICE, PRACTICE

Practice is the best way to learn C#.


Your task in this mission is to create a simple windows forms application for
employee payroll. The specific requirements are listed in the rest of the
mission.
Create a Windows Forms application that allows the user to enter employee
payroll information. It allows the user to enter a new employee, add hours
worked, and display all employee payment information. A sample MainForm
is shown here.
You will need a label and four buttons for the main form .

If the user clicks on the “Add New” button, a new form is displayed as shown
below. This form uses a new control called GroupBox for organization
purposes. The form also needs three label controls, three textbox controls and
three button controls.

The save button on the form will save the new employee into a text file,
employee.txt, in the default debug folder. The Clear button will clear the
form and the Close button will close the form.

Back to the MainForm in design view, if the “Add Hours” button is clicked, a
new form is displayed. This form also uses a GroupBox control, three label
controls, three textbox controls, and three button controls.
The first two of the three TextBoxes on the right column are “readonly”. Set
their ReadOnly property to true. A read only textbox will not accept user
input. They are used in the form for displaying employee data.

When the “Add Hours Worked” form loads, the first employee from
employee.txt should be displayed. Then the user enters hours worked and
clicks on the “next” button. The hours worked should be added to the
employee in the List, and the second employee data is displayed and expects
the user to enter hours worked. When all hours worked data are entered, a
pop up will display “no more employees.” The user can then click on the
“Close” button, which will close the form and save all data from the list to
the same employee.txt file. For each employee, only the most recent hours
worked data is saved in the employee.txt file. In other words, each employee
has only one hours worked data.

Back to the MainForm in design view, when the Display All button is
clicked, the following form will be displayed. This form includes one listbox
and two button controls.
The “Print” button on the form will print all employee data in a nicely
formatted way on paper. The “Close” button will close the form.

Back to the main form in design view, the “Exit” button will exist the
program.
You are not expected to complete this project without any references. You
can go back to the earlier missions and copy and paste code.
Congratulations, and thank you for reading this book. Enjoy coding.

You might also like