Lab 3-1: Adding Components and Implementing Members
In this lab, you will create a DoughnutMachine class that represents a doughnut-making machine for your Virtual Doughnut Factory. This class will create instances of a Doughnut class on a regular schedule and update the display form through events. The solution to this lab is available on the Supplemental Course Materials CD-ROM in the \Labs\Ch03\Lab 3-1\Solution folder.Before You Begin
Before you begin this lab, you must have completed and opened the Chapter 2 lab or loaded the Chapter 2 lab solution from the CD-ROM
Estimated lesson time: 45 minutes
Exercise 3.1: Creating the DoughnutMachine ComponentIn this exercise, you will create a component that represents a doughnut-making machine. This class will create and manage instances of a Doughnut class and expose a collection of doughnuts. In addition, it will implement member events that inform the containing component when a doughnut is ready.
To create the DoughnutMachine component
From the Project menu, choose Add Component. The Add New Item window appears. Name your component DoughnutMachine, and click OK. The component designer opens.
In the Toolbox, under the Windows Forms tab, double-click Timer. A Timer component is added to the designer.
In Solution Explorer, right-click DoughnutMachine and choose View Code.
Add an enum to your component that represents the different types of doughnuts. Your enum should look like this:
Visual Basic .NET
Public Enum DoughnutType Glazed Sugar Chocolate ChocolateCake Custard Grape Lemon PlainCake SugarCake End Enum
Visual C#
public enum DoughnutType { Glazed, Sugar, Chocolate, ChocolateCake, Custard, Grape, Lemon, PlainCake, SugarCake }
Add a property to your class to indicate the flavor of doughnut it is currently making. Include a private variable to hold the property value. This property should return a DoughnutTypes enum value. The following code is a sample of what your property should look like:
Visual Basic .NET
Private mFlavor As DoughnutType Public Property Flavor() As DoughnutType Get Return mFlavor End Get Set (ByVal Value As DoughnutType) mFlavor = Value End Set End Property
Visual C#
private DoughnutType mFlavor; public DoughnutType Flavor { get { return mFlavor; } set { mFlavor = value; } }
Within the bounds of the DoughnutMachine class, create a nested Doughnut class to represent a doughnut. It should have a flavor property, a price property, and a read-only property, which represents the time it was made. Because read-only variables can be set only in the constructor, you must also create a constructor for the class that sets the value of the time the doughnut instance was made. Your class should look something like this:
Visual Basic .NET
Public Class Doughnut ' These variables hold the property values Private mFlavor As DoughnutType ' A default value for price Private mPrice As Single = .50 Private ReadOnly mTimeOfCreation As Date ' These are the properties of your class Public Property Flavor() As DoughnutType Get Return mFlavor End Get Set(ByVal Value As DoughnutType) mFlavor = Value End Set End Property Public Property Price() As Single Get Return mPrice End Get Set(ByVal Value As Single) mPrice = Value End Set End Property Public ReadOnly Property TimeOfCreation() As Date Get Return mTimeOfCreation End Get End Property ' This is the constructor. It sets the value of ' mTimeOfCreation Public Sub New(ByVal Flavor As DoughnutType) ' Date.Now is a property of Date that returns the ' current time. mTimeOfCreation = Date.Now mFlavor = Flavor End Sub End Class
Visual C#
public class Doughnut { // These variables hold the property values private DoughnutType mFlavor; // A default value for price private float mPrice = .50F; private readonly System.DateTime mTimeOfCreation; // These are the properties of your class public DoughnutType Flavor { get { return mFlavor; } set { mFlavor = value; } } public float Price { get { return Price; } set { mPrice = value; } } public System.DateTime TimeOfCreation { get { return mTimeOfCreation; } } // This is the constructor. It sets the value of mTimeOfCreation public Doughnut(DoughnutType Flavor) { // System.DateTime.Now is a property of System.DateTime that // returns the current time mTimeOfCreation = System.DateTime.Now; mFlavor = Flavor; } }
Create a private member collection and a default property (Visual Basic .NET) or an indexer (Visual C#) for the DoughnutMachine class that exposes the members of this collection. This collection will hold the instances of the Doughnut class that are created by the DoughnutMachine. An example follows:
Visual Basic .NET
Private mDoughnuts As New System.Collections.ArrayList() Public Default Property Doughnuts(Index As Integer) As Doughnut Get Return CType(mDoughnuts(Index), Doughnut) End Get Set (Value As Doughnut) mDoughnuts(Index) = Value End Set End Property
Visual C#
private System.Collections.ArrayList mDoughnuts = new System.Collections.ArrayList(); public Doughnut this[int Index] { get { return (Doughnut)mDoughnuts[Index]; } set { mDoughnuts[Index] = value; } }
Add a public event to be raised when a doughnut is created. In Visual C#, you should also declare a public delegate.
Visual Basic .NET
Public Event DoughnutComplete()
Visual C#
public delegate void DoughnutCompleteDelegate(); public event DoughnutCompleteDelegate DoughnutComplete;
Using the drop-down menus in the code editor (Visual Basic. NET) or the Events button in the designer (Visual C#), add an event handler for the Timer1.Tick event.
Add code to the event handler you created in the previous step that creates a new Doughnut, adds it to the mDoughnuts collection, and raises the DoughnutComplete event. An example follows:
Visual Basic .NET
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As _ System,EventArgs) Handles Timer1.Tick Dim aDoughnut As New Doughnut(Me.Flavor) mDoughnuts.Add(aDoughnut) RaiseEvent DoughnutComplete() End Sub
Visual C#
private void timer1_Tick(object sender, System.EventArgs e) { Doughnut aDoughnut = new Doughnut(this.Flavor); mDoughnuts.Add(aDoughnut); DoughnutComplete(); }
Add two write-only properties named Enabled and Interval as Boolean (bool) and Integer (int), respectively. These properties will serve to set the internal properties of the timer. An example follows:
Visual Basic .NET
Public WriteOnly Property Enabled() As Boolean Set(ByVal Value As Boolean) Timer1.Enabled = Value End Set End Property Public WriteOnly Property Interval() As Integer Set(ByVal Value As Integer) Timer1.Interval = Value End Set End Property
Visual C#
public bool Enabled { set { timer1.Enabled = value; } } public int Interval { set { timer1.Interval = value; } }
Add a method to the DoughnutMachine class that sets the machine to make the correct type of doughnuts, sets the appropriate interval, and turns the machine on. This method should take a DoughnutType as a parameter. An example follows:
Visual Basic .NET
Public Sub MakeDoughnuts(ByVal dFlavor As DoughnutType) Flavor = dFlavor Select Case dFlavor Case DoughnutType.Chocolate Interval = 15000 Case DoughnutType.ChocolateCake Interval = 12000 Case DoughnutType.Custard Interval = 10000 Case DoughnutType.Glazed Interval = 10000 Case DoughnutType.Grape Interval = 10000 Case DoughnutType.Lemon Interval = 10000 Case DoughnutType.PlainCake Interval = 5000 Case DoughnutType.Sugar Interval = 8000 Case DoughnutType.SugarCake Interval = 6000 End Select Enabled = True End Sub
Visual C#
public void MakeDoughnuts(DoughnutType dFlavor) { Flavor = dFlavor; switch(dFlavor) { case DoughnutType.Chocolate: Interval = 15000; break; case DoughnutType.ChocolateCake: Interval = 12000; break; case DoughnutType.Custard: Interval = 10000; break; case DoughnutType.Glazed: Interval = 10000; break; case DoughnutType.Grape: Interval = 10000; break; case DoughnutType.Lemon: Interval = 5000; break; case DoughnutType.PlainCake: Interval = 5000; break; case DoughnutType.Sugar: Interval = 8000; break; case DoughnutType.SugarCake: Interval = 6000; break; } Enabled = true; }
From the Build menu, choose Build Solution to build your solution.
In this exercise, you will create an instance of DoughnutMachine in frmMain to create doughnuts for your virtual storefront. You will add code to set the flavor of the doughnuts you are making and add a method to handle the DoughnutComplete event as it is raised by your DoughnutMachine component. You also will add a method to halt doughnut production.
Add a class-level variable to represent an instance of the DoughnutMachine component. For example:
Visual Basic .NET
Private myDoughnutMachine As DoughnutMachine
Visual C#
private DoughnutMachine myDoughnutMachine;
Create an event handler for frmMain_Load. In this method, create a new instance of DoughnutMachine and assign it to the myDoughnutMachine variable. For example:
Visual Basic .NET
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load myDoughnutMachine = New DoughnutMachine() End Sub
Visual C#
private void frmMain_Load(object sender, System.EventArgs e) { myDoughnutMachine = new DoughnutMachine(); }
Create private variables to hold the values corresponding to the number of doughnuts currently in inventory. For example:
Visual Basic .NET
Private mRaisedGlazed As Integer Private mRaisedSugar As Integer Private mRaisedChocolate As Integer Private mCakePlain As Integer Private mCakeChocolate As Integer Private mCakeSugar As Integer Private mFilledLemon As Integer Private mFilledGrape As Integer Private mFilledCustard As Integer
Visual C#
private int mRaisedGlazed; private int mRaisedSugar; private int mRaisedChocolate; private int mCakePlain; private int mCakeChocolate; private int mCakeSugar; private int mFilledLemon; private int mFilledGrape; private int mFilledCustard;
Add a submenu to the Make menu item of the Doughnuts Menu. Add the items Raised, Cake, and Filled. Set the names of these items to mnuRaised, mnuCake, and mnuFilled, respectively. Add a submenu to the Raised menu item with the items Glazed, Sugar, and Chocolate. Set the names of these items to mnuRaisedGlazed, mnuRaisedSugar, and mnuRaisedChocolate. When complete, your menu should look like Figure 3.1 in the designer.
Figure 3-1. The user interface with menus.
In the click handler for mnuRaisedGlazed, write code that calls the DoughnutMachine.MakeDoughnut method, indicating the kind of doughnut to make. You should also set the Checked property of this menu item to true and the Check property of mnuRaisedSugar and mnuRaisedChocolate to false. A sample follows:
Visual Basic .NET
Private Sub mnuRaisedGlazed_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles mnuRaisedGlazed.Click mnuRaisedGlazed.Checked = True mnuRaisedSugar.Checked = False mnuRaisedChocolate.Checked = False myDoughnutMachine.MakeDoughnuts( _ DoughnutMachine.DoughnutType.Glazed) End Sub
Visual C#
private void mnuRaisedGlazed_Click(object sender, System.EventArgs e) { mnuRaisedGlazed.Checked = true; mnuRaisedSugar.Checked = false; mnuRaisedChocolate.Checked = false; myDoughnutMachine.MakeDoughnuts( DoughnutMachine.DoughnutType.Glazed); }
Create similar methods for mnuRaisedSugar and mnuRaisedChocolate.
Create a method to handle the DoughnutComplete event of myDoughnutMachine. It should increment the appropriate variable and write the value to the appropriate text box. The following example demonstrates how it could be implemented:
Visual Basic .NET
Private Sub DoughnutCompleteHandler() Select Case myDoughnutMachine.Flavor Case DoughnutMachine.DoughnutType.Glazed mRaisedGlazed += 1 txtGlazedRaised.Text = mRaisedGlazed.ToString Case DoughnutMachine.DoughnutType.Sugar mRaisedSugar += 1 txtSugarRaised.Text = mRaisedSugar.ToString Case DoughnutMachine.DoughnutType.Chocolate mRaisedChocolate += 1 txtChocolateRaised.Text = mRaisedChocolate.ToString End Select End Sub
Visual C#
private void DoughnutCompleteHandler() { switch (myDoughnutMachine.Flavor) { case DoughnutMachine.DoughnutType.Glazed: mRaisedGlazed ++; txtGlazedRaised.Text = mRaisedGlazed.ToString(); break; case DoughnutMachine.DoughnutType.Sugar: mRaisedSugar ++; txtSugarRaised.Text = mRaisedSugar.ToString(); break; case DoughnutMachine.DoughnutType.Chocolate: mRaisedChocolate ++; txtChocolateRaised.Text = mRaisedChocolate.ToString(); break; } }
In the Form1_Load event handler, add code to hook up the myDoughnut Machine.DoughnutComplete event with the doughnut complete event handler as follows:
Visual Basic .NET
AddHandler myDoughnutMachine.DoughnutComplete, AddressOf _ DoughnutCompleteHandler
Visual C#
myDoughnutMachine.DoughnutComplete += new DoughnutMachine.DoughnutCompleteDelegate(DoughnutCompleteHandler);
Add a menu item to the Doughnuts menu titled &Stop, and name it mnuStop. In the click event handler for this menu item, set the Enabled property of myDoughnutMachine to false. For example:
Visual Basic .NET
Private Sub mnuStop_Click(ByVal sender As System.Object, ByVal e _ As System.EventArgs) Handles mnuStop.Click myDoughnutMachine.Enabled = False End Sub
Visual C#
private void mnuStop_Click(object sender, System.EventArgs e) { myDoughnutMachine.Enabled = false; }
Build and save your solution.
To test your solution, press F5 to start the application.
From the Doughnuts menu, choose Raised, and then Sugar. Note that a check mark appears next to the sugar menu item. Every eight seconds, the value in the Raised Sugar text box should be incremented. Follow the same steps with the Glazed menu item. The appropriate box should be incremented every 10 seconds. Similarly, for Chocolate, the appropriate box should be incremented every 15 seconds.
From the Doughnuts menu, choose Stop to stop the production of doughnuts.