Background and general information on the .NET framework
Lesson 1 - Print Functionality
The PrintDocument Component
- Encapsulates all info required to print page
- PrinterSettings property contains details on available printers capabilities
- Default PageSettings contains configuration info for a page
- Print controller describes how each page guided through printing process
Creating PrintDocument object
- Either via designer or through code
- Both methods of creation result in component automatically configured to work with default system printer
How Printing Works
-
Printed content provided b y application logic
-
Print job initiated by PrintDocument.Print()
- Start job
- Raises 1+ PrintPage event
- Provide handler for event to print content (if none exists nothing is printed)
-
PrintPage event raised for each page
-
Handler for PrintPage must track print job and ensure correct page printed
PrintPage event
-
Objects and info required to print content wrapped in PrintPageEventArgs object
- Cancel - indicates if job should be cancelled
- Graphics - contains Graphics object used to render content
- HasMorePages - indicates if additional pages should be printed
- MarginBounds - Rectangle object representing portion of page within margin
- PageBounds - Rectangle object representing entire page
- PageSettings - PageSettings object for current page
-
To render content use same methods as to render form
// Method to handle PrintPage event
public void PrintElipse(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawElipse(Pens.Black, e.MarginBounds);
}
- Specify print job has multiple pages by using HasMorePages property (note, if fail to set to false after last page printed app will continue to raise PrintPage events)
- Create event handler for PrintPage
- Double click PrintDocument instance in designer to create default handler
- Declare event handler in code
Printing Content
-
Use Graphics object supplied by PrintPageEventArgs to render
-
When printing multiple lines of text must include logic to calculate line spacing
- Calculate number of lines per page by dividing margin bounds height by font height
- Calculate line position by multiplying font height by line number
-
May use different colours when printing to colour printer as black and white
- Some colours easily discernible on screen can be indistinguishable on paper
- Provide alternative logic to accommodate black and white printers
- Determine printer colour capability using PrinterSettings.SupportsColor
- Can force printer into black and white mode by setting PrinterSettings.SupportsColor to false
PrintPreviewControl
- Allows graphical preview of printed content
- PrintPreviewControl must be associated with PrintDocument instance
myPrintPreview.Document = myPrintDocument;
- After association made the PrintPreviewControl displays content to be printed by control by capturing output of PrintDocument control
- Update preview in response to changing conditions by calling InvalidatePreview method
myPrintPreview.InvalidatePreview();
- The Zoom property specifies magnification level
- Fractional value reduces image
- 1 causes preview to be displayed full size
- Greater than 1 causes an enlargement
PrintPreviewDialog
- Implements most commonly used print preview functionality
- Provided as standard by .NET framework
- Suitable for requirements of most apps - use PrintPreviewControl when require greater control
Printing Configuration
- Printing support highly configurable
- PrintDocument.PrinterSettings contains info about available printers, used unless overridden by PrintPage handler
- When PrintDocument created default config for default printer loaded into PrinterSettings
- User configuration of print jobs via PrintDialog and PrintSetupDialog
PrintDialog
- Allow users to set PrinterSettings property of PrintDocument object at runtime
- Add to app by dragging instance of PrintDialog from WindowsForms tab of Toolbox to designer
- Display at runtime by calling
PrintDialog1.ShowDialog();
- Must be associated with PrintDocument object, via PrintDialog.Document property
PrintSetupDialog
- Used like PrintDialog
- Allows user to configure page and printer settings at runtime
Configure PageSetting at run time
- May wish to configure individual pages, e.g. print one in landscape, rest in portrait
- Change page settings via PrintPageEventArgs.PageSettings - represents settings for page being printed
Lesson 2 - Accessing and Invoking Components
.NET and COM Type Libraries
-
Create reference to type library via Add References dialog
- .NET tab displays available .NET assemblies
- COM tab displays COM type libraries
- Projects tab displays available projects
- Add reference to unlisted item via Browse button
-
Use the type library
-
Declare and instantiate desired class
-
ActiveX controls = implementation of COM
- Add reference in same way as other COM objects
- Can add to Toolbox
- Have significant performance drawbacks - only use when .NET control equivalent not available
Web Service
-
Web service = class hosted on internet
-
Call its methods either synchronously or asynchronously
-
Create reference in Solution Explorer via Add Web Reference window
- Navigate to URL of Web reference or
- Search Online if URL not known
-
Universal Description Discovery Integration (UDDI) allows search of web for components providing web services
- Company selected web services it offers are displayed
- Choose service and XML contract shown in left pane
-
When instance created .NET creates proxy representing web service
- When method called it is relayed to Web service address specified
-
Synchronous calls behave like normal function calls
- Response times can vary
- App execution pauses until function returns
-
Asynchronous call to web service invoked on separate thread
- Permits app execution to continue while call processed
- For every web service method there are 2 additional asynchronous methods beginning Begin and End
- Begin async call by calling Begin method passing over synchronous parameters and an AsyncCallback delegate
- Begin method has return type of IAsyncResult
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);
}
}
- Must specify callback method, but don't need to use it. Can receive data in same method by calling the End method. Program execution will halt at End call until result is available
Accessing Windows API
-
Most important functionality wrapped in .NET classes
-
Use DllImportAttribute to gain access to native functions
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern int Beep(int dwFreq, int dwDuration);
Lesson 3 Accessibility
Design
-
Accessibility begins in design
-
Flexibility = key principle
-
User can customise UI to their needs
-
Choose variety of input methods
- Keyboard access to important tasks
- Mouse click access for common tasks
-
Choice of output methods
- Sound
- Graphics
- Text
-
-
Consistent interaction
- Within itself
- With other applications
-
Compatibility with accessibility aids
Program Accessibility
Support Standard System Settings
- Ensures all user apps have consistent look and feel provided by system settings
- Implement via System objects in .NET framework
- Design app so can be used on screen at 640 * 480
High Contrast
- Support high contrast option in system colours
- Avoid background images (reduces contrast)
Keyboard Access
-
Document + make discoverable keyboard access to all app features
-
Provide shortcut keys to menu items
-
Set Tab order on dialogs
Notify Keyboard Focus Location
- Usually managed by .NET framework
- Always incorporate code to set focus to first control on form when it is first displayed
Do not rely on sound alone
- Sound is important cue
- Must also use visual cues
- flash background colour
- display message box
- use non-modal screen to display info while app runs
Accessibility Properties
- Each control supports 5 properties that determine how it interacts with accessibility aids
- AccessibleDescription - description reported to accessibility aids
- AccessibleName - name reported to accessibility aids
- AccessibleRole - role of control that is reported to accessibility aids. Select value from an enum, normally default unless control behaving peculiarly or is custom then set to value describing it, e.g. set to Chart if control displays a chart
- AccessibilityObject - read-only instance of AccessibleObject providing info about control to usability aids
- AccessibleDefaultActionDescription - description of control default action, set in code not via designer
Lesson 4 - Implementing Help
The Help Class
- Display HTM or CHM files to users
- Encapsulates HTML Help 1.0 engines
- Exposes 2 static methods
- ShowHelp - display help file for particular control. Takes
- reference to control
- URL for help file
- optional navigator specifying help file element to display (TableOfContents, Find, Index, Topic or keyword search)
- ShowHelp - display help file for particular control. Takes
Help.ShowHelp(MyForm, @"C:\myHelpFile.htm", "HelpMenu");
- ShowHelpIndex call made same way as for ShowHelp
Help.ShowHelpIndex(MyForm,@"C:\myHelpFile.htm");
HelpProvider Component
-
It is an extender provider - coordinates and maintains properties for each control on form
-
Adds 3 properties to each control on form
- HelpString - displayed when it has focus and F1 pressed
- HelpKeyWord
- HelpNavigator
- TableOfContents
- Find
- Index
- Topic
- AssociatedIndex
- KeywordIndex
-
Can set in properties window during design or in code
-
Can specify HelpNameSpace specifying URL for help file associated with HelpProvider
- If not set then HelpString displayed and other 2 properties ignored
- If set displays help file specified by HelpKeyWord and HelpNavigator
- Can still access HelpString, but only via code using HelpProvider.GetHelpString() method
myHelpProvider.GetHelp(Button1);
Lesson 5 - Globalisation and Localisation
-
Globalisation = apply culture based formatting to data, e.g. use of period as thousand separator and , as decimal
-
Localisation = retrieving appropriate pieces of data based on culture, e.g. different form title based on language (English, French, etc.)
-
Culture = info about region in which app being used. Identified by code.
-
code represents to framework what current language is (2 letter code)
-
can also specify region in which app is used (2 letter code after dash)
-
codes only specifying language = neutral cultures
-
codes specifying region = specific cultures
- En = English language, no region
- en-CA = English language, Canada
- af-ZA = Afrikaans language, South Africa
-
some exceptions
- Cy-uz-UZ = Uzbek language, Uzbekistan, Cyrillic alphabet
- Lt-uz-UZ = Uzbek language, Uzbekistan, Latin alphabet
- zh-CHT = traditional Chinese, no region
- zh-CHS = simplified Chinese, no region
-
-
App automatically reads system culture and implements them
-
Change current culture of app by setting CurrentThread.CurrentCulture to new instance of CultureInfo class
System.Threading.Thread.CurrentThread.Currentculture = new System.Globalization.CultureInfo("fr-CA");
- Retrieve CultureInfo for CurrentCulture via CultureInfo.CurrentCulture
CultureInfo myCurrentculture = CultureInfo.CurrentCulture;
Globalisation
- Data not formatted by application will be unaffected by change to Thread.CurrentThread.CurrentCulture, e.g. label set to "$500" will always display this regardless of culture
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");
Localisation
-
Localisation supported by creating separate localised form resource files for each culture app supports. At run time appropriate version loaded based on CultureInfo.CurrentUICulture.
-
If resources appropriate to current value of CultureInfo.CurrentUICulture then app displays resources for default culture
-
UI culture must be set before form displaying localised resources is loaded. To set UI culture programmatically should do so in constructor of main form
-
Every form exposes Localizable property indicating if form is localised or not
-
When Localizable property set to true, IDE creates appropriate resource files
- Based on Language property of form
- When Language set to Default IDE edits forms and controls for the Default UI culture
- To create forms for other cultures set Language to appropriate value
-
Localisation not limited to strings, button sizes may change to accommodate longer strings
-
Validating input in international app traditionally difficult, under .NET use validation mechanisms of Char, e.g. Char.IsDigit and Char.IsLetter
Culture-Specific Formatting
- Can modify specific members of CultureInfo to tailor app functionality - e.g. Japanese bank that deals in $, use Japanese specific formatting, but uses $ as currency symbol
- Following members define how globalisation formatting carried out
- DateTimeFormat - how dates and times formatted, e.g. abbreviated day and month names, display of AM and PM, date and time formats, calendar and day names
- NumberFormat - describes decimal and thousand separators to use for numbers and currency, currency symbol, display of percentages
- TextInfo - code page to use, list separator
CultureInfo modJPCulture = new CultureInfo("jp-JN");
modJPCulture.NumberFormat.CurrencySymbol = "$";
Thread.CurrentThread.CurrentCulture = modJPCulture;
Right-to-left Display
-
Standard Windows Forms provide RightToLeft property enabling right-to-left UI in app
-
RightToLeft property set to
-
Yes - controls becomes mirror of themselves in respect to formatting
- reverses text alignment
- caption is right aligned
- vertical scroll bars appear on left
- horizontal scroll bars initialised with slider right-aligned
- check boxes have CheckAlign property reversed
- Tab buttons reversed
- item alignment in list boxes and combo boxes reversed
-
No - controls take normal formatting
-
Inherit - the default value, inherit setting from Form
-
-
Content of controls with RightToLeft set to Yes is not reversed - i.e. alignment of control changes but text displayed as read from left-to-right. Must format strings manually.
Character Encodings
- .NET uses Unicode UTF-16
- Supports legacy formats, e.g. Single-Byte, Double Byte and Bidirectional
- Encoding conversions via Encoding class obtained by calling Encoding.GetEncoding()
// Code page 932 represents Japanese chars
Encoding myEncoding = Encoding.GetEncoding(932);
- Use Encoding instance to convert chars to Unicode (and visa versa) via Encoding.Convert(). Takes source encoding, target encoding and array of bytes
// 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);
- Use GetChars to convert array of bytes to array of chars
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
Declaration
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;
or
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:
- Logically represents a single value
- Instance size less than 16 bytes
- Will not change after creation
- Will not be cast to a reference type
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
}
Enumerations
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
Strings
More than just data containers, also provide manipulation via their members, e.g.
System.String
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.
-
-
- joins two strings
-
- == - true if two strings have same contents
- != - inverse of equality
- = - copies contents of one string to another. Causes strings to behave like value types, although implemented as reference types
Arrays
Declared by [], e.g.
int[] ar = { 3, 1, 2 };
Array.Sort(ar);
Streams
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");
Console.WriteLine(sr.ReadToEnd());
sr.Close();
Exceptions
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.
try
{
StreamWriter sw = new StreamWriter("text.txt");
sw.WriteLine("Hello, world!");
sw.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Messagge());
}
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
Inheritance
Together with Interfaces helps provide consistency (e.g. Every class implements ToString())
e.g.
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.
Interfaces
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 Create class declaration
class AClass
{
}
- Add interface declaration
class AClass : IComparable
{
}
- 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.
Generics
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
- Reduced run time errors . Compiler can't detect type errors when casting to / from objects. Only find problem at runtime when exception raised
- Improved performance . Casting requires boxing.
Creation
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,
Consumption
Gen<double, int> gb = new Gen<double, int>(10.25, 2005);
Console.WriteLine(gb.t + gb.u);
Constraints
Overcome restrictions on limiting capabilities to that of the Object class. Support for 4 types:
-
Interface - restrict to only types implementing specified interfaces, e.g. where T : IComparable
-
Base class / struct - restrict to types derived from specified base class or struct, e.g. where T : SomeClass
-
Constructor - restrict to types implementing parameterless constructor. Always appears last in list of constraints, e.g. where T : new()
-
Reference or value type - restrict to reference or value type, e.g. where T : struct
Events
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.
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:
- Create method to respond to event
public void button1_Click(object sender, EventArgs e) { }
- Add the event handler
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) {}
}
Attributes
Describe a type or property in way that can be programmatically queried via reflection.
Common uses include:
- specifying security privileges required
- specifying security privileges to refuse (reduces security risk)
- declaring capabilities (e.g. Serialization)
- providing title, description, copyright notice, etc., e,g,
[assembly: AssemblyTitle("ch01cs")]
Derive from
System.Attribute
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:
- Add TypeForwardedTo attribute to source file for TypeA in the source class library assembly
using System.Runtime.CompilerServices;
[assembly.TypeForwardedTo(typeof(DestLib.TypeA))]
- Cut the definition of the type from the source file in the source class library assembly
- Paste typeA definition into destination class library assembly
- 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:
- System.Convert - converts between types that implement System.IConvertible
- (type) cast operator - between types the define conversion operators
- type.ToString, type.Parse - between string and base types, exception thrown if not possible
- type.TryParse, type.TryParseExact - between string and base type, returns false if conversion not possible
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
- Define conversion operators to simplify narrowing / widening conversions between numeric types. Use implicit for conversion that don't loose precision and explicit for those that could.
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){}
}
- Override ToString for conversion to strings and Parse from strings
- Implement System.IConvert to enable conversion via System.Convert - use for culture-specific conversions.
- Implement TypeConverter to enable design-time conversion for use in Visual Studio properties window.