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" or "uxForm.cs".
If you are building a Forms App, Click on the "Design" tab of "Form1.cs" to see the GUI layout. You can see the code by right-clicking on "Form1.cs" in the Solution Explorer window and selecting "View Code", or you can double click on the GUI itself 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. We won't do much of that here, but check back to your CIS300 notes to see how Dr. Howell did this.
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 few GUI-based assignments 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; a red blob will appear. 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).
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 clicking on its blob or 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" menu item in DEBUG. 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 selecting "STEP OVER".
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 expression 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(); } } } ===================================================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 your new class library in another program, do these steps:
First,
write the project that uses it:
===================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FUtility; // IMPORTANT: 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-showHere's an 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 MyDialog : Form private string x; // saves info typed in the text box public MyDialog() { InitializeComponent(); } ... private void button1_Click(object sender, EventArgs e) { x = textBox1.Text; // Dispose(); // forces termination. // call this later to obtain the text typed in the dialog: public string getText() { return x; } } ===================================================
=================================================== MyDialog dialog = new MyDialog(); DialogResult r = dialog.ShowDialog(); // pauses execution till dialog finishes if (r == DialogResult.OK) // then extract text: { string t = dialog.getText(); ... } ===================================================
You can easily make a VS Form application so that its 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, create a new form and name it PassiveForm.
Next, insert a label, call it label1,
into PassiveForm. The label will be your "command window."
Next, add this method to class PassiveForm:
===================================================
public void WriteLine(string s) {
label1.Text = label1.Text + "\n" + s;
Refresh();
}
===================================================
Notice that the built-in method, 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 PassiveForm
(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 PassiveForm's Location field like this:
public partial class PassiveForm : Form {
// coordinates for upper left corner of the visible passive form:
static int xPosition = 0;
static int yPosition = 0;
public PassiveForm() {
InitializeComponent();
}
private void PassiveForm_Load(object sender, EventArgs e)
{ // set location of where to display the new passive form:
this.Location = new Point(xPosition,yPosition);
// update position coordinates for the next time a passive form 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 PassiveForm()); // DON'T GIVE CONTROL TO THE FORM !
// PLACE CODE HERE THAT CONSTRUCTS YOUR SYSTEM AND RUNS IT:
// As needed, here or elsewhere, construct passive form objects and use them:
PassiveForm f = new PassiveForm();
f.Show();
... f.WriteLine("hello"); ...
MessageBox.Show("Click to exit.");
}
===================================================
You can generate as many passive forms as you
want --- they are merely objects that happen to have a visual
presentation on your display.
Here is an example, where there is a "main", "active" GUI,
Form1,
and two passive forms:
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
PassiveForm f = new PassiveForm(); f.Show();
PassiveForm g = new PassiveForm(); g.Show();
... f.WriteLine("hello"); ... g.WriteLine("hi"); ...
Application.Run(new Form1(f, g)); // this would construct the "active"
// Form1 and give control to it.
// Notice that we altered Form1's constructor to receive the handles to
// the passive forms so that it can write to them as desired.
}
=================================================== 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. (Use Application.Exit() when you want to force all forms in the entire program to stop.)
It is also OK for a Forms App to start a "main form", which itself constructs more forms. All the buttons on all the forms will be active.
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 object, that is, fake a Brinch-Hansen-style monitor. )-:
===================================================
...
namespace Test
{
// objects constructed from this entity (model) class are shareable:
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 Visual Studio has a Test menu that can generate a project containing the test code. But the format of tests is not so easy to work with (it's like a whole separate programming language). So here's a simple way 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();
}
reader.Close(); reader.Dispose();
// 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);
}
reader.Close(); reader.Dispose();
// Write file's lines one by one:
StreamWriter writer = new StreamWriter("..\\..\\..\\file2.txt"));
foreach(string line in lines) {
writer.WriteLine(line);
}
writer.Close(); writer.Dispose();
===================================================
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:
public class Clock { ... private int time; public int getTime() { ... } } public class Form1 { private Button button1; private Label label1; private Clock cl; public Form1(Clock c) { cl = c; ... } ... public void onClick() { ... cl.getTime() ...} }A class diagram summarizes the design of what we coded. It looks like this:
Within Form1, the handle to the Clock is named by the private field var, cl. (The tiny "lock" means private.) Form1 has a reference to exactly one clock, and for this reason, the arrow to Clock is labelled by a , called a multiplicity ("how-many-multiples"). 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."![]()
There is a small variation on the above diagram, where the private fieldname,
cl, is moved to the arrow as a label, like this:
A private variable is labelled by a minus sign, -.
You will see labelled arrows used a lot in practice
--- remember that the label is actually a fieldname!
Notice that Form1 also 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 didn't write those classes, and since don't need to show how class Button or Label connect to other classes, we just leave the Button and Label inside Form1.
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. Here is the same relationship, but where the fieldnames are placed as labels on the arrow:![]()
You can draw it as you wish.![]()
The multiplicities can be 1, 2, ..., n..m (n upto m), * (zero or more).
To indicate that the fieldname label is an array, put it in braces:
The code for the above design might look like this:
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) { ... }
}
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.
IMPORTANT: Nclass does not correctly transfer the fieldname labels on arrows into the generated C# files. So, declare fieldnames as private variables in the classes. But DO remember to write the multiplicity numbers on the arcs, because this is an important part of your design.