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.
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.
Use the "View" menu to make visible key subwindows such as Toolbox, Solution Explorer, and Properties.
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.
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:
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:
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:
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.
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.
=================================================== 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:
=================================================== 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.)
=================================================== 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!
http://www.dotnetperls.com/messagebox-showFor 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");
=================================================== 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; } } ===================================================
=================================================== Form3 dialog = new Form3(); DialogResult r = dialog.ShowDialog(); // pauses execution till dialog finishes if (r == DialogResult.OK) // then extract text: { string t = dialog.getText(); ... } ===================================================
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:
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(); } ... } } }
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. }
=================================================== 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.
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.
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();
}
}
}
===================================================
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.
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.)
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:
Here are three data structures that are hugely useful in practice:
=================================================== 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
http://www.dotnetperls.com/enumThe 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(); } } ===================================================
=================================================== 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: Listlist = new List ===================================================(d.Keys); // Loop through list: foreach (string k in list) { Console.WriteLine("{0}, {1}", k, d[k]); } Console.ReadLine(); }
=================================================== // 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 tickswhere
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.
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
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:
Within Form1, the handle to the Clock is named by the private field var, cl. (A private variable is labelled by a minus sign, -, or a "lock".) Form1 has a reference to exactly one clock. Notice that Form1 did not create the Clock, it does not own it; if the Form1 dies, the Clock remains. "Form1 refers to the Clock."
The coding that matches the picture looks like this:
public class Clock {
...
private int time;
public int getTime() { ... }
}
public class Form1 {
private Button button1; private Label label1;
private Clock cl;
...
public void onClick() { ...}
}
Notice that Form1 holds fields button1: Button and label1: Label. Now, Button and Label are classes, too, and if we truly wanted, we could draw class boxes for them. But since we don't need to show how class Button or Label connects to other classes, we just leave the Button and Label as names inside Form1.
In contrast, perhaps other components in our blueprint will need to link to class Clock, maybe because they share a clock or they make their own clocks. So, we need to draw class Clock as a box so we can draw links to it.
IMPORTANT: Say that Form1 does not remember the reference to
Clock within its own field. (Maybe it gets the handle to Clock through a
parameter to a method call, e.g.
onClick(c: Clock) is used in the above picture). Clearly,
Form1 still needs Clock to compile. We use a dashed arrow, like this:
The fieldname is gone.
The diamond should be solid black.
The multiplicities can be 1, 2, ..., n..m (n upto m), * (zero or more).
To indicate that the field name is an array, put it in braces:
Here, the Customer owns zero or more accounts, saved in an array (or list
or a single aggregate) named accts:
public class Account { private int balance;
private int idnumber;
. . . }
public class Customer {
private string name; private string address;
private Account[] accts;
. . .
public void deposit(int acct_id, int amount) { ... }
}
Finally, say that an Account holds a field that has the handle to
its owner, the Customer. We can add this information to the
diagram like this:
I trust you can read this ("the Customer owns possibly many
Accounts, saved in array, accts, and each Account knows the name
of its one owner, saved in field, owner"). The extra labelling is
important because it tells us how to design the code
of the two classes.
If you find the double labelling too hard to read, then recode the
less important labels as a field, like this:
I will let you do this, but you gotta do one or the other to be accurate
about the program structure.
Here, both Boss and Worker are subclasses of class Person.
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.
Nclass does not correctly transfer the labels on arrows into the generated C# files. Remember to add this manually.