554-Project-3-Bombardo-Davis

=SSE 554 Project 3= =Chris Bombardo & Jonathan Davis= =Spring 2010=

Project Scope:
The purpose of this project is to eventually build a touch screen application for day care providers. The application will allow employees to log naps, meals, medicines, and diaper changes. Parents will be able to log in and view the information in a report format. An administrator role also exists to add/remove children, parents, and employees and to generate center-wide reports.

Although this project consists of advanced topics from throughout the C# text, this report will primarily focus on five chapters:

Chapter 14: Errors & Exceptions Chapter 20: Security Chapter 26: Data Access Chapter 31: Windows Forms Chapter 32: Data Binding

Chapter 14: Errors & Exceptions
There is no way to avoid errors. As the authors put it “Errors happen” – or as Forest Gump put it “Shit Happens”. The trick is to anticipate errors and handle them accordingly.

One of the benefits of the .Net framework is the improved methods of catching and handling errors. .Net has added mechanisms for custom error handling and identification of error types all wrapped in the try-catch-finally.


 * Exception Classes**

C# has many exception classes built-in. Any time a C# program has an error exception object is created. The object contains a vast amount of information to assist in tracking the error. Although there are built-in exception classes you can also create your own to manage errors. The Microsoft provided classes (the authors say there are too many to list 1770 page book, so you can image) reside under the System namespace, except for the IOException.

The generic exception class System.Exception, which is not recommended for use because it does not give specifics about the error condition. The C# book points out System.SystemException and System.ApplicationException as importation classes for handling errors.

System.SystemExecption is the common generic system errors. It will be thrown for error such as the StackOverflowException. In the Day Care application we use NullReferernceException, which inherits the System.SystemException. The NullReferernceException class is to catch an error of an object reference not set to an instance of an object.

In our CloseCreateUser method there could be ever so slight some reason that the form is already closes, object failed to initiate, or something causing the object not to exit at the time the application tries to close the form, which is an object. When this happens if could cause the application to crash. Instead we plan on catching the error and handling.

As you will see below we use the try-catch-final statements. First, the try statement: The Try statement is followed by the code that is going to be executed. If an error occurs it is passes to the catch, in our cause if it is a NullReferenceException. If an error occures the catch code is ran. Currently, we have a simple message box telling the form could not be closes, even though it is actually probably already closed. In reality there should be code collect data about the error, display something to the user, and log the error information for tracking.

The final statement is we can use but do not have at that the time is Finally. The Finally sattement is executed after the try and catch, if the catch is executed. Finally if often used as a clean up.

code format="csharp" public static void CloseCreateUser {           try {               if (createUsers != null) {                   createUsers.Dispose; createUsers = null; }           }            catch (NullReferenceException) {               MessageBox.Show("Unable to open create user at this time."); }       }

code The introduction of try,catch, finally in .Net has made error handling fairly simple. It has also give the programmer large control over what the user will see and how to manage errors. One of the goals we set out in the project is manage most of error in one class. We made static error class: code format="csharp" static class Errors {

} code

The idea behand the error class is two write the code once to log, track, and communicate errors. Since the error class is static we do not need to initialize the class, instead we can call it from anywhere. The final product will call the error class in the catch statement, passing the error, the method name, and the error information. The error class will log the data (we are still discussing if it should be in a log file or database). It will also keep track of the last error to check if we have a repeating error that needs immediate attention.

Chapter 20: Security
Although we focused on security during Project 1, several of the concepts also apply to this project.

Most security exploits involve the target application incorrectly checking the incoming data or in some cases not at all. Data should not be trusted until the data has been properly validated. There are two rules concerning data input.
 * Input Validation**

Rule 1: All input is evil until proven otherwise. Rule 2: Data must be validated as it crosses the boundary between untrusted and trusted environments.

Trusted data is data you or a trusted entity has complete control over. Any data submitted by a user is initially untrusted data. Data validation not only protects the application from users with malicious intent, it also protects the application from honest users who simply make an input mistake.

Many applications today distribute functionality between client and server machines or between peers, and many developers rely on the client portion of the application to provide specific behavior. Once deployed, however, the client software is no longer under the control of the developer or server administrators. There is no longer a guarantee that the requests made by the client came from a valid client. Those requests may have been forged.

The critical issue is trust attributing too much trust to data provided by an untrusted entity. Furthermore, the same concept applies to the client, as the server could be a rogue server.

As SQL injections became a common method of hackers in recent years validation inputs and Stored Procedures have had programmers’ busy updating code. The best method of showing the importance of input validation is to first show how simple a SQL injection can be used to gain information against a non-validated field. The following code is based on a simple password recovery email based on the users input their email address. The code passes the email to GetUserDataByEmail which users a Select – From – Where statement to pull the users data and pass it back in the data set. code format="csharp" public DataSet GetUserDataByEmail(string userEmail) {           string constr = "Provider=sqloledb;Data Source=SqlServerIPAddress;InitialCatalog=DataBaseName;User Id=UserName;Password=UserPassword;";

string str_select = "SELECT * FROM tbl_users where email = " + userEmail; SqlConnection con = new SqlConnection(constr); DataSet ds = new DataSet; SqlDataAdapter da = new SqlDataAdapter(str_select, con); da.Fill(ds); return ds; }

code Without the input validation if a users passes their proper email address, such as MACNEIL_PE@Mercer.edu the code would act properly test if the where clause is true if the email matches MACNEIL_PE@Mercer.edu and pass back the data for this user. However, if end user passes in “’anything' OR 'x'='x'” this will make the where statement true for ALL users and pass the entire data set back. Image if this was a system showing the user data to reset a password based on the input of an email address, a simple hack could garner the information on all the users.

Though input validation is not the only method (and I would use multiple) method of stopping SQL injections, it is the one in example here. If the input data was validated for the @ and remove an ‘ or “ would remove most of vulnerabilities of a SQL injection on email input. Another method and more proper method would have a email validation as the code below shows, this would validate the code format="csharp" public static bool isEmail(string inputEmail) {           inputEmail = NulltoString(inputEmail); string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\(([a-zA-Z0-9\-]+\" +               @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";            Regex re = new Regex(strRegex);            if (re.IsMatch(inputEmail))                return (true);            else                return (false);        } [[code Validate all inputs into your methods. The regular expression methods in the System.Text.RegularExpressions namespace are useful for confirming that input is of the correct form, such as an e-mail address.

I have to admit I did not know about System.Text.RegularExpressions until I did recommendation #6. This is one of the most useful namespaces I have found in the project, at least up to recommendation #6. Not only did I discover the System.Text.RegularExpressions namespace I also found a validation for nearly every numerical input at [] This is a great resource for validation. This could could easily be expanded to validate nearly all inputs and placed in a validation class and used throughout a lot of projects, OO programming at its best! Numerical (Alphabet, AlphaNumeric, Integer, Positive Integer, Floating point numbers) validator: code format="csharp" using System.Text.RegularExpressions; using System; /*  csc /r:System.Text.RegularExpressions.dll,System.dll Validation.cs  class Validation {           public static void Main {               String strToTest; Validation objValidate = new Validation; Console.Write("Enter a String to Test for Alphabets:"); strToTest = Console.ReadLine; if (objValidate.IsAlpha(strToTest)) {                   Console.WriteLine("{0} is Valid Alpha String", strToTest); }               else {                   Console.WriteLine("{0} is not a Valid Alpha String", strToTest); }           }            // Function to test for Positive Integers. public bool IsNaturalNumber(String strNumber) {               Regex objNotNaturalPattern = new Regex("[^0-9]"); Regex objNaturalPattern = new Regex("0*[1-9][0-9]*"); return !objNotNaturalPattern.IsMatch(strNumber) && objNaturalPattern.IsMatch(strNumber); }           // Function to test for Positive Integers with zero inclusive public bool IsWholeNumber(String strNumber) {               Regex objNotWholePattern = new Regex("[^0-9]"); return !objNotWholePattern.IsMatch(strNumber); }           // Function to Test for Integers both Positive & Negative public bool IsInteger(String strNumber) {               Regex objNotIntPattern = new Regex("[^0-9-]"); Regex objIntPattern = new Regex("^-[0-9]+$|^[0-9]+$"); return !objNotIntPattern.IsMatch(strNumber) && objIntPattern.IsMatch(strNumber); }           // Function to Test for Positive Number both Integer & Real public bool IsPositiveNumber(String strNumber) {               Regex objNotPositivePattern = new Regex("[^0-9.]"); Regex objPositivePattern = new Regex("^[.][0-9]+$|[0-9]*[.]*[0-9]+$"); Regex objTwoDotPattern = new Regex("[0-9]*[.][0-9]*[.][0-9]*"); return !objNotPositivePattern.IsMatch(strNumber) && objPositivePattern.IsMatch(strNumber) && !objTwoDotPattern.IsMatch(strNumber); }           // Function to test whether the string is valid number or not public bool IsNumber(String strNumber) {               Regex objNotNumberPattern = new Regex("[^0-9.-]"); Regex objTwoDotPattern = new Regex("[0-9]*[.][0-9]*[.][0-9]*"); Regex objTwoMinusPattern = new Regex("[0-9]*[-][0-9]*[-][0-9]*"); String strValidRealPattern = "^([-]|[.]|[-.]|[0-9])[0-9]*[.]*[0-9]+$"; String strValidIntegerPattern = "^([-]|[0-9])[0-9]*$"; Regex objNumberPattern = new Regex("(" + strValidRealPattern + ")|(" + strValidIntegerPattern + ")"); return !objNotNumberPattern.IsMatch(strNumber) && !objTwoDotPattern.IsMatch(strNumber) && !objTwoMinusPattern.IsMatch(strNumber) && objNumberPattern.IsMatch(strNumber); }           // Function To test for Alphabets. public bool IsAlpha(String strToCheck) {               Regex objAlphaPattern = new Regex("[^a-zA-Z]"); return !objAlphaPattern.IsMatch(strToCheck); }           // Function to Check for AlphaNumeric. public bool IsAlphaNumeric(String strToCheck) {               Regex objAlphaNumericPattern = new Regex("[^a-zA-Z0-9]"); return !objAlphaNumericPattern.IsMatch(strToCheck); }       }

code

Chapter 26: Data Access

 * ADO.NET**

ADO.NET provides consistent access to data sources such as Microsoft SQL Server, as well as data sources exposed through OLE DB and XML. Data-sharing consumer applications can use ADO.NET to connect to these data sources and retrieve, manipulate, and update data.

ADO.NET cleanly factors data access from data manipulation into discrete components that can be used separately or in tandem. ADO.NET includes .NET Framework data providers for connecting to a database, executing commands, and retrieving results. Those results are either processed directly, or placed in an ADO.NET DataSet object in order to be exposed to the user in an ad-hoc manner, combined with data from multiple sources, or remoted between tiers. The ADO.NET DataSet object can also be used independently of a .NET Framework data provider to manage data local to the application or sourced from XML.

The ADO.NET classes are found in System.Data.dll, and are integrated with the XML classes found in System.Xml.dll. When compiling code that uses the System.Data namespace, reference both System.Data.dll and System.Xml.dll.

ADO.NET shops with four database client namespaces: SQL Server, Oracle, ODBC (mysql, etc), and one for any database exposed through OLE DB (Microsoft Access).


 * App.Config**

The connection string can be stored in the app.config file to facilitate ease of reuse and maintenance. In our project, we included the connection string in the app.config file, but also in the code for ease of documentation. code format="csharp"    code
 * Using Connections Efficiently**

As with other scarce resources in .NET, such as windows, graphics, and objects, it is good practice to ensure that database connections are closed after use. Keeping a connection open for longer than necessary can affect other sessions. Leaving a connection open can lock other users out of an entire set of tables, hurting application performance considerably. Closing database connections should be considered mandatory.

There are two main ways to ensure that database connections are released after each use:


 * One: Try . . . catch . . . finally**

Within the finally block, you can release any resources that you have used. The downfall to using this method is that it is up to the programmer to ensure that the connection is closed. Also, if you are opening multiple resources using this method, the finally blocks become less readable.


 * Two: The using block statement**

The using clause ensures that the database connection is closed regardless of how the block is exited. It is used to ensure that objects that implement the IDisposable interface are cleared up immediately upon exit.

When programming, you should use at least one of these methods, but it is best to use both methods together. The using statement ensures the connection object has been closed, while the try. . . catch. . . finally portion offers good exception handling.

The Close is not strictly necessary, because the using clause will ensure that it is done anyway. The close is included so that we have programmatic control over precisely when the resource is released, as there is no point in locking a resource unnecessarily.


 * Reading from the Database**

There are five steps to retrieving the data from our program 1. Connect to the data source 2. Open the connection 3. Issue a SQL query 4. Read and display the data with the data reader 5. Close the data reader and the connection

Connecting to the data source is done by creating a connection object using a connection string. The connection string includes the name of the provider for the database, the login information, and the name of the particular database to use.

For our SQL Server Express edition database, we need to include the following using statement at the top of our .cs file(s): code format="csharp" using System.Data.SqlClient; code The connection object looks like this: code format="csharp" string sqlConnectString = @"Data Source=(local)\SQLExpress;Integrated security=SSPI;Initial Catalog=DayCare;"; code Data Source=(local) is the name of the SQL Server to access. Local is a shorthand name that refers to the server instance running on the current machine. The name of our instance is SQLExpress.

The next part of the connection string specifies how to log in to the database. Here, I use the integrated security of the Windows login so that no separate username and password needs to be specified. SSPI stands for Security Support Provider Interface, which is the standard built-in security for SQL Server and Windows.

Finally, the particular database to use is specified, in our case, the database is called DayCare. Our connection object is now configured for our machine and database. Next, we need to open the connection object, which establishes the connection to the database: code format="csharp" thisConnection.Open; code This takes place inside our using statement that was discussed earlier. If the Open method were to fail, a SqlException exception will be thrown.

The third step is to create a command object and give it a SQL command to perform a database operation. In our case, this is retrieving some data. code format="csharp" SqlCommand thisCommand = thisConnection.CreateCommand; thisCommand.CommandText = "SELECT * FROM dcUser WHERE passcode = " + passCode + ";"; code The connection object has a method called CreateCommand to create a command associated with this connection, so we will use this to get our command object. The SQL command itself is assigned to the CommandText property of the command object. We want to list the information for the user whose passcode matches the passcode input from the login form. The SQL command is: code format="csharp" SELECT * FROM dcUser WHERE passcode = " + passCode + "; code The fourth step is to read the data with a data reader. The data reader is a lightweight, fast object for quickly getting the results of a query. It is read-only so it can’t be used to update the data.

There are several methods for getting the results out of the reader, but the following is the usual process. The Read method of DataReader reads a single row of data resulting from the query, and returns true while there is more data to read and false is there is not. We set up a while loop to read the data with the Read method and return the results. Because we know that our database only allows unique passcodes, there should only be one record returned. code format="csharp" SqlDataReader thisReader = thisCommand.ExecuteReader; while (thisReader.Read) {                   return Convert.ToInt16(thisReader["userType"].ToString); } code In this case, we then convert the returned object (thisReader[“userType”) to an integer and return it to the location where our method was called. We could have displayed the data on the form, sent it to the console as output, popped it up in a message box, or any number of things.

When Read returns false at the end of the results, the while loop ends.

The fifth and final step is to close the objects we opened, which include the reader object and the connection object. Each of these objects has a Close method, which we call before exiting the program: code format="csharp" thisReader.Close; thisConnection.Close; code The login form uses this code to authenticate the user, and to return the usertype (1 = Admin, 2 = Employee, 3 = Parent) to the next form.



The code in its entirety can be found below: code format="csharp" string sqlConnectString = @"Data Source=(local)\SQLExpress;Integrated security=SSPI;Initial Catalog=DayCare;";

using (SqlConnection thisConnection = new SqlConnection(sqlConnectString)) {               thisConnection.Open; SqlCommand thisCommand = thisConnection.CreateCommand; thisCommand.CommandText = "SELECT * FROM dcUser WHERE passcode = " + passCode + ";"; SqlDataReader thisReader = thisCommand.ExecuteReader; while (thisReader.Read) {                   return Convert.ToInt16(thisReader["userType"].ToString); }               thisReader.Close; thisConnection.Close; code
 * Populating Form elements from a database**

A database can be used to populate form elements. In our Edit user form, we use a combo box to determine which user to edit. The combo box is populated with the user’s name from the DCUSER table in the database. code format="csharp" private void populateUsers {

string sqlConnectString = @"Data Source=(local)\SQLExpress;Integrated security=SSPI;Initial Catalog=DayCare;";

using (SqlConnection thisConnection = new SqlConnection(sqlConnectString)) {               thisConnection.Open; SqlCommand thisCommand = thisConnection.CreateCommand; thisCommand.CommandText = "SELECT * FROM dcUser WHERE usertype = 3;"; SqlDataReader thisReader = thisCommand.ExecuteReader;

while (thisReader.Read) {                   int myIndex = Convert.ToInt16(thisReader["ID"]); string myName = thisReader["userFirstName"].ToString + " " + thisReader["userMiddleName"].ToString + " " + thisReader["userLastName"].ToString; this.cmbSelectUser.Items.Add(myName);

}               thisReader.Close; thisConnection.Close;

}

code


 * Updating the Database**

The edit user form allows us to update the user's attributes in the database:



All of the actions that you would typically perform on a database, such as updating, inserting, and deleting records, can be accomplished with the same pattern:

1. Fill a DataSet with the data from the database to work with 2. Modify the data held in the DataSet (update, insert, or delete records) 3. Once all modifications are made, persist the DataSet changes back to the database

With this method, there is no need to worry about the exact SQL syntax for updating the database and all of the modifications to the database can be performed at one time.

The first part of the program is similar to the previous example; a connection string is created: code format="csharp" string sqlConnectString = @"Data Source=(local)\SQLExpress;Integrated security=SSPI;Initial Catalog=DayCare;"; SqlConnection thisConnection = new SqlConnection(sqlConnectString); Then, we create a SqlDataAdapter object, with the next statement: SqlDataAdapter thisAdapter = new SqlDataAdapter("SELECT userID, userType, passcode, userFirstName, userMiddleName, userLastName, userDOB FROM dcuser WHERE userID = " + userID + ";", thisConnection); code Next, we create the correct SQL statements to update the database. The SqlCommandBuilder will take care of this: code format="csharp" SqlCommandBuilder thisBuilder = new SqlCommandBuilder(thisAdapter); code thisAdapter is passed to the SqlCommandBuilder constructor as an argument. The correct SQL statements are generated and associated with the passed data adapter by the constructor when the SqlCommandBuilder object is created. The DataSet object is now created: code format="csharp" DataSet thisDataSet = new DataSet; code The associated DataTable in the DataSet has been named the same as the table we want to access: dcuser. code format="csharp" thisAdapter.Fill(thisDataSet, "dcuser"); code Because only one row should be returned, because we put a qualifier in our SQL query to select the single row that we are interested in. The single row returned, which is the row we want to change, is Row[0].

We declare dcuser as a DataTable and assign the dcuser table from the Tables property of thisDataSet. Then we can assign the submitted values from the form: code format="csharp" thisDataSet.Tables["dcuser"].Rows[0]["userFirstName"] = textBoxFN.Text; thisDataSet.Tables["dcuser"].Rows[0]["userMiddleName"] = textBoxMN.Text; thisDataSet.Tables["dcuser"].Rows[0]["userLastName"] = textBoxLN.Text; int userType = 0; if (radioAdmin.Checked == true) {                       userType = 1; }                   if (radioEmployee.Checked == true) {                       userType = 2; }                   if (radioParent.Checked == true) {                       userType = 3; }                   thisDataSet.Tables["dcuser"].Rows[0]["userType"] = userType; thisDataSet.Tables["dcuser"].Rows[0]["passcode"] = txtKeyCode.Text; thisDataSet.Tables["dcuser"].Rows[0]["userDOB"] = dateTimePickerDOB.Value; code The DataSet, DataTable, DataRow, and DateColumn are in-memory representations of the data in the table. We need to call the data adapter’s Update method to update the database: code format="csharp" thisAdapter.Update(thisDataSet, "dcuser"); code The Update method automatically goes through the rows in DataTable to check for changes that need to be made to the database. The changes are then committed to the database and the connection object can be closed: code format="csharp" thisConnection.Close; code
 * Writing to the Database**

We need to write to the database when a new user is created. The create user form is below:



The process to add a new row to a table is straightforward: 1. Create a new DataRow 2. Populate it with some data 3. Add it to the Rows collection of the Dataset 4. Persist this change back to the database by calling the Update method of the data adapter

Connecting to the database was discussed earlier, so the lines of interest here are between the thisAdapter.Fill and thisAdapter.Update method calls.

First, we create the new row object, using the NewRow method of the DataTable object: code format="csharp" DataRow thisRow = thisDataSet.Tables["dcuser"].NewRow; code This actually creates a new row object using the same columns as the Customers table, but does not actually add it to the DataSet. We need to assign some values to the columns before that can be done. code format="csharp" thisRow["userFirstName"] = textBoxFN.Text; thisRow["userMiddleName"] = textBoxMN.Text; thisRow["userLastName"] = textBoxLN.Text; int userType = 0; if (radioAdmin.Checked == true){ userType = 1; }                   if (radioEmployee.Checked == true){ userType = 2; }                   if (radioParent.Checked == true){ userType = 3; }                   thisRow["userType"] = userType; thisRow["passcode"] = txtKeyCode.Text; thisRow["userDOB"] = dateTimePickerDOB.Value; code We get the data from the form to add to the table. Now we can actually add the row using the Add method of the Rows collection: code format="csharp" thisDataSet.Tables["dcuser"].Rows.Add(thisRow); code We then need to call the Update method to actually add the new row to the database on disk: code format="csharp" thisAdapter.Update(thisDataSet, "dcuser"); code The DataSet is an in-memory, disconnected copy of the data; it is the DataAdapter which is actually connected to the database on disk and therefore its Update method needs to be called to synchronize the in-memory data in the DataSet with the database on disk.

The code in its entirety can be found below: code format="csharp" string sqlConnectString = @"Data Source=(local)\SQLExpress;Integrated security=SSPI;Initial Catalog=DayCare;"; SqlConnection thisConnection = new SqlConnection(sqlConnectString); SqlDataAdapter thisAdapter = new SqlDataAdapter("SELECT userType, passcode, userFirstName, userMiddleName, userLastName, userDOB FROM dcuser", thisConnection); SqlCommandBuilder thisBuilder = new SqlCommandBuilder(thisAdapter); DataSet thisDataSet = new DataSet; thisAdapter.Fill(thisDataSet, "dcuser"); DataRow thisRow = thisDataSet.Tables["dcuser"].NewRow; thisRow["userFirstName"] = textBoxFN.Text; thisRow["userMiddleName"] = textBoxMN.Text; thisRow["userLastName"] = textBoxLN.Text; int userType = 0; if (radioAdmin.Checked == true){ userType = 1; }                   if (radioEmployee.Checked == true){ userType = 2; }                   if (radioParent.Checked == true){ userType = 3; }                   thisRow["userType"] = userType; thisRow["passcode"] = txtKeyCode.Text; thisRow["userDOB"] = dateTimePickerDOB.Value; thisDataSet.Tables["dcuser"].Rows.Add(thisRow); thisAdapter.Update(thisDataSet, "dcuser"); thisConnection.Close; code Although the following tips are not directly .NET-related, the author devoted several pages to the topic of naming conventions.
 * Naming Conventions**

For database tables, singular names should be used, such as user instead of users. Our database follows this convention with the tables nap, user, child, contact, diaper change, and room. Some form of naming convention should also be adopted for the fields that go into a table. Having a good table convention means you can look at virtually any table in the database and instinctively know what the fields are used for. Our database follows this recommendation as well.

For database columns, singular names should be used instead of plural names. Columns that link to another table should be named the same as the primary key of that table. The author does not that this is not always possible. Date fields should have a “_on” suffix appended to the end of the column name and fields that record the user should be suffixed by a “_by”. Our database follows all of these recommendations.

=Chapter 31: Windows Forms=

In all of the prior projects we have not wrote much about application presentation. Since presentation is such a large part of the application we thought it would be important to give some coverage. In presentation portion of the book we are going to focus on chapter 31 windows forms. The usage of forms is much easier than it was just a couple of years ago. Windows Forms is now much the same way you drag and drop a control from a toolbox in the Form Designer.

The author points out in the last several years the decision to create client-application with forms versus a web-application has become a little more difficult. Web-applications no longer need to be deployed to each computer, updated on each computer, or managed much easier. However, client applications can be developed quickly and efficiently and provide the user with a rich experience.


 * Creating a Windows Form Application**

In creating the form in a client application two things need to be pointed out - first the form inheritance System.Windows.Forms.Form.

In our project the MainScreen form inheritance: code format="csharp" public partial class MainScreen : Form code The second thing is the entry point of the application. In the books example the entry point of the application is contained in the form. In our project the entry point is within a class, Program.cs. In the class we start the first form with (login = new Login). code format="csharp" We did not use the standard (new Login), which .Net auto-creates. Instead use the login form variable declared: code format="csharp" private static Login login; code Next, we initialize the form in at the Application.Run. We use the variable with the initialization for we can manage the forms from the program.cs. Each of the forms to be used in the application is set as variables in the class: code format="csharp" private static CreateUser createUsers; private static InputChild inputChild; private static Login login; private static MainScreen mainScreen; private static Reports reports; private static LogOffWarning logOffWarning; code To control each of the forms with the program class we wrote a show and close for each of the forms.


 * The Show form:**

The ShowCreateUser method opens the CreateUser form. The first thing to note is the parameter passes with the form opening. The createuser form can be used to create a user or edit a user. The parameter passes makes the decision. code format="csharp" public static void ShowCreateUser(bool isEditing) { code

Next we check if the form is already created. If is already created or not null then we just need to show the form, simple by using the createUser.Show. With that said the program should never use the createUsers.Show, becease we are using modal forms for the createUsers. Forms in .Net come in two forms modal and Modeless. The primary difference is a modal form or dialog box must be closed or hidden before you can continue working with the rest of the application - http://msdn.microsoft.com/en-us/library/aa984358(VS.71).aspx.

The intent here of using modal forms is the createUser form is meant to be used then closed. While the form is in use no other form should be able used or on top. So, the form is also started with the TopMost property set to true. code format="csharp" if (createUsers == null) { code

If the createUser is null then the createUser variable is set to an new instanceof the CreateUser form passing the isEditing boolean parameter.

code format="csharp" createUsers = new CreateUser(isEditing); code

Finally, we show the Form with the .showDialog to create a modal form.

code format="csharp" createUsers.ShowDialog; } else { createUsers.Show; } } code

The above procedure of followed for each of our forms.

code format="csharp" public static void ShowInputChild(bool isEditing) { if (inputChild == null) { inputChild = new InputChild(isEditing); inputChild.ShowDialog; } else { inputChild.Show; } }

code The login form is a bit difference. It is never closed, talk about below in the closing methods. Since it is never closed the ShowLogin shoud never start as need the nee Login, it will always use the login.Show.

code format="csharp" public static void ShowLogin { if (login == null) { login = new Login; login.Show; } else { login.Show; } } code Notice with the ShowMainScreen we pass two parameters. Both the parameters are passed to setup the ShowMainScreen for the particular user logged in, this will be touched on more later. Next, the mainScreen form is shown with only the .Show method. In other words, we are opening the form in the Modeless form. The mainScreen will remain open while other forms are opened and used, so it was best to open as a Modeless.

code format="csharp" public static void ShowMainScreen(int userID, int userType) { if (mainScreen == null) { mainScreen = new MainScreen(userID, userType); mainScreen.Show; } else { mainScreen.Show; } }

public static void ShowLogOffWarning { if (logOffWarning == null) { logOffWarning = new LogOffWarning; logOffWarning.ShowDialog; } else { logOffWarning.Show; } }

public static void ShowReports { if (reports == null) { reports = new Reports; reports.ShowDialog; } else { reports.Show; } }

code In the program to manage the forms we must close each of the forms when needed. To do so we use the CloseCreateUser form. We have to levels of error checking just to make sure the form is not locked or already closed when the method is called. The error checking is saftey not to instead of crashing the program and can catch and manage the error. code format="csharp" public static void CloseCreateUser { try {

code First we check to make sure the createUser not null, if it already null there is no reason to close it. Once we determine it is null we Dipose of the form. Instead of just closing it with .Close we dispose of it so it is instantly garbage collected and we do need to run the Closing method of the form. If we determine there is a need to ever use the Closing method of the form then we can call the .Close then .Dispose. Though it is redundant it will help keep the memory emptier. code format="csharp" if (createUsers != null) { createUsers.Dispose; createUsers = null; } }

code If for some reason we do have a null object and it gets past the if statement we can catch the exception and handle it instead of crashing the app:

code format="csharp" catch (NullReferenceException) {

} }

code

We will follow this procedure for each of our forms with a couple of exceptions, pointed out below. code format="csharp" public static void CloseInputChild { try { if (inputChild != null) { inputChild.Dispose; inputChild = null; } } catch (NullReferenceException) {

} } code Since the logoff is the main form and it does several things in the background (such as the auto log off) the form is never closed, unless the application is closed. Instead the Login form is only hidden.

code format="csharp" public static void CloseLogin { try { login.Hide; } catch (NullReferenceException) {

} }

public static void CloseMainScreen { try { if (mainScreen != null) { mainScreen.Dispose; mainScreen = null; } } catch (NullReferenceException) {

} }

public static void CloseLogOffWarning { try { if (logOffWarning != null) { logOffWarning.Dispose; logOffWarning = null; } } catch (NullReferenceException) {

} }

public static void CloseReports { try { if (reports != null) { reports.Dispose; reports = null; } } catch (NullReferenceException) {

} } code

The final portion of the program.cs to point out for forms is the logout method. In the logout method we needed to close all of the forms except the login form. To do so we could check if each form is open the close it, however, since in each close form method we have a double check to see if the form is open before trying to close it, we can simple call the close on all of the forms, just to verify each is closed. code format="csharp" public static void logout { secondsLoggedIn = 0; CloseCreateUser; CloseInputChild; CloseReports; CloseMainScreen; CloseLogOffWarning; ShowLogin; }

code If we need to open a form it would be a as simple as calling the Show method for the form in the Program.cs. As an example below the button click for opening create user. Since Program is a static class it does not need to be initialized, so we just need to call Program.ShowCreateUser. Note we are calling the createUser with the false, since we are creating a user and not editing a user.

code format="csharp" private void btnCreateUser_Click(object sender, EventArgs e) { Program.ShowCreateUser(false); }

code If we need to close the form we do the same thing as we did to open the form, only we will call the Close method for the form. Below is the example of were we all the Program.CloseCreateuser. Since it is the cancel button being clicked there is no data saved first, the form is just closed.

code format="csharp" private void btnCancel_Click(object sender, EventArgs e) { Program.CloseCreateUser; }

code Next we will look at adding to the forms. When adding any object to a form the IDE does most of the work for you. It writes the initial code to display to object, the text of the object and so forth. When adding the buttons for children in the class for the mainScreen (image below) the IDE added:



Of course we created the name and added the actual .text of the button, but the IDE auto created everything else. If in the Design view and you click on the button the IDE will create the event handler for you. In the code below you see what the IDE creates: code format="csharp" // // btnChild1 // this.btnChild1.Location = new System.Drawing.Point(40, 17); this.btnChild1.Name = "btnChild1"; this.btnChild1.Size = new System.Drawing.Size(190, 77); this.btnChild1.TabIndex = 0; this.btnChild1.Text = "Student Name"; this.btnChild1.UseVisualStyleBackColor = true; this.btnChild1.Click += new System.EventHandler(this.btnChild_Click);

code We anted to show two buttons. Since the buttons are identical and will perform the task if clicked, just with a different student. So what we did is modify the code the IDE created and pointed the buttons to the same click event handler. In the click event handler we parse the information form the button sender -- the name and ID of the student. The benefit of this is we only needed to write one event handler for all of out student buttons. code format="csharp" // // btnChild2 // this.btnChild2.Location = new System.Drawing.Point(40, 139); this.btnChild2.Name = "btnChild2"; this.btnChild2.Size = new System.Drawing.Size(190, 77); this.btnChild2.TabIndex = 1; this.btnChild2.Text = "Student Name "; this.btnChild2.UseVisualStyleBackColor = true; this.btnChild2.Click += new System.EventHandler(this.btnChild_Click);

code Outside of buttons on the other interesting things we used are panels. We wanted to create multiple different screens but wanted to stay on the same full screen for the task of managing students in the application. Instead getting the flashing of a form change we created multiple panels on a single form. When the user switches between tasks the application is actually hiding and displaying different panels.

As you can see below the activity screen (where the employee logged in can add a potty, feeding, nap, or medicine to the student selected form the mainScreen is actually the same form. We just hide the childPanel and displayed the activityPanel.



Following from the theme above here is the napPanel along with the code to switch the display. code format="csharp" private void btnNap_Click(object sender, EventArgs e) { code We added a auto-logout if the user is logged in without any activity for a set period of time. So, each time a button is clicked the inactivity counter is reset.: code format="csharp" Program.ResetSecondsLoggedIn = 0; code Next we hide the activityPanel: code format="csharp" activityPanel.Visible = false; code Since we are loading the napPanel we need to load the current time into the start date timePanel. The date and time are in a separate panel because they are used for more activities than just the nap, so we can hide and show the timePanel when needed. Additionally, we made the time panel editable incause the needed to change the time the activity started or stopped (as you will see from the image below).

code format="csharp" loadTime;

code Finally we show the timePanel and napPanel:

code format="csharp" timePanel.Visible = true; napPanel.Visible = true;

} code The results:



In addition to the information above we used textboxes, combo boxes, radio buttons, and checkboxes within the application. However, if we continue to the write-up on presentation we would need to limit the write-up on other topics.

=Chapter 32: Data Binding=

This project doesn't utilize data binding nearly as extensively as it utilizes the concepts from the data access chapter, however, parent users can access reports which include the DataGridView Control.

Data binding is a simple way to create a read/write link between form controls (discussed above) and the database. C# also allows you to bind to data in other structures, such as arrays and collections. Data binding is basically the link between the application’s user interface and the business logic.

Data binding is bridges your binding target and your binding source. Each binding has these four components: a binding target object, a target property, a binding source, and a path to the value in the binding source to use. In our application, we have a TextBox bound to the firstName property of a child object. The target object is the TextBox, the target property is the Text property, the value to use is firstName, and the source object is the child object.

code format="csharp" SqlDataAdapter da1 = new SqlDataAdapter("SELECT * FROM child",cn); da1.TableMappings.Add("Table","Child"); da1.Fill(ds); txtFirstName.DataBindings.Add("Text",dsView,"Child.firstName"); txtMiddleName.DataBindings.Add("Text",dsView,"Child.middleName "); txtLastName.DataBindings.Add("Text",dsView,"Child.lastName "); code

To establish the binding, the Binding object is used.

The two most useful events on the binding class are Format and Parse. These two events, raised when the data is pushed from the data source to the control or when the data is pulled from the control to the data source, allow you to do special validating and formatting of the data.

The Parse event is used when that data is changed in the control and needs to go back to the data source. The Format event is used for formatting the data from the data source before it is displayed on the control. When data is pushed from the data source to the control in the Format event is raised and you can perform whatever data formatting or validation is necessary prior to displaying it.

In our program, we use these events to convert the DateTime values associated with nap times to more readable information in the parent’s daily report: code format="csharp" private void textBoxDOB_FormatDate(object sender, ConvertEventArgs e) {

if (e.DesiredType != typeof(DateTime)) return; if (e.Value.GetType != typeof(string)) return; string value = (string)e.Value; try { e.Value = DateTime.Parse(value); } catch(Exception ex) { MessageBox.Show(ex.Message); }

} code