People who are old like me cut our teeth in the world of DOS. It is often something we all wish never evolved into Windows. DOS was very easy to work in. It was also very limiting.
Anyway, enough nostalgia. How many of you have written small utility programs? I know I have written a whole host of them. I often like to write small programs without a Windows interface. It makes the program smaller and consequently faster.
Back when I started out programming, writing windowless programs was called a living. Now they are called console applications. Few people can make a living these days writing just console applications. These applications do have their uses, though, and you should be aware of how to write them.
C and C++ programmers have always enjoyed the ability of writing console applications. VB programmers never could. The most common use for console applications these days is as debugging screens for a program. Often console applications are meant to be used only by those who wrote them or those with a great deal of technical knowledge about what they are doing.
The following example transfers the employee list screen from the last example to a console program. This program is tiny and has only one function, but it gives you an idea of how to get data from a user, validate it, and display some results. This is all easy in a Windows program, but you need a slightly different plan of attack when you write a console program.
First, start a new VB or C# console project. Mine is called "Console." Listings 2-5a and 2-5b show the code for this program.
using System; using System.Collections; namespace Console_c { /// <summary> /// Console application for simple data entry /// </summary> class Class1 { [STAThread] static void Main(string[] args) { bool ByEmp = false; SortedList Emps = new SortedList(); Emps.Add("500", "Person A"); Emps.Add("502", "Person B"); Emps.Add("501", "Person C"); Emps.Add("503", "Person D"); Console.WriteLine("Welcome to the Console Application for Data Entry.\n"); while(true) { Console.WriteLine("Enter the sort key for employees."); Console.WriteLine("\n'N' for Sort by name, " + "'C' for Sort by clock #, 'X' to exit program."); string SortOrder = Console.ReadLine(); if(SortOrder.ToUpper() == "N" ) { ByEmp = true; break; } else if(SortOrder.ToUpper() == "C" ) { ByEmp = false; break; } else if(SortOrder.ToUpper() == "X" ) return; else { Console.WriteLine("Only 'N' for Sort by name, " + "'C' for Sort by clock # is allowed." + " ('X' to exit program)"); Console.WriteLine("\n\n"); } } SortedList PrintEmp = new SortedList(); string Header = ByEmp ? "\tNames\t Clock #" : "\tClock #\t Names"; for(int k=0; k<Emps.Count; k++) { if(ByEmp) PrintEmp.Add(Emps.GetByIndex(k), Emps.GetKey(k)); else PrintEmp.Add(Emps.GetKey(k), Emps.GetByIndex(k)); } Console.WriteLine("\n{0}", Header); Console.WriteLine("\t--------------------"); for(int k=0; k<PrintEmp.Count; k++) { Console.WriteLine("\t{0}\t{1}", PrintEmp.GetKey(k), PrintEmp.GetByIndex(k)); } Console.ReadLine(); } } }
Module Module1 Sub Main() Dim ByEmp As Boolean = False Dim Emps As SortedList = New SortedList() Emps.Add("500", "Person A") Emps.Add("502", "Person B") Emps.Add("501", "Person C") Emps.Add("503", "Person D") Console.WriteLine("Welcome to the Console Application for Data Entry.\n") While (True) Console.WriteLine("Enter the sort key for employees.") Console.WriteLine("\n'N' for Sort by name, " + _ "'C' for Sort by clock #, 'X' to exit program.") Dim SortOrder As String = Console.ReadLine() If (SortOrder.ToUpper() = "N") Then ByEmp = True Exit While ElseIf (SortOrder.ToUpper() = "C") Then ByEmp = False Exit While ElseIf (SortOrder.ToUpper() = "X") Then Return Else Console.WriteLine("Only 'N' for Sort by name, " + _ "'C' for Sort by clock # is allowed." + _ " ('X' to exit program)") Console.WriteLine("\n\n") End If End While Dim PrintEmp As SortedList = New SortedList() Dim Header As String = _ IIf(ByEmp, "\tNames\t Clock #", "\tClock #\t Names") Dim k As Int32 For k = 0 To Emps.Count - 1 If (ByEmp) Then PrintEmp.Add(Emps.GetByIndex(k), Emps.GetKey(k)) Else PrintEmp.Add(Emps.GetKey(k), Emps.GetByIndex(k)) End If Next Console.WriteLine("\n{0}", Header) Console.WriteLine("\t--------------------") For k = 0 To PrintEmp.Count - 1 Console.WriteLine("\t{0}\t{1}", PrintEmp.GetKey(k), _ PrintEmp.GetByIndex(k)) Next Console.ReadLine() End Sub End Module
As you can see from the program, I am in an infinite loop waiting for a key press from the user. This key press needs to be followed by a carriage return before the ReadLine() function returns. I then decide how to format the output based on what the user pressed.
One of the common things I see new programmers doing when testing for a character or string is either testing only for one case or testing for both upper- and lowercase. What I do here is convert the character to uppercase and only test for that. It uses less code and is not as subject to error.
One other thing I would like to bring your attention to is the type of collection I use. I use a SortedList to hold both the original information and to hold the displayable information.
The .NET Framework has a wide selection of collection classes. I suggest strongly that you become familiar with them. I use a specialized collection class in this example because it removes a lot of the work I would normally need to do.
I could have used a simple multidimensional array like I did in the Windows version of this program. The reason I chose the SortedList is because it holds a key-value pair and it automatically sorts on the key. I used the simple array in the Windows version because for display purposes I put the information in a ListView control, which did the sorting for me.
Remember a while back when I said that I like defining some controls directly in code rather than placing them on the form itself? One of the reasons for this is that I can use some capability of the control that I would otherwise have to program myself.
It is not a hard stretch to rewrite this console application so that I use a ListView control as the vehicle to hold the sorted information. I could then go back to using a simple multidimensional array for the original employee list. I would use the ListView control to sort the information for me, and then I could extract the information as I printed it on the screen. The user never sees this invisible control.
Like anything else in .NET, however, the ListView control inherits quite a bit of functionality from parent classes and also includes a specialized collection. Why go overboard with all the features of the ListView control when you can implement a standard specialized collection, as I do in this example?
By the way, VB 6.0 programmers should definitely be at home with collections and the foreach construct. Although the collections provided in C# are not in the same form (more methods and properties) as the VB collection, they serve the same purpose. If you are a VB 6.0 programmer and you want to use the VB 6.0 type of collection, you can. VB .NET has a collection object that is identical to the VB 6.0 collection object. If you are a VB 6.0 programmer and you want to transfer over to C#, you will need to write a collection class that wraps up a SortedList and exposes the familiar four properties of a VB 6.0 collection:
Add
Remove
Count
Item (you will need to implement an iterator for this)