If you don't have MS Outlook, you may want to give this a try for simple scheduling. You can use it to write one line activities at any hour throughout your lifetime. It also includes an alarm feature for notifying you of special events. Since it includes the source code, you can modify it to customize your scheduling needs.
The Scheduling program consists of three main classes. The Form (shown above), the DatabaseController used to read and write scheduled events into the database and RowData which corresponds to data extracted from a row in the database. UML Design is shown below:
The Above Design was Reverse Engineered using
WithClass 2000 UML Design Tool
There are many aspects of the C# .NET framework we could talk about in this code such as the use of the timer, listview manipulation, key capturing, calendar control, and edit box positioning. In this article, we will concentrate primarily on how to use ADO.NET to read and write the scheduling information. Below is a database snapshot of our calendar database:
The ADO.NET Library Framework provides a fairly simple means of reading and writing data to an access JET database. Reading from the database is performed in a few steps. First, you set up what's called an ADODataSetCommand Object. This object allows you to assign SQL commands to it in order to manipulate the database. The code for assigning a command to this object is shown below:
- private ADODataSetCommand AdoCmd = new ADODataSetCommand("SELECT * FROM Activities", "Provider=Microsoft.JET.OLEDB.4.0;data source=calendar.mdb");
-
- ...........
-
- AdoCmd.SelectCommand.CommandText = "SELECT * FROM Activities WHERE Date = #" + strDate + "#";
Here we have a DataSet Command Object in which we change the command to filter only Activity rows that are performed on a specific date. These are the rows we will display in our listview located on the left side of the form. Once we have the DataSet Command Object setup, we can create a dataset and fill it:
- DataSet dtSet = new DataSet();
- AdoCmd.FillDataSet(dtSet, "Activities");
The DataSet can now be used to extract information from the table. The table reference is gotten from the collection of tables in the dataset. Our database only has one table "Activities", so we can just get the first table, indexed at 0. Once we have the reference to the DataTable, we can go through the Rows collection and extract each row of information from the table. A Column of information in a row is extracted by dereferencing using the column name of the table (e.g. dtRow["Activity"] ). You could also use the column index (e.g. dtRow[4]):
- DataTable dTable = dtSet.Tables[0];
-
- foreach(DataRow dtRow in dTable.Rows) {
- nCount = CalcRow(dtRow);
-
- listView1.ListItems[nCount].SetSubItem(0, dtRow["Activity"].ToString());
-
- if (dtRow["IsAlarm"].ToString().ToBoolean() == true) {
- listView1.ListItems[nCount].ImageIndex = 1;
- } else {
- listView1.ListItems[nCount].ImageIndex = 0;
- }
- }
Writing in ADO.NET is a bit more, well, complicated. To write (insert) a new row, I used a simple method provided by the Rows Collection object called AddUpdate. Below is a snippet of code from the WriteOutActivities routine in the DatabaseController to show how this command is used:
-
-
-
- AdoCmdAll.SelectCommand.CommandText = "SELECT * FROM Activities ORDER BY ID";
- AdoCmdAll.FillDataSet(dtSetAll, "Activities");
- ..........
- int nMax = 0;
- DataTable dTableAll = dtSetAll.Tables[0];
- if (dTableAll.Rows.Count > 0) {
-
- nMax = dTableAll.Rows[dTableAll.Rows.Count - 1]["ID"].ToString().ToInt32() + 1;
- }
- if (nMax < 0) {
- nMax = 0;
- }
-
- dTableAll.Rows.AddUpdate(new object[] {
- nMax,
- strDate,
- Time2Integer(listView1.ListItems[index].Text),
- IsRowAM(index),
- listView1.ListItems[index].SubItems[0],
- (listView1.ListItems[index].ImageIndex == 1)
- });
- ........
-
- AdoCmd.Update(dtSetAll, "Activities");
First, the Maximum ID is calculated to get a brand new unique primary key. The maximum row is determined by forcing the dataset to return the rows in order using ORDER BY ID in the SQL statement of the DataSet Command. Then the row of data including the ID (Primary Key), date, time, am/pm flag, activity, and an alarm flag is added using the AddUpdate command. Finally, we need to call Update on the DataSet Command Object, AdoCmd to force the changes to take place from the dateset into the database.
Editing an existing row is done a bit differently. Below we show how to update a row in the database that turns the alarm flag off in an activity. This is done by calling BeginEdit on a row, changing the data in the row and then calling EndEdit. Afterwards, we call Update on the ADODataSetCommand, to make sure the changes are saved in the database:
- public void DeleteAlarm(int nKey) {
- try {
-
- AdoCmd.SelectCommand.CommandText = "SELECT * FROM Activities WHERE ID = " + nKey.ToString();
- DataSet dtSet = new DataSet();
- AdoCmd.FillDataSet(dtSet, "Activities");
- DataTable dTable = dtSet.Tables[0];
-
- foreach(DataRow dtRow in dTable.Rows) {
- dtRow.BeginEdit();
- dtRow["IsAlarm"] = false;
- dtRow.EndEdit();
- }
-
- AdoCmd.Update(dtSet, "Activities");
- } catch (Exception exx) {
- System.Console.WriteLine(exx.Message.ToString());
- }
- }
That's really all there is to it. I think you'll find it is a little more intuitive than the recordset concept in Visual C++. As far as the Scheduling program is concerned, look forward to future enhancements such as printing your daily schedule. Happy Scheduling!