Copyright © 2012 David Schmidt

Lecture 0:
Using C# with Visual Studio and Nclass


0.1 New Projects
    0.1.1 Basic IDE operations
0.2 Console application
0.3 Forms application
    0.3.1 Widgets
    0.3.2 Widget event handling
0.4 Using the debugger
0.5 Inserting multiple classes in a namespace
    0.5.1 Building a library class; linking to it
    0.5.2 Generating GUI message boxes, input dialogs, and passive views
0.6 Multiple GUIs with buttons
0.7 Multiple GUI threads
    0.7.1 Using lock on an object shared by two threads
    0.7.2 Multiple threads of execution
0.8 Compiling a project into binary
    0.8.1 Doing the above work without VS
    0.8.2 Unit testing
0.9 Useful C# concepts
    0.9.1 Lists (dynamic arrays)
    0.9.2 Enumerations
    0.9.3 Dictionaries
    0.9.4 Delegates
    0.9.5 Textfile I/O and String manipulation
0.10 Using UML class notation
    0.10.1 Using Nclass


Visual Studio ("VS") helps you construct a C# project that you can test and later compile into an .exe or .dll file. You can download, for free, Visual Studio C# 2010 Express from here.

IMPORTANT: Use the web site, www.dotnetperls.com as your "reference text" when you use Visual Studio to develop C# programs. It is an easy-to-consume, example-driven introduction to the useful parts of C#. Any details I omit here you will find in www.dotnetperls.com.


0.1 New Projects

Open VS and click on "New Project". A new window appears. The three useful choices are
  1. "Windows Forms App" (generates a default GUI)
  2. "Class Library" (for a standalone library class (.dll file))
  3. "Console App" (for a DOS-window-based app)
Remember to fill in the name of your new project on the bottom. Rod Howell's style is "RodHowell.Cis300.MyProjectName".

Technical note: actually, VS creates a ``solution'' that holds a ``project'' (a project is a C# package). It is possible to add a second project to the same solution: You do this by right-clicking on the solution name in the Solution Explorer window then then select ADD then NEW PROJECT. If you look at the folder structure that is created, you will find a folder holding the ``solution'' which holds two folders that are ``projects'' (C# packages). Be careful if you do this trick.


0.1.1 Basic IDE operations

Click on green arrow to run app.

Use the "View" menu to make visible key subwindows such as Toolbox, Solution Explorer, and Properties.


0.2 Console application

If you construct a new project that is a console application, you will receive a class that contains a Main method. From this point, you can code vanilla C#, say, like the examples in my CIS200 notes from 2008. (Scroll to the bottom of the page for the relevant links.)


0.3 Forms application

If you construct a new project that is a forms application, you will receive a class, Form1.cs that holds a C# form widget. You drag and drop widgets into it.

Note that the default file names are "Form1.cs" and "Program1.cs". You can change these. To do it, within Solution Explorer, right click on file name and use menu to change it, e.g., "Form1.cs" to "View.cs".

If you are building a Forms App, Click on the "Design" tab of "Form1.cs" to see the GUI layout. You can double click on the GUI to see its code.


0.3.1 Widgets

You can change size of a widget by dragging its borders. You can change its title by changing its "Text" value in the Properties window. There are a lot of properties for a widget (e.g., Size, Anchor); see the list of widgets and key properties below.

You add widgets to a GUI with the Toolbox. Example: go to Toolbox, select Toolstrip and then click on the GUI to drop the widget. You can change the Properties of the toolstrip. (Click on the widget to activate its properties in the Properties window.) Each widget has a name, a font, a color, an anchor. (You can Anchor a button so that it does not float in the layout in its parent widget is resized.)

IMPORTANT: to change the var name of the widget in the source code, change the "(Name)" entry in its Properties list. Eg., Change "toolstrip1" to "uxToolStrip".

Here are some widgets and key properties:

Each widget has a name, a font, a color, an anchor. You can Anchor a button so that it does not float in the layout in its parent widget is resized. In Toolbox, in Common Components, you can find tools like Web Browser, that you can select and insert. See www.dotnetperls for examples of other useful widgets.

It is also possible to add to Common Components a widget that someone else (or you) has written. Assume this widget is packaged as a .dll file.

Example: Rod Howell has written a widget he titled, "Drawing". Here's his explanation:

The large white box in the GUI is a control that is not defined in the .NET Framework, and is therefore not yet in the Toolbox. The code for this control is posted as RodHowell.Cis300.Components.dll with this assignment. You will need to download that file, then right-click on "Common Controls" in the Toolbox. In the resulting popup menu, select "Choose Items...". In the resulting window, click the "Browse" button, and navigate to the location of RodHowell.Cis300.Components.dll. This should add the class Drawing to the list in the window - make sure this class is checked, and click "OK". The Drawing class should now appear at the end of "Common Controls" in the Toolbox.

Documentation for this class is also posted. When you open this documentation, you will get a Security Warning. In this window, you will need to uncheck the box, "Always ask before opening this file." If you don't uncheck this box, you will get a message, "Navigation to the webpage was canceled", and you will not see the documentation.

Now that Drawing is in the Toolbox, add one of the appropriate size to complete your form. You will need to change the following properties:

  • (Name)
  • Anchor
  • BackColor: This property controls the background color of the Drawing. It needs to be White.


0.3.2 Widget event handling

To add "the usual" event handler to a widget, double click on it in the GUI display. This generates an event-handler template in your class Form; within in this type the handler code. to see component's code. For example, for a button named, uxHome,
private void uxHome_Click(object sender, EventArgs e)
        {
            uxBrowser.GoHome();   // the code I added
        }
This handles the button click by calling method GoHome in object uxBrowser.

IMPORTANT: there is a huge list of events associated with a widget. To see them, click on the widget and in the Properties window, click on the lightning bolt ("events") to see all the events to which event handlers can be associated. You click on an event, and VS will generate the appropriate template for its handler.

You should read Rod Howell's first GUI assignment in CIS300 to get tips for using VS to build widgets.


0.4 Using the debugger

To run an app, just press the green |> button on VS. But you can stop the program in the middle of execution and look at the values of its variables by using the debugger. Here's how:

Set breakpoints: easiest way is to click to the left of the line where you want to step: click on the left vertical grey bar. Or, use cursor to select a line where you want to stop. Use DEBUG menu item and select TOGGLE BREAKPOINT. This marks the line (you will see a blob at the left of the line). Next, use DEBUG menu and select WINDOWS, then LOCAL. (You can also select CALL STACK window.)

Now, use DEBUG, START DEBUGGING. The program will run and stop at the selected breakpoint. In the window at the bottom, you should see the values of the variables that are visible at the program point, and you will see the stack of unfinished method calls. (If you don't see this stuff, select DEBUG, WINDOWS, LOCAL and also CALLSTACK and also AUTOS.) Click the green button to continue to the next breakpoint. (You can insert multiple breakpoints, of course. You can remove a breakpoint by selecting it with the cursor and then use DEBUG, TOGGLE BREAKPOINT.)

You can also single-step (run-and-stop, one line at a time) using the "step into" button, which is immediate to the right of the green arrow. (Or, select menu DEBUG and STEP-INTO. Note the short-cut key for doing multiple steps.) Step-into will enter called methods, too.

You can single-step but not enter called methods by clicking "step over" button.

You can exit the currently active method and execute to the method's call point by clicking "step out".

About the debug windows: in addition to LOCALS and CALL STACK and AUTOS, you use WATCH to enter vars or exprs whose values you wish to query at each breakpoint. You can use the IMMEDIATE window as an expr interpreter that uses the current context at the current breakpoint.


0.5 Inserting multiple classes in a namespace

You can always type multiple classes in one and the same file, e.g.,
===================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Hello2
{
    class Program
    {
        static void Main(string[] args)
        {
            new F().f();
        }
    }

    class F
    {
        public void f()
        {
            Console.Write("Please type your name: ");
            string input = Console.ReadLine();
        }
    }
}

===================================================
But it is usually better to have the extra class in another file but still listed as part of the same namespace. You do this:
  1. Use the PROJECT menu, select ADD CLASS (or ADD COMPONENT, then ADD CLASS). This generates
    ===================================================
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Hello2
    {
        class Class2
        {
        }
    }
    
    ===================================================
    that you fill in. (Remember, to rename Class2, just right-click on it in the Solutions window.)
  2. Now you can use it in the other files of your project.


0.5.1 Building a library class; linking to it

You create a stand-alone library class or classes by making a New Project that is a "Class Library". The class in the previous example might be done like this:
===================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FUtility
{
    public class F
    {
        public void f()
        {
            Console.Write("hello ");
            string input = Console.ReadLine();
        }
    }
}

===================================================
Once it is finished, use the BUILD SOLUTION menu item, listed under menu BUILD or DEBUG.

To use it in another program, do these steps. Write the project that uses it:

===================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FUtility;   //  IMP: add this line!

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            F ob = new F();  ob.f();
        }
    }
}

===================================================
Notice the line, using FUtility. Next, in the PROJECT menu, choose ADD REFERENCE, and use the browser window to locate and select the class, labelled as a .dll file, e.g., HelloClass.dll. This links the external class to the project.

Note: you can also link to the class by right clicking on the "References" item in the Solution Explorer window.

Important: if the dll should not be edited by you, then link (add reference to) the dll file in the bin subfolder and not the ``project'' that generated the dll file. The latter step loads the source code into VS and lets you alter it!


0.5.2 Generating GUI message boxes, input dialogs, and passive views

C# has a built-in message box (dialog). Here is a link about how to construct them:
http://www.dotnetperls.com/messagebox-show
For example:
DialogResult result = 
     MessageBox.Show("Continue?", "Question", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)  {
    MessageBox.Show("You answered yes.");
}
MessageBox.Show("Click to exit.", "The End");

Input dialog

C# does not have an input dialog box, but you can make one from a form:
  1. use VS to select PROJECT, ADD FORM. This adds a new form to your project. Use VS to add a textbox and a button IMPORTANT: in the button's properties, set its DialogResult to OK. (This makes the dialog finish when you click the button!)
  2. Add an event handler for the button click, and add a method that later returns the text typed in the textbox:
    ===================================================
    
        public partial class Form3 : Form  
            private string x;  // saves info typed in the text box
    
            public Form3() {
                InitializeComponent();
            }
            ...
    
            private void button1_Click(object sender, EventArgs e)  {
                x = textBox1.Text; 
                // Dispose();  // forces termination.
    
           // call this later to obtain text typed in dialog:
           public string getText() { return x; }
        }
    
    ===================================================
  3. Whenever you need to use the dialog in the program, do this:
    ===================================================
    
    Form3 dialog = new Form3();
    DialogResult r = dialog.ShowDialog(); // pauses execution till dialog finishes
    if (r == DialogResult.OK)   // then extract text:
       { string t = dialog.getText();  ... }
    
    ===================================================

Passive output form

You can easily remake a VS Form application so that the Form is "passive", that is, it merely displays output data like a command window (and does not have buttons or text fields for input). This makes it easy to convert a console application into a Forms application.

First, say that you insert a label, call it label1, into Form1. The label will be your "command window." Next, add this method to class Form1:

===================================================

public void WriteLine(string s) { 
    label1.Text = label1.Text + "\n" + s; 
    Refresh(); 
}

===================================================
Notice that Refresh is called to redraw the updated Form. You call WriteLine each time you want to generate a new line of output.

Also, if you plan to construct multiple instances of Form1 (maybe one form for each player in a game), then you must position each new instance so it does not overlap the others. Use static variables and Form1's Location field like this:

public partial class Form1 : Form {
    // coordinates for upper left corner of the visible Form:
    static int xPosition = 0;  
    static int yPosition = 0;

    public Form1() {
       InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    { // set location of where to display the new Form1:
      this.Location = new Point(xPosition,yPosition); 
      // update position coordinates for the next time a Form1 is created:
      xPosition = xPosition + this.Width; 
      yPosition = yPosition + 50;
    }

    // adds a new line of text, s,  to the output:
    public void WriteLine(string s) { 
      label1.Text = label1.Text + "\n" + s; 
      Refresh(); 
    }
  }

Now, change the Main method in the Forms application to look like this:

===================================================

static void Main() {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    //Application.Run(new Form1());  // DON'T GIVE CONTROL TO Form1

    // PLACE CODE HERE THAT CONSTRUCTS YOUR SYSTEM AND RUNS IT:
    // as needed, here or elsewhere, construct Form1 objects and use them:
    Form1 f = new Form1();
    f.Show();
    ...  f.WriteLine("hello"); ...

    MessageBox.Show("Click to exit.");
}

===================================================
You can generate as many Form1's as you want --- they are merely objects that happen to have a visual presentation on your display. You can also construct distinct Form classes and display as many as you like:
  1. Use VS to select PROJECT, ADD FORM. This adds a new form to your project. Use VS to edit its widgets.
  2. Add to the form the methods that are called when the form must be updated, e.g.,
        public partial class Form2 : Form  {
            public Form2() { InitializeComponent(); }
    
            // Say that  Form2  has a label named  label2 :
            public void update(string s) {  label2.Text = s;  Refresh(); }
            ...
            }
        }
    }
    
  3. Construct and show the Form2 objects just like the example earlier, e.g.,
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
    
        Form1 f = new Form1(); f.Show();
        Form2 g = new Form2(); g.Show();
        ... f.WriteLine("hello"); ... g.update("hi"); ...
    
        Application.Run(new Form1());  // this would construct another
                          //  instance of Form1 and give control to it.
    }
    
The above code hands control to the widgets in Form1, but g.update(...) can be called as needed to refresh the data displayed in the passive form.


0.6 Multiple GUIs with buttons

Say that you want to have two or more Forms that each have buttons that trigger computation when pressed. Here is how you change the Main method to do this:
===================================================

static void Main() {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      // Say that Form1 has some buttons on it.
      // We can construct two of it, and the the buttons on both forms
      // are alive:
      Form1 f = new Form1(); f.Show();  // remember to  Show  the form
      Form1 g = new Form1(); g.Show();
      Application.Run();  // there is no need for an argument to  Run!
    }

===================================================
Now, even if you "kill" both of the above forms by pressing their X-buttons in the upper right corner of the forms, the program is "stuck" in its Run method, which is listening for events for all zero remaining forms.


0.7 Multiple GUI threads

Real-life systems are often running on multiple processors. We can learn about this form of behavior by creating one C# program that "splits" into multiple "threads" of execution. (In principle, each thread runs on its own processor.)

Here is our starter example: Say we want one application to generate two forms, each with its own thread of execution. Here's how to rewrite Program.cs:

===================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;  //  ADD ME

namespace TestWindow
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            new Thread(Driver1).Start();   // ADD ME
            new Thread(Driver2).Start();   // ADD ME
            MessageBox.Show("Forms started in their own threads");

            //Application.Run(new Form1());   // no need for this
        }

        // ADD THESE PROCEDURES:
        static void Driver1() 
        { Application.Run(new Form1()); }
        static void Driver2() {
        { Application.Run(new Form2()); }
    }
}

===================================================
The code generates two threads of execution (activation stacks, instruction counters) Then it finishes the main thread and shows the message box.


0.7.1 Using lock on an object shared by two threads

First off, threads can be dangerous. Say that two threads of execution wish to share an object (example: a database shared by two view objects). Access to the shared object must be controlled so that only one thread executes the object's code at a time.

C# has a primitive critical-section operation, called lock, which uses an object's handle as a kind of semaphore. Here is an example of a clock object that is shared by three threads of execution. (You place a ''lock'' around the body of each method to the shared ob, that is, fake a Brinch-Hansen-style monitor. )-:

===================================================

 ...
namespace Test
{
    // objects constructed from this entity (model) class are share-able:
    public class Clock      // note the uses of  lock(this)  !!!
    {
        private int i = 0;

        public void tick()
        { lock (this) { i = i + 1; } }

        public int getTime()
        { lock (this) { return i; } }
    }
}


using System;
 ...
using System.Threading;  // needed for multiple threads
namespace Test
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Clock c = new Clock();
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            new Thread(Driver).Start(c);    // note that  c  is the arg!
            new Thread(Driver2).Start(c);   // same here
            Application.Run(new Form1(c));  // same here
        }

        static void Driver(Object c)  // you can pass an object to a new thread
        {   Application.Run(new Form2((Clock)c)); }

        // runs yet another thread, a controller which ticks the clock each second:
        static void Driver2(object x) {
            Clock c = (Clock)x;
            while (true) {
                Thread.Sleep(1000);  // sleep 1 second
                c.tick();
            }
        }
    }
}

 ...
namespace Test
{
    public partial class Form1 : Form
    {
        private Clock d;
        public Form1(Clock c) {
            d = c;
            InitializeComponent();
        }
        // Say that  Form1  has a button:
        private void button1_Click(object sender, EventArgs e)
        { d.tick(); }
    }
}

 ...
namespace Test
{
    public partial class Form2 : Form
    {
        private Clock d;
        public Form2(Clock c) {
            d = c;
            InitializeComponent();
        }
        // Say that  Form2  has a button and a label:
        private void button2_Click(object sender, EventArgs e)
        { int t = d.getTime();
          label2.Text = t.ToString(); Refresh();
        }
    }
}

===================================================


0.7.2 Multiple threads of execution

Here are three ok references:
http://msdn.microsoft.com/en-us/library/c5kehkcz%28v=vs.71%29.aspx

http://www.albahari.com/threading/part2.aspx

http://www.c-sharpcorner.com/UploadFile/1d42da/thread-locking-in-C-Sharp/
All of them encourage you to use a "thread delegate" construction when generating a new thread, e.g.:
===================================================

using System;
using System.Threading;

class ThreadTest 
{
   public void runme() { Console.WriteLine("runme called"); }

   public static void Main() {
      ThreadTest b = new ThreadTest();
      Thread t = new Thread(new ThreadStart(b.runme));
      t.Start();
   }
}

===================================================
I don't know if this is safer than the naive version of threads that I already showed you.


0.8 Compiling a project into binary

Use the BUILD SOLUTION menu item (listed under either BUILD or DEBUG) to do this. Always do this when finishing a new Class Library (dll) project.


0.8.1 Doing the above work without VS

The C# compiler can be used standalone, from a command window, to compile and test programs and library components. The details are found in my CIS200 notes from 2008 --- see the last four links on that page.

If you want a GUI for your C# program, then you are stuck using VS; it's too much work to build a GUI by hand in C#. In contrast, other languages (e.g., Python) make GUI-building not so hard. (See the previous link.)


0.8.2 Unit testing

The components (classes) of a system should be tested individually (or in an order where the class to be tested depends only on classes that are already tested). This is called unit testing.

To unit-test a class, you should write code to construct it and call all its methods. The tests should make full use of the methods, fields, and their interactions. Place the tests in static methods and call them from Main. Here's an example:

===================================================

public class Clock {
   private int t = 0;

   public void tick() { t = t + 1; }

   public int getTime() { return t; }
}
Here is a unit test:

public static void Main() {
   // place unit tests here:
   testClock();
}

public static void testClock() {
   Clock c = new Clock();
   for (int i = 0; i <= 20; i++) {
       Console.WriteLine(c.getTime());
       c.tick();
  }
}

===================================================
Now, if class Clock is already part of a Console Application, we revise the Main procedure to test it. But Clock might be coded in a Class Library (.dll) or a Form Application, which cannot be started by Main.

In Java, we can insert Main into class Clock and execute Clock as an application! But C# won't let us do this trick. So, we must generate a new project to hold Main.

The full version of Visual Studio has a Test menu that can generate a project containing the test code. The free version doesn't, so here's what you do to unit-test:

  1. Open the project, say it's named CCC, where class Clock lives.

  2. Select File then Add then New Project. Make a Console Application, name it UnitTest, and save it in CCC's folder. This makes a second, separate folder, and in the Solution Explorer window, you will see both CCC and UnitTest listed.

  3. In the Program.cs file in project UnitTest, insert your test methods and call them from Main. At the top, remember to type using CCC; and remember to select Project then Add Reference then select CCC. This links the test code to the class.

  4. To run your Main method, you must set it as the ``start up'': Go to the Solution Explorer window and click on the name, UnitTest. Then, select Project then Set as StartUp project.

  5. Now you can Debug as usual.
When you are finished testing, leave UnitTest where it is. It can be used in the future to test any modifications to the project.


0.9 Useful C# concepts

You will find additional helpful material at wwww.dotnetperls.com.

Here are three data structures that are hugely useful in practice:


0.9.1 Lists (dynamic arrays)

Most of the time, the arrays you use will need to grow and shrink. That is, you want a list, not an array. Lists are faked in C# by a library class, List. Here are two links for reference:
===================================================

http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx

http://www.dotnetperls.com/list

===================================================
Here are the basic ideas:
===================================================

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
	List<int> list = new List<int>();
	list.Add(2);
	list.Add(3);
	list.Add(7);
        Console.WriteLine(list.Count);  // prints 3
        Console.WriteLine(list[2]);  // OK to index like an array

	foreach (int i in list)
	{
	    Console.WriteLine(i);
	}

        // Can add elements at any position and can remove them:
        list.Insert(0, 2);  // places the  2  at index 0 and shifts the rest
        list.RemoveAt(list.Count - 1); // removed rightmost element
    }
}

===================================================
There are also operations for finding elements, slicing, etc.; see the first reference listed just above.

C# lists work well with the ListBox widget; see http://www.dotnetperls.com/listbox


0.9.2 Enumerations

When you want a data type that is a set of named values, e.g., the days of the week, or the suits of a deck of cards, you can define it with an enumeration type, which is a macro for a static class. Here is a decent reference:
http://www.dotnetperls.com/enum
The example shows what you need to know:
===================================================

using System;

class Program
{
    enum Suit {Spades, Hearts, Diamonds, Clubs};

    static void Main()
    {
        Suit mycard = Suit.Hearts;
        Console.WriteLine(mycard);       // prints  Hearts
        Console.WriteLine((int)mycard);  // prints 1

        if (mycard == Suit.Hearts) {Console.WriteLine("ok");}

        foreach (var suit in Enum.GetValues(typeof(Suit)))
        { Console.WriteLine(suit); };

        Console.ReadLine();
    }
}

===================================================


0.9.3 Dictionaries

The world's best secret weapon for quick table building. (A dictionary is a kind of hash table that is indexed like an array.) Thankfully, they are "almost built-into" C#. Try these:
===================================================

static void Main(string[] args)
{           // a dictionary mapping string keys to int values:

            Dictionary<string, int> d = new Dictionary<string, int>();

            d["flea"] = 1000;
            d.Add("cat", 3);
            d.Add("dog", 1);
            Console.WriteLine(d["cat"]);
            d["cat"] = d["cat"] - 1;;
            Console.WriteLine(d["cat"]);

            if (d.ContainsKey("cat")) { Console.WriteLine(d["cat"]); }
            // how to traverse a dictionary:
            foreach (var pair in d)
            {  Console.WriteLine("{0}, {1}", pair.Key, pair.Value);  }

            // Store the keys in a List:
            List list = new List(d.Keys);
            // Loop through list:
            foreach (string k in list)
            { Console.WriteLine("{0}, {1}", k, d[k]); }
            
            Console.ReadLine();
}

===================================================


0.9.4 Delegates

Sometimes a method must call another method without knowing its name. Here is an example, a queue object that holds a list of tasks that must be completed once some signal occurs. The names of the tasks don't matter --- what matters is that each task is called. The code uses the C# delegate type and looks like this:
===================================================

// defines a datatype,  Task,  which is the type of methods 
//   that take zero arguments and return no answer:
delegate void Task();

class TaskQueue {  // holds a list of tasks to do
    private List<Task> queue;

    public TaskQueue() { 
      queue = new List<Task>();  // empty list
    }

    public void addTask(Task t) { queue.Add(t); }

    // executes all queued tasks (methods) when signalled:
    public void signal() {
        foreach(Task t in queue) { t(); }  // execute all the tasks
        queue.Clear();   // empty  queue  all at once
    }
}

===================================================
The system can use a TaskQueue like this:
TaskQueue q = new TaskQueue();
Clock c = new Clock();
Clock d = new Clock();
q.addTask(c.tick);
q.addTask(d.tick);
q.addTask(c.tick);
// ... later ... :
q.signal();  // executes the queued ticks
where
public class Clock {
   private int t = 0;
   public void tick() { t = t + 1; }
   public int getTime() { return t; }
}
This technique is standard to operating-systems coding. It can also be used to save multiple event-handlers that are called when a single event is signalled:
delegate void ButtonClickHandler(object sender, EventArgs e);

public class Controller {
    private List<ButtonClickHandler> handlers = new List<ButtonClickHandler>();

    public void register(ButtonClickHandler h) { handlers.add(h); }

    public void signal(object sender, EventArgs e) {
        foreach (ButtonClickHandler h in handlers) { h(sender, e); }
    }
}
Say we have a Form with a button, button1. We construct
Controller c = new Controller();
and we tell Visual Studio to call c.signal when button1 is clicked. Then, when the button is pressed, c.signal(..,..) executes and itself executes all methods saved in c's handlers list.


0.9.5 Textfile I/O and String manipulation

A disk file is found with its path, which is usually written as a string, e.g, "C:\\Users\\Me\\Documents\\file.txt". You can also use a "relative path", e.g., "file.txt", which means find file.txt in the same folder where the program's exe code lives. Another example: "..\\..\\..\\file.txt" which means find the file 3 folder-levels higher than where the program's exe code lives. This is an OK path for data files for your VS Solution, because it is located at the top-level folder of the Solution. (Try the examples below with VS to see what I mean.)

Here are some examples that read and write text files:

===================================================

// Write a string array to a file:
string[] stringArray = new string[] {"cat","dog","arrow"};
File.WriteAllLines("..\\..\\..\\file0.txt", stringArray);

// Write a long string to a file (note the  \r\n  to end each line):
File.WriteAllText("..\\..\\..\\file1.txt", "a \"cat\"\r\na dog\r\n");

// Read a text file into one long string:
string contents = File.ReadAllText("..\\..\\..\\file0.txt");

// Read lines of a text file into a string array:
string[] lines = File.ReadAllLines("..\\..\\..\\file0.txt");

// Read file's lines one by one:
StreamReader reader = new StreamReader("..\\..\\..\\file1.txt"));
string line = reader.ReadLine();
while ((line != null) {
        Console.WriteLine(line);
        line = reader.ReadLine();
}

// A more terse way of doing the previous loop:
StreamReader reader = new StreamReader("..\\..\\..\\file1.txt"));
string line;
while ((line = reader.ReadLine()) != null) {
        Console.WriteLine(line);
}

// Write file's lines one by one:
StreamWriter writer = new StreamWriter("..\\..\\..\\file2.txt"));
foreach(string line in lines) {
    writer.WriteLine(line);
}

===================================================
Here are examples for disassembling a string into its parts:
===================================================

string s = " <folder \"A.B.C\">  ";  // string is   <folder "A.B.C">

if (s.Contains("<folder")) {   // ask if substring is found in  s
    Console.WriteLine("folder");
    int start = s.IndexOf('\"');          // find  "  starting from index 0 in  s
    int end = s.IndexOf('\"', start+1);   // find  "  starting from index  start+1
    Console.WriteLine(start + " " + end); // writes  9 15

    // extract substring:   Substring(startIndex, LengthToExtract) :
    string path = s.Substring(start + 1, (end - start) - 1); 
    Console.WriteLine(path);  // writes  A.B.C

    // split a string into pieces, where  '.'  is the separator char:
    string[] names = path.Split('.');
    foreach (string n in names) { Console.WriteLine(n); }
}

===================================================
Here are references that might help:
http://www.csharp-station.com/HowTo/ReadWriteTextFile.aspx

http://www.dotnetperls.com/file


0.10 Using UML class notation

Before you do much work with VS or any editor, you should draw a blueprint of the system you will build. Use the class-diagram language from UML to draft your components.

There is a reasonable introduction to the class-diagram language at http://www.cs.sjsu.edu/~pearce/modules/lectures/uml/class/index.htm.

Here is a link with some useful tips: http://www.csci.csusb.edu/dick/cs201/uml.html.

The complete notation is overwhelming. We will use these parts:

  1. components: class (name in normal font)), abstract class (italic font), interface (italic font)

  2. fields and methods (typed inside the component): public (+), private (-), abstract (italicized) or static (underlined).

  3. associations: these will be solid lines and dotted lines, as explained below. We annotate an end of a line with two (optional items): beneath the line, a (field)name, and above the line, a multiplicity. Sometimes a line has a kind of arrowhead. See below for examples.
We will use these forms of associations (but there are many more!):

When we construct "use-case realizations", we will use Collaboration Diagrams, which show the objects constructed from class diagrams and the order in which they call one another.


0.10.1 Using Nclass

http://nclass.sourceforge.net/ is a free, useful tool for drawing class diagrams. It can generate a VS project from just the class diagram you draw. It is dead easy to use. (There is no user manual; just click or double click on icons, names, etc., to see all the options.) By the way, Visual Studio 2012 appears to have a class-diagram drawing utility that appears to operate similarly to Nclass.