Wednesday, September 2, 2009

Code4Food #1: Frank Car Assistant application.

Hi! There are a lot of situations when you as a programmer need to code just for 5 bucks. Of course you don't have to put your soul in these kind of programs, if you don't want to, but remember if you will make a nice piece of code, which will satisfy all client's requirements, you will definitely be able to buy some caviar as a bonus to your butter and bread. Ladies and gents, Code4Food series is starting. Yesterday I was talking to my online friend Frank. He already studied Java programming language so I thought I should presented him C# language, writing down some simple examples. I'm gonna try to present you the same thing using the same examples. Here is the sourcecode for Downloading: FrankTestConsoleApp sourcecode FrankCarAssistant sourcecode

"Hello World"

So first program is like always HelloWorld 1. File -> New -> Project 2. Choose Project types -> Visual C# -> Windows -> In templates choose Console Application 3. Choose a name for your project. In my case I chosen the name FrankTestConsoleApp. In Program.cs file we will have the following thing:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FrankTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!!!");

            Console.ReadKey();
        }
    }
}
Another thing that I was showing was some loops from C#. We first create an array of strings and than we call each string using different loops.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FrankTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = { "Frank", "Timur", "Jessica", "Helen" };

            Console.WriteLine("=======FOR loop=========");

            for (int i = 0; i < names.Length; i++)
            {
                Console.WriteLine("Hello {0}!", names[i]);
            }

            Console.WriteLine("=======FOREACH loop=========");

            foreach (string name in names)
            {
                Console.WriteLine("Hello {0}!", name);
            }

            Console.WriteLine("=======WHILE loop=========");

            int index = 0;

            while (index < names.Length)
            {
                Console.WriteLine("Hello {0}!", names[index]);
                index++;
            }

            Console.ReadKey();
        }
    }
}
So the result is the same for each loop.

Car class

The next thing we did was creating a Class Library Project CarsModel. 1. File -> New -> Project 2. Choose Project types -> Visual C# -> Windows -> In templates choose Class Library When you create a Class Library project it means that all the classes which will be in this project will be built into a single .DLL file. A DLL file can contain multiple namespaces. In this project we created a class Car which contains 2 properties: int WheelNumber and a string Name, and a method PrintInfo, and 2 constructors. A property is a public accessor to a private field of the class. This is an analog for Java's get and set methods. For example: we have a private field _wheelsNumber which can be accessed by other classes using the WheelNumber property. A property can have 2 parts get and set. When you have in your property the get part it means that the other class can read the value of your private field. The set part of the property allows to set a value for the private field of the class. In fact when you read a property (ex.: int numberOfCars = car.WheelNumber) everything inside the get part is executed (in our case it's get { return _wheelsNumber; }). When you write a value into a property (ex.: car.WheelNumber = 3) everything inside the set part is executed. You can have properties with only get or only set part. It means that you can only read or write into this property. The PrintInfo method was only used for printing to our console the Car data (name and wheels number). By creating this method into the Car class we made it possible to call this method from the class instance (ex.: car.PrintInfo()). This way of programming is called to delegate to an object a method, usually it is used when you refactor your old code and you see that a method only uses the instance of a class, for example X. It is than logically to move this method into the class X itself, than you can simple call x.RefactoredMethod() In this class we also have 2 constuctors with and without parameters. The constructor with parameters initializes the properties of this class. The default constructor (without parameters) initializes the properties with its default values (for int it is 0, and for string it's string.Empty).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CarsModel
{
    public class Car
    {
        private int _wheelsNumber = 0;

        public int WheelNumber
        {
            get { return _wheelsNumber; }
            set { _wheelsNumber = value; }
        }

        private string _name = string.Empty;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public Car()
        {

        }

        public Car(int wheelz, string carName)
        {
            this.WheelNumber = wheelz;
            this.Name = carName;
        }

        public void PrintInfo()
        {
            Console.WriteLine(this.Name);
            Console.WriteLine(this.WheelNumber);
            Console.WriteLine("=================");
        }
    }
}

Frank Car Assistant Console Application

Than we build the project and added its DLL file to the references of the FranksTestConsoleApp, and made a little console application which I'm gonna try to explain.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CarsModel;

namespace FrankTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Car> listCar = new List<Car>();

            Car franksCar = new Car(2, "Honda Civic");
            Car timurCar = new Car(1, "4x4");

            listCar.Add(franksCar);
            listCar.Add(timurCar);
            listCar.Add(new Car(14, "Jessica"));

            bool iWantToLeave = false;

            while (!iWantToLeave)
            {
                Console.WriteLine(Environment.NewLine);

                PrintHelp();

                Console.WriteLine(Environment.NewLine);

                int numberEntered = int.Parse(Console.ReadLine());

                switch (numberEntered)
                {
                    case 2: RemoveCarFromList(listCar);
                        break;
                    case 3: listCar.Add(AddNewCar());
                        break;
                    case 4: iWantToLeave = true;
                        break;
                    default: ShowMeTheCars(listCar);
                        break;
                }
            }

            Console.WriteLine("Bye");

            Console.ReadKey();
        }

        /// 
        /// Prints the current list of cars.
        /// 
        /// The lists of cars.
        private static void ShowMeTheCars(List<Car> listCar)
        {
            Console.WriteLine(Environment.NewLine);

            foreach (Car carName in listCar)
            {
                carName.PrintInfo();
            }
        }

        /// 
        /// Prints the help.
        /// 
        private static void PrintHelp()
        {
            Console.WriteLine("This is the Frank car system assistant");
            Console.WriteLine("PRESS");
            Console.WriteLine("1 - To see the list of the cars");
            Console.WriteLine("2 - To remove a car from the list");
            Console.WriteLine("3 - To add a car to the list of the cars");
            Console.WriteLine("4 - To say 'Bye'");
        }

        /// 
        /// Adds the new car.
        /// 
        /// The new car object
        private static Car AddNewCar()
        {
            Console.WriteLine("Enter the name of the car: ");
            string name = Console.ReadLine();
            Console.WriteLine("Enter the number of wheels: ");
            int number = int.Parse(Console.ReadLine());

            return new Car(number, name);
        }

        /// 
        /// Removes the car from list.
        /// 
        /// The list of cars.
        private static void RemoveCarFromList(List<Car> listCar)
        {
            string nameOfTheCar = Console.ReadLine();

            Car searchedCar = listCar.Find(delegate(Car car) { return car.Name == nameOfTheCar; });

            if (searchedCar == null)
            {
                Console.WriteLine("ERROR! We don't have this car, really, don't try to find it.");
                return;
            }

            listCar.Remove(searchedCar);
        }

    }
}
So first I'm gonna explain what this application is doing. So it can print you the help menu and depending on the part you select, it can show the list of cars available with it's characteristics, add a new car or remove a car with a certain name. The PrintHelp method only prints some bunch of strings. In the beggining of our Main method what we do is initialize a List of our object Car from CarsModel namespace, and we add some custom cars in it.
List<Car> listCar = new List<Car>();

Car franksCar = new Car(2, "Honda Civic");
Car timurCar = new Car(1, "4x4");

listCar.Add(franksCar);
listCar.Add(timurCar);
listCar.Add(new Car(14, "Jessica"));
In the AddNewCar method we create a new car by entering its name and the number of the wheels for this particular car and than return this car. ShowMeTheCars method calls for each Car object from a list of cars (listCar) its method PrintInfo(). The most interesting method is RemoveCarFromList method. What I am doing there is trying to show the power of List objects in C#. Firstly we have a Find method in List object which permits us to find an object from the list which satisfy a specified condition. Car searchedCar = listCar.Find(delegate(Car car) { return car.Name == nameOfTheCar; }); In this example the condition is that the name of the car which we indicated (nameOfTheCar) should coincide with the car's name from the list (car.Name). And for formulating it we create a delegate with the list's object as an argument which should return a boolean value (true or false), according to specified condition. Than in Main method we create a boolean field iWantToLeave = false, and we will loop, while we'll want to leave. Firstly we'll call PrintHelp method, than we'll parse the introduced number, and will pass this number in a switch statement, and treat each case apart. Notice that we'll have a default case, when any other number than specified in case statements will be introduced. If the user choose the exit option I just set the field iWantToLeave = true and the while condition isn't already passed and we close the app.

Frank Car Assistant App

Now we need to translate the application logic from a console app to a windows forms app.
1. File -> New -> Project 2. Choose Project types -> Visual C# -> Windows -> In templates choose Windows Forms Application
First we draw our form. And add into references of this project the CarsModel.dll file.
Now for the Add Car and Remove Car buttons we use the same code as for our console application.
The interesting part comes to populating our listbox and refreshing it.
For populating listbox we added this code:
BindingSource bSource = new BindingSource();
...
private void Form1_Load(object sender, EventArgs e)
{
   InitListOfCars(listCar);

   bSource.DataSource = listCar;

   lstCars.DataSource = bSource;
   lstCars.DisplayMember = "Name";
}
This means we have a binding source and we put it it (as its Datasource) the list of our cars. Now we put this binding source as Datasource of the listbox. In listbox.DisplayMember we choose the property of our object which will be shown in listbox, in our case it is name that we want to show. We decided that we need to fill in the textboxes with the data of selected car. This is made by this code:
private void lstCars_SelectedIndexChanged(object sender, EventArgs e)
{
   txtCarName.Text = (lstCars.SelectedItem as Car).Name;
   txtNumberOfWheels.Text = (lstCars.SelectedItem as Car).WheelNumber.ToString();
}
And we most difficult part was to find out how to update listbox data when we add or remove a Car object. The solution s this line: bSource.ResetBindings(true); the program generates automatically a Reload event when the flag is equal to true, and the datasource for bindingSource is reloaded.
So that have been the longest post of mine so far, but we've done a lot of stuff this time. Hope you liked it! Next time we'll be thinking about possible improvements and bugs in Frank Car Assistant application, and will try to fix them.

No comments:

Post a Comment