Background and general information on the .NET framework

Lesson 1 - Print Functionality

The PrintDocument Component

Creating PrintDocument object

How Printing Works

PrintPage event

// Method to handle PrintPage event 
public void PrintElipse(object sender, System.Drawing.Printing.PrintPageEventArgs e)
e.Graphics.DrawElipse(Pens.Black, e.MarginBounds);

Printing Content


myPrintPreview.Document = myPrintDocument; 


Printing Configuration




Configure PageSetting at run time

Lesson 2 - Accessing and Invoking Components

.NET and COM Type Libraries

Web Service

public class AsyncDemo 
WebService1 myService;

public void CallMethodAsynchronously()
myService = new WebService1();

// Create AsyncCallback delegate
System.AsyncCallback myCallback = new System.AsyncCallback(CallBack);

// Object required by method call but not
// used
myService.BeginMyMethod(myCallback, new Object());

public void CallBack(IAsynResult e)
string myString;

myString = myService.EndMyMethod(e);

Accessing Windows API


private static extern int Beep(int dwFreq, int dwDuration);

Lesson 3 Accessibility


Program Accessibility

Support Standard System Settings

High Contrast

Keyboard Access

Notify Keyboard Focus Location

Do not rely on sound alone

Accessibility Properties

Lesson 4 - Implementing Help

The Help Class

Help.ShowHelp(MyForm, @"C:\myHelpFile.htm", "HelpMenu"); 

HelpProvider Component


Lesson 5 - Globalisation and Localisation

System.Threading.Thread.CurrentThread.Currentculture = new System.Globalization.CultureInfo("fr-CA");
CultureInfo myCurrentculture = CultureInfo.CurrentCulture; 


Label1.Text = "$500" 

Whereas setting to value formatted to currency will result in "500" being displayed for en-GB - note no currency conversion takes place

Label1.Text = (500).ToString("C"); 


Culture-Specific Formatting

CultureInfo modJPCulture = new CultureInfo("jp-JN"); 

modJPCulture.NumberFormat.CurrencySymbol = "$";

Thread.CurrentThread.CurrentCulture = modJPCulture;

Right-to-left Display

Character Encodings

// Code page 932 represents Japanese chars

Encoding myEncoding = Encoding.GetEncoding(932);
// Obtain encoding instances 

byte[] tgtData;

Encoding srcEncoding = Encoding.GetEncoding(932);

UnicodeEncoding tgtEncoding = new UnicodeEncoding();

// Convert legacy data (in mystring) to bytes

byte[] myData = srcEncoding.GetBytes(myString);

// Perform conversion

tgtData = Encoding.Convert(srcEncoding, tgtEncoding, myData);

UnicodeEncoding myEncoding = new UnicodeEncoding();

char[] myChars;

myChars = myEncoding.GetChars(myBytes);

Framework Fundamentals

Lesson 1: Using Value Types

Built-in value types

Simplest types, e.g. Numeric, boolean

Still function as objects (e.g. Support for ToString(), etc.)

Contain data directly, stored on stack - rather than reference to data in heap.

Runtime optimises performance of 32-bit integers (Int32 and Uint32) - use these for counters and frequently accessed integral variables.

Double is most efficient floating-point type due to hardware optimisation.

Assignment between value types causes data to be copied (i.e. Two separate copies on stack).

Derived from System.ValueType


To use must declare symbol as instance of required type.

Implicit constructor -> no need to use New keyword

Declare as nullable if want to determine if value has been assigned

Nullable<bool> b = null;


bool? b = null;

If nullable then HasValue and Value members are available

if (b.HasValue) Console.Writeline("b is {0}", b.Value);

User-defined types

Again store data on stack, but otherwise nearly identical to classes

Usually more efficient than classes

Should meet following criteria:

Composites of other data types that make working with related data easier, e.g. System.Drawing.Point contains X and Y integer properties to describe a location.

Define own types using struct keyword.

Note, new operator keyword to define operators within classes and structs, e.g.

Public static Cycle operator+(Cycle arg1, int arg2)
arg1.Value += arg2;

return arg1


Related symbols having fixed values, e.g.

enum Titles : int {Mr, Ms, Mrs, Dr };

Although value is an integer it is easy to output its symbol, e.g.

Console.WriteLine("{0}", Titles.Dr); // Displays "Dr"

Lesson 2: Using Reference Types

Built-in Reference Types

Most framework types

Store the address of their data (i.e. a pointer) on stack. Actual data stored in heap.

Heap memory managed by garbage collection.

Garbage collection occurs when needed or when triggered via GC.Collect.

Optimised for applications where most data instances short lived, except for those allocated at start of application.

Assigning one reference variable to another creates a second copy of the reference to the same memory location in the heap as the original.

Derived from System.Object


More than just data containers, also provide manipulation via their members, e.g.


provides members to work with text.

Instances of System.String are immutable. Any change to string causes a new string to be created and the old one abandoned. To void unnecessary temporary strings use string members Concat, Join or Format. Alternative use

StringBuilder class to create dynamic (mutable) strings - most flexible as can div multiple statements.

Overrides System.Object operators.


Declared by [], e.g.

int[] ar = { 3, 1, 2 };



Mechanism to read / write to disk, communicate over network.

Derived from System.IO.Stream

Simplest = StreamReader and StreamWriter which provide access to text files. After processing call Close method so file does not remain locked, e.g.

StreamReader sr = new StreamReader("test.txt");




Unexpected events interrupting normal execution flow,e.g. Read large text file from removable disk and user ejects disk

Should never cause assembly to fail completely - should plan for them to occur, catch them and process appropriately.

StreamWriter sw = new StreamWriter("text.txt");

sw.WriteLine("Hello, world!");


catch (Exception ex)

Base System.Exception class provides message and application data. Framework provides many derivations to describe different situations.

Can define own exceptions, these should derive from System.ApplicationException.

Runtime will execute first catch block with matching exception, so order them from most-specific to least

Finally block executes after try and any catch blocks. Use to close any streams and clean up after other objects that may be left open if exception occurs.

All code except simple variable declarations should be within try block.

Exception handling does incur slight performance penalty.

Lesson 3: Constructing Classes


Together with Interfaces helps provide consistency (e.g. Every class implements ToString())


class DerivedException : System.ApplicationException
public override string Message{ get { return "Error"; } }

Can use derived classes interchangeably, e.g 5 classes derived from System.Drawing.Brush all of which can be passed to Graphics.DrawRectangle that requires a Brush as one of its parameters.


A contract defining common set of members that all classes implementing interface must provide, e.g, IComparable defines CompareTo method allowing two instances of class to be compared for equality.

Class can implement multiple interfaces.

To implement follow these steps:

  1. 1 Create class declaration
class AClass

  1. Add interface declaration
class AClass : IComparable

  1. Right click on IComparable, select "Implement Interface" and then "Implement Interface" again. VS2005 will insert required skeleton methods.

Common interfacesIComparable - implement if values can be ordered

IDisposable - permits manual disposal of object

IConvertible - convert class to be type, e.g. boolean, byte

ICloneable - copy an object

IEquitable - compare 2 instances for equality

Search Results Web results

IFormattable - convert value to specially formatted string

Partial Classes

Split class definition across multiple files.

Benefit = hide details of class definition so derived classes can focus on most significant potions.

Form class = example. Previously all form designer generated code in class. Now this code is hidden in form .Designer.cs file.


Allow definition of type while leaving some details unspecified. Instead of specifying parameter types can leave clients to specify them.

Several classes found in System.Collections.Generic namespace.

Why Use

Previously developers used Object class to achieve similar functionality.

2 significant advantages

  1. Reduced run time errors . Compiler can't detect type errors when casting to / from objects. Only find problem at runtime when exception raised
  2. Improved performance . Casting requires boxing.


class Gen<T, U>
public T t;

public U u;

public Gen(T _t, U _u)

t = _t;

u = _u;

Class has two members of type T and U. Consuming code determines these types.

Generic code only valid if will compile for every possible instance of it, i.e. Limited to capabilities of Object class - call ToString, GetHasCode, but not + or > operator. These restrictions do not apply to the consuming code,


Gen<double, int> gb = new Gen<double, int>(10.25, 2005);

Console.WriteLine(gb.t + gb.u);


Overcome restrictions on limiting capabilities to that of the Object class. Support for 4 types:


Message sent by object to signal occurrence of action - could be caused by user interaction, or program logic.

Object raising event = event sender

Object capturing event = event receiver

Event sender does not know which object will receive events it raises. This requires pointer like functionality to link source and receiver - provided by Delegate.


Class holding reference to method.

Unlike other classes it posses a signature and can only reference methods matching its signature.

Equivalent to type safe function pointer.

Delegate declaration defines delegate class - declaration provides signature whilst runtime provides implementation, e.g.

public delegate void AlarmEventHandler(object sender, EventArgs e);

Standard event handler signature (above) defines method that does not return a value, whose first parameter refers to the instance raising the event and second parameter is a class derived from EventArgs that holds the event data.

If event does not generate data then second parameter = instance of EventArgs, otherwise it is instance of derived class.

EventHandler= predefined delegate for event that does not generate data. If event does generate data then must provide own delegate (see above).

To associate event with handler, add instance of delegate to the event - as follows:

public void button1_Click(object sender, EventArgs e) { }
this.button1.Click += new System.EventHandler(this.button1_Click);

Example using custom EventArgs and generic EventHandler

public class CustomEventArgs : EventArgs {}

public class Publisher
public event EventHandler<CustomEventArgs> ce;

public void Go() {OnRaiseCE(new CustomEventArgs());}

protected virtual void OnRaiseCE(CustomEventArgs e)
// temp copy to avoid race condition where
// subscriber unsubscribes between
// null check and event being raised

EventHandler<CustomEventArgs> handler = ce;

if (handler != null) handler(this,e);

public class Subscriber
public void Subscriber(Publisher p){p.ce += HandleCE;}

public void HandleCE(object sender, CustomEventArgs e) {}


Describe a type or property in way that can be programmatically queried via reflection.

Common uses include:

[assembly: AssemblyTitle("ch01cs")]

Derive from


Visual Studio automatically creates some attributes (such as title, description, version, etc.) when project created - these should be edited as the defaults may not contain desired information (e.g. Description will be blank)

To enable a class to be serialized must include [Serializable] attribute.

The following attribute declares that the class needs to read c:\boot.ini. The runtime will throw an exception prior to execution if it lacks specified privilege.

[assembly:FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read=@"C:\boot.ini"]

Type Forwarding

The attribute [assembly:TypeForwardedTo()]allows a type to be moved from one assembly into another without clients of the first assembly having to be recompiled.

Follow these steps to move TypeA from source to destination class library:

  1. Add TypeForwardedTo attribute to source file for TypeA in the source class library assembly
using System.Runtime.CompilerServices;

  1. Cut the definition of the type from the source file in the source class library assembly
  2. Paste typeA definition into destination class library assembly
  3. Rebuild both libraries

Lesson 4: Type Conversion

VB vs C#

VB allows implicit conversions, C# prohibits implicit conversion that loose precision.

To turn off implicit conversion in VB add Option Strict On to top of each source file.

Both VB and C# permit implicit conversion if destination can accommodate all possible source values (called a widening conversion)

If the range of the source exceeds the destination (a narrowing conversion) then explicit conversion is required:

Narrowing conversion may return incorrect result if source value exceeds destinations type range. If conversion between types not defined then compile-time error generated.

Boxing & Unboxing

Boxing converts value to reference type, e.g.

int i = 123;

object o = (object) i;

Unboxing converts reference to value type.

object o = 123;

int i = (int) o;

Incur overhead so avoid using in repetitive tasks.

Boxing occurs when call virtual methods that a structure inherits from System.Object (e.g. ToString).

How to avoid

Implement type specific overloads for procedures accepting various value types

Use generics whenever possible

Override ToString, Equals and GetHash virtual members when defining structures.

Conversion in Custom Types

public struct TypeA
public int Value;

// Implicit conversion from an int
public static implicit operator TypeA(int arg){}

// Explicit conversion to an integer
public static explicit operator int(TypeA arg){}