40
COMP 585 Noteset #8 Microsoft APIs for GUI App Development History Win32 API A large collection of global functions to build and configure GUI components. You could call this a “struct” approach to GUI building: no true OOP encapsulation and very little abstraction. The programmer had to write large complex programs that interacted with the platform at a very low level. Wikipedia entry quotes well-known Windows programming author Charles Petzold as observing that the C “Hello, World” program in Windows SDK 1.0 was 150 lines long, with a 20 line .rc (resource) file. Microsoft Foundation Classes (MFC) An early attempt at an OOP model for GUI construction, imperfect by today’s standards, but very successful and influential at the time, and still in use today. Used primarily with C++. MFC succeeded in hiding much – but not all – of the Win32 level code behind a cleaner higher-level OOP facade. The weakness was that a significant number of operations required use of Win32 API calls, thus frequently breaking the OOP model. One source of frustration for the programmer was that the time invested in learning MFC did not eliminate the need to learn the original Win32 API. Still very much alive for legacy code, but not currently emphasized by Microsoft. .NET The .NET framework is Microsoft’s current software framework for the development of Windows applications. It is a departure from Microsoft’s previous approach, in that source code is compiled to an intermediate, platform-independent language called Common Intermediate Language (CIL), which is then interpreted by the Common Language Runtime (CLR). This is analogous to the Java compiler producing bytecodes which are interpreted by the JVM. A significant element of .NET is an extensive Framework Class Library (FCL). API documentation for the class library is available at the MSDN (Microsoft Developer’s Network) website. Another major accomplishment of the .NET framework is to provide a uniform API for all supported programming languages. Previously, Microsoft provided separate libraries for different languages – C++, VB, etc. – with the result that the different libraries were rarely in sync. In .NET, there is one underlying library, so no matter the source language, a .NET API function or method call .NET will hit the same code. Windows Forms or WinForms (Part of .NET) Rather than defining packages to import as in Java, .NET divides its class library into hierarchical namespaces, which are referenced at the top of a source file that needs them. In C#, the “using” directive references a namespace. The code is stored in dynamic link library (.DLL) files. For GUI programming the System.Windows.Forms namespace is the basis for relatively simple GUIs built around the Form class. The Form plays the role of the JFrame in a Java Swing app. Graphics are based on an older Microsoft standard called Graphics Device Interface (GDI), which is fast becoming obsolete by today’s standards, at least in areas like gaming that require high performance animation. With the release of .NET 3.0, Microsoft introduced a new GUI development standard called Windows Presentation Framework (WPF). This leaves the status of WinForms unclear. Microsoft is still supporting it in maintenance mode (bug fixes) but there are few new features being added. WinForms is very much alive and in wide use in some corporations, with a significant code base for front end apps. Windows Presentation Foundation or WPF (Also Part of .NET) WPF represents Microsoft’s current approach to GUI development. It has a similar relation to WinForms as Java Swing has to AWT. WinForms development is very much alive, but Microsoft’s emphasis has switched to WPF. WPF uses a modern graphics API – DirectX. New namespaces have been introduced – System.Windows and System.Windows.Controls. Programmer should be careful to keep WinForms and WPF namespaces separated in their thinking. WPF introduces an XML-derived markup language called XAML (pronounced “ZAM-ul”) or eXtensible Application Markup Language as an alternative way to define layout. WPF GUIs can be defined through a mixture of XAML files for layout and code files for event handlers (called delegates in C#). Code that accompanies and supports XAML layout is called “code-behind.” Use of XAML is optional, and GUIs can still be built fully programmatically from source code files. Separation of the design of an app’s layout from the coding of the app’s behavior gives software developers new options for using their development team more effectively. Layout design can be assigned to a design specialist who doesn’t also need to be a coding specialist. Similarly, the coding specialist can focus on coding, and not worry about specialized graphic design tasks that require a different skill set. WPF is still very much alive but its long- term future is currently being debated in the blogosphere.

COMP 585 Noteset #8 Microsoft APIs for GUI App Development

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8

Microsoft APIs for GUI App Development

History

Win32 API

A large collection of global functions to build and configure GUI components. You could call this a “struct” approach to

GUI building: no true OOP encapsulation and very little abstraction. The programmer had to write large complex

programs that interacted with the platform at a very low level. Wikipedia entry quotes well-known Windows

programming author Charles Petzold as observing that the C “Hello, World” program in Windows SDK 1.0 was 150

lines long, with a 20 line .rc (resource) file.

Microsoft Foundation Classes (MFC)

An early attempt at an OOP model for GUI construction, imperfect by today’s standards, but very successful and

influential at the time, and still in use today. Used primarily with C++. MFC succeeded in hiding much – but not all – of

the Win32 level code behind a cleaner higher-level OOP facade. The weakness was that a significant number of

operations required use of Win32 API calls, thus frequently breaking the OOP model. One source of frustration for the

programmer was that the time invested in learning MFC did not eliminate the need to learn the original Win32 API. Still

very much alive for legacy code, but not currently emphasized by Microsoft.

.NET

The .NET framework is Microsoft’s current software framework for the development of Windows applications. It is a

departure from Microsoft’s previous approach, in that source code is compiled to an intermediate, platform-independent

language called Common Intermediate Language (CIL), which is then interpreted by the Common Language Runtime

(CLR). This is analogous to the Java compiler producing bytecodes which are interpreted by the JVM. A significant

element of .NET is an extensive Framework Class Library (FCL). API documentation for the class library is available

at the MSDN (Microsoft Developer’s Network) website. Another major accomplishment of the .NET framework is to

provide a uniform API for all supported programming languages. Previously, Microsoft provided separate libraries for

different languages – C++, VB, etc. – with the result that the different libraries were rarely in sync. In .NET, there is one

underlying library, so no matter the source language, a .NET API function or method call .NET will hit the same code.

Windows Forms or WinForms (Part of .NET)

Rather than defining packages to import as in Java, .NET divides its class library into hierarchical namespaces, which

are referenced at the top of a source file that needs them. In C#, the “using” directive references a namespace. The code

is stored in dynamic link library (.DLL) files. For GUI programming the System.Windows.Forms namespace is the

basis for relatively simple GUIs built around the Form class. The Form plays the role of the JFrame in a Java Swing app.

Graphics are based on an older Microsoft standard called Graphics Device Interface (GDI), which is fast becoming

obsolete by today’s standards, at least in areas like gaming that require high performance animation. With the release

of .NET 3.0, Microsoft introduced a new GUI development standard called Windows Presentation Framework (WPF).

This leaves the status of WinForms unclear. Microsoft is still supporting it in maintenance mode (bug fixes) but there are

few new features being added. WinForms is very much alive and in wide use in some corporations, with a significant

code base for front end apps.

Windows Presentation Foundation or WPF (Also Part of .NET)

WPF represents Microsoft’s current approach to GUI development. It has a similar relation to WinForms as Java Swing

has to AWT. WinForms development is very much alive, but Microsoft’s emphasis has switched to WPF. WPF uses a

modern graphics API – DirectX. New namespaces have been introduced – System.Windows and

System.Windows.Controls. Programmer should be careful to keep WinForms and WPF namespaces separated in their

thinking. WPF introduces an XML-derived markup language called XAML (pronounced “ZAM-ul”) or eXtensible

Application Markup Language as an alternative way to define layout. WPF GUIs can be defined through a mixture of

XAML files for layout and code files for event handlers (called delegates in C#). Code that accompanies and supports

XAML layout is called “code-behind.” Use of XAML is optional, and GUIs can still be built fully programmatically

from source code files. Separation of the design of an app’s layout from the coding of the app’s behavior gives software

developers new options for using their development team more effectively. Layout design can be assigned to a design

specialist who doesn’t also need to be a coding specialist. Similarly, the coding specialist can focus on coding, and not

worry about specialized graphic design tasks that require a different skill set. WPF is still very much alive but its long-

term future is currently being debated in the blogosphere.

Page 2: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 2

Silverlight

Initially, Silverlight was a browser plug-in for streaming video, it became Microsoft’s initiative for developing Rich

Internet Applications (RIAs), similar to Java FX or Adobe Flex (Flex is a programming-oriented development

environment for Flash applications). Microsoft has now officially deprecated it.

Resources for Windows Forms and WPF Development

Since they are part of the .NET framework, WinForms and WPF are currently tightly bound to Microsoft Windows,

support for other platforms is be minimal, although some projects are in the works. The Mono Project has implemented a

subset of the .NET framework for Linux, but there’s no timeline for completion. Microsoft announced in April 2015 that

it would be releasing their own official version of .NET for Linux and Mac, but it is a work in progress.

If you plan to work only from Mac platform, one solution is to set up a virtual environment such as Virtual Box or

VMWare, create a Windows OS instance in this virtual environment, and install the development tools into that virtual

instance. Your Mac hardware will have to meet at least minimum reasonable requirements for RAM/HD/CPU to support

the virtual environment solution. Another solution is to configure your Mac for dual boot and boot directly to Windows

OS for WPF related work. This solution will also require reasonably up-to-date RAM/HD/CPU configuration.

Go to the Microsoft Developer’s Network (MSDN) site at http://msdn.microsoft.com and download the latest version of

Visual Studio. There are many editions, but the Visual Studio Community Edition 2015 is free and has all the features

needed for the projects in this class. The install will include the most recent .NET framework version (4.6), the IDE, and

command line tools for command line access to the compilers.

Extensive API documentation of the .NET framework class library is also available at MSDN. This is a complex site

that is frequently reorganized, so a hardcoded URL in the class notes isn’t a reliable way to give directions. The easiest

way to get to the start page for the documentation is to google “MSDN .NET framework class library” and look for the

first link that takes you to a page on msdn.com. Just as Java organizes documentation by package, the .NET FCL

organizes documentation by namespace. It’s much easier to navigate if you know which namespace your class or other

element is in. If you don’t, your best bet is to use the search box at the top of the documentation page. From the

documentation page, find the tree-based index near the upper left of the page, and start with the .NET Development item:

.NET Development �

.NET Framework 4.6 (or whatever version you’re using) �

.NET Framework Class Library

From this point, the tree-based index is opened to the complete set of namespaces for .NET. It’s a big set and we only

need a handful for the programs in this course.

Intro to C#

.NET applications can be developed using several different languages: C++, C#, VB, and others. Of the popular

languages, C# seems to be the one Microsoft promotes as the default language for .NET development. It is a strict OOP

language with syntax similar to the C/C++/Java family. At a lower level, it is significantly different, it is not simply

Microsoft’s version of Java.

Tools

A clean install of Visual Studio will install the required .NET framework as well as the Visual Studio IDE. The C#

compiler can also be accessed from the command line. WinForms apps have a trivial build process and can be built by a

command line compile. WPF apps cannot, a WPF app is a more complex mix of C# source files and XAML files, the

build process is more complex and cannot be easily run as a series of commands at the command prompt, it will need the

Visual Studio IDE to complete it.

It is not a goal of the course to cover C# in depth, but I will present here an overview of some important features that

directly impact how the language is used with the WinForms and WPF APIs. We’ll start with some basic C# programs

that don’t use the GUI APIs. For these simple examples, we will use the csc (C# compiler) to create an executable, then

run the executable, directly from the Windows command line interface (Command Prompt or (better) PowerShell).

Page 3: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 3

The Hello, World! Program (Console Version)

Type the following into a file named ConsoleHelloWorld.cs

class ConsoleHelloWorld { public static void Main() { System.Console.WriteLine("Hello, world!"); } }

From the command prompt, compile the class file with the C# compiler csc

% csc ConsoleHelloWorld.cs

The result is an executable ConsoleHelloWorld.exe. Execute it by typing its name at the prompt

% ConsoleHelloWorld

Output is directed to command prompt console window. If the current directory “.” is not in your path, you will need to

run it with the command % .\ConsoleHelloWorld

A couple of points about C# programs to notice even on this simple version:

• C# source files end with file name extension .cs. The name of the file is not required to match the name of the

class as in Java.

• The entry point to the program is a method named “Main()” with a capital-M. The C# convention is to name

methods to start with a capital letter. The Main() method can omit the argument list if it doesn’t use it. If it is

included, it’s the same as the signature for “main()” in a Java program: Main(String[] args) or Main(string[]

args).

• The String datatype is aliased to “string,” so you can use either String or string, they are identical in meaning.

• The rough equivalent to Java’s “System.out.println()” is “System.Console.WriteLine()”

Page 4: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 4

The Hello, World! Program (WinForms Version from Charles Petzold)

Jumping ahead, here is a GUI-based Hello, World program using WinForms. There are many new features thrown in to

this example, but they will be explained in detail later.

using System; // namespaces using System.Drawing; using System.Windows.Forms; class HelloWorld : Form { // class HelloWorld inherits from class Form // entry point for the app: Main() public static void Main() { HelloWorld hw = new HelloWorld(); // instantiate HelloWorld object Application.Run(hw); // run the app with Form object } // constructor for class HelloWorld public HelloWorld() { this.Text = "Hello World"; // set Text property of Form this.BackColor = Color.White; // set BackColor property of Form } // override the OnPaint() method of class Form protected override void OnPaint(PaintEventArgs pea) { Graphics grfx = pea.Graphics; grfx.DrawString("Hello, Windows Forms!", Font, Brushes.Black, 0, 0); } }

Some points of explanation:

• Instead of importing packages, C# uses namespaces with the “using” directive. If you don’t add a using

directive, the console output function is called with its fully qualified name System.Console.WriteLine(). But if

you add the “using System;” directive, you can shorten the call to Console.WriteLine().

• The top-level container of a C# WinForm GUI is class Form. It plays the role of a JFrame in a Java Swing app.

• Inheritance is indicated by C++ style syntax: “HelloWorld : Form” The super class is called the base class, and

a sub class is called a derived class.

• Properties of the Form (Text, BackColor, etc.) are set in the HelloWorld constructor by direct assignment, but

set/get encapsulation is provided implicitly (behind the scenes) with set/get blocks, described below.

• The inherited version of the OnPaint() method from class Form is overridden in the derived class HelloWorld to

draw a String (the “override” keyword is normally required in this context).

• The driver instantiates a HelloWorld form object and passes it to the Application.Run() static method.

Application.Run() is responsible for the event handling thread.

Page 5: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 5

Some Differences Between C# and Java

MSDN has an article titled “C# for Java Developers.” Google it by title, or try this link:

https://msdn.microsoft.com/en-us/library/ms228358(v=vs.90).aspx

C# has been influenced by C, C++, Java, and other languages. Syntactically, all of these languages appear superficially

similar. But for Java programmers especially, C# has features that don’t have a direct analog in Java. It also uses certain

keywords that might look familiar but mean something different in C#. In this section, I’ll mention some of the most

important features that will be of interest to Java programmers, but the list is not exhaustive.

Quick observations

• Entry point is public static void Main(String[] args) { } not public static void main(String[] args) { }

• Filenames and class names less strictly coordinated

• Compilation produces a linked executable, not a series of individual .class files.

• “using” directive for namespaces without wildcard character, not “import” with packages

Topics covered in more depth

• Arrays (rectangular vs. jagged)

• Options for parameter passing to methods: out, ref

• Distinction between “class” and “struct” (reference vs. value semantics)

• Fields and Properties (implicit set/get blocks with no explicit set/get methods)

• Inheritance and Polymorphism (virtual, override, and new keywords)

• Delegates (function pointers encapsulated as objects)

• Anonymous methods and Lambda Expressions

• Nested Classes

• Static Classes

• Partial Classes

C# Arrays

C# supports both rectangular arrays and jagged arrays (arrays-of-arrays).

Rectangular arrays: 1D: int[] data = new int[5]; 2D: int[,] values = new int[5,3]; 3D: string[,,] names = new string[10,10,10];

Jagged arrays: 2D: int[][] data = new int[5][]; for (int i=0; i<5; i++) data[i] = new int[3];

Functions and Properties

For Rectangular Arrays data.GetLength(0): number of elements in 0th dimension data.GetLength(1): number of elements in 1st dimension … For Jagged Arrays data.Length: number of elements in 0th dimension data[0].Length: number of elements in 0th row data[1].Length: number of elements in 1st row …

Note: int[,] and int[][] are not the same type. If all you want is a simple rectangular array, use the [x,y] notation, not the

[x][y] notation.

Page 6: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 6

Example Program for Arrays

using System; public class A { public static void a(int[,] x) { for (int i=0; i<x.GetLength(0); i++) { for (int j=0; j<x.GetLength(1); j++) { Console.Write(x[i,j] + " "); } Console.WriteLine(); } } public static void a(int[][] x) { for (int i=0; i<x.Length; i++) { for (int j=0; j<x[i].Length; j++) { Console.Write(x[i][j] + " "); } Console.WriteLine(); } } public static void Main() { int[,] data1 = new int[3,5]; for (int i=0; i<data1.GetLength(0); i++) { for (int j=0; j<data1.GetLength(1); j++) { data1[i,j] = i + j; } } a(data1); int[][] data2 = new int[3][]; for (int i=0; i<data2.Length; i++) data2[i] = new int[5]; a(data2); } }

Page 7: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 7

Static Classes

The meaning of the “static” keyword is problematic in C/C++/Java/C#. It has been overloaded and overused when a new

and more precise keyword would have been better. Furthermore, its meaning is similar but not identical across languages.

In the context of Java classes, here is what it means:

• A top-level class is always static, but counterintuitively, it cannot be explicitly declared as static. One way to

look at the issue is that a static class has no implied reference to an enclosing object, and by definition, a top-

level class isn’t enclosed by another class.

• Nested classes can be static or non-static. A static nested class is similar to a top-level class except that it has

increased visibility into the properties of its enclosing class. A non-static nested class is also called an inner

class, and has an implied reference to an object of the enclosing type.

In the context of C# classes, static means something different:

• A top-level class can be either static or non-static. But the keyword static in the context of a class in C# means

something very different than it does in Java.

• A C# static class can have only static properties and cannot be instantiated.

• Therefore, a top-level non-static class in C# is analogous to a top-level static class in Java. But in Java, top-level

static classes never include the static keyword, it is implicit.

• Nested classes in C# can also be static or non-static. But neither implements the concept of an inner class in

Java, C# doesn’t support the Java concept of inner classes. A C# nested class never gets an automatically

generated reference to an instance of the enclosing class.

See https://msdn.microsoft.com/en-us/library/ms173120.aspx

Page 8: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 8

Here is a C# example of a nested class. The nested class is not declared static, but it has behavior that is similar to a static

nested class in Java.

public class Outer { private int v; private int x; public class Inner { private int p; private int q; public Inner() { p = 0; q = 0; } } public Outer() { v = 0; x = 0; } } class Tester { public static void Main(string[] args) { Outer outer = new Outer(); Outer.Inner inner = new Outer.Inner(); note the “static” style } }

C# Does Not Support Java Inner Classes

In the Main() method, note how the instance of the inner class was instantiated. The instantiation does not use a reference

to an instance of the outer class object. Rather, it uses a static-style instantiation, referencing only the name of the outer

class, not an instance of the outer class.

To experiment further, note that in the Inner() constructor in C#, the code would not be able to make an unqualified

reference to an instance variable of the outer class, for example:

public Inner() { p = v; // illegal in C#, no outer instance q = x; }

This might come as a surprise because the similar operation is permitted in Java because of the implied reference to an

instance of the enclosing class.

public Inner() { p = v; // okay in Java, same as “p = Outer.this.v;” q = x; }

The point of this example is that Java-style inner classes are not supported in C#.

Page 9: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 9

Here is the similar definition in Java:

public class Outer { private int v; private int x; public class Inner { private int p; private int q; public Inner() { p = 0; q = 0; } } public Outer() { v = 0; x = 0; } } class Tester { public static void main(String[] args) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); note the non-static style } }

Note the construction in the main method that would be required to independently instantiate an object of the inner class.

It must be instantiated explicitly with a reference to an instance of the outer class. Java also supports the static style

instantiation, which you would use if class Inner were declared to be a static nested class rather than an inner class.

Here’s another Java example, with example of allowed/disallowed operations:

public class MainClass { private int x; private int y; private static int z; public static class StaticSubClass { private int p; private static int q; public void f() { MainClass m = new MainClass(); //p = x; // not okay p = m.x; // okay p = z; //q = x; // not okay q = m.x; // okay q = z; } } public class SubClass { private int a; //private static int b; // not okay } } class Driver { public static void main(String[] args) { MainClass m = new MainClass(); MainClass.StaticSubClass c1 = new MainClass.StaticSubClass(); MainClass.SubClass c2 = m.new SubClass(); } }

Page 10: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 10

Values and References

Data is stored in memory, either a primitive variable or an object. Variables and objects have both a content and a

location. Value refers to the content of some variable or object, and reference refers to the location of some variable or

object.

In Java, primitive variables are treated strictly with value semantics only. The programmer cannot obtain a reference

to a primitive variable because there is no programming mechanism to refer to where the primitive variable is located. If

a primitive variable is declared inside a method (a local variable), the variable is created on the stack, and the variable is

deleted when the method that contains it returns. Such memory handling is sometimes called static memory allocation.

In Java, object references are handled with strict reference semantics only. Objects cannot be declared or created

directly. Only a reference variable can be declared. Then an object is created using the “new” keyword. The memory

comes from the heap, and the “new” operator returns its location. This location is assigned to the reference variable.

The memory for the object is retained as long as at least one reference to the object is reachable. Objects cannot be

allocated on the stack, although reference variables that point to them may be on the stack.

In C and C++, the programmer can use pointers and reference parameters in methods to treat both primitives and objects

as either references or pointers. This gives rise to quite a bit of additional syntax in C++, in particular. Here’s an

example from the C programming language which provides an address operator & to obtain the address or pointer to any

variable and an indirection operator * to reach a value indirectly through a pointer variable.

int x; // x is of type “int” int *p; // p is of type “pointer to int” x = 5; // assign 5 to x p = &x; // assign address of x to p int y = *p; // assign the indirection of p (in this case 5) to y

C# classes are like Java classes: they define objects which live on the heap and which undergo garbage colllection.

Reference semantics apply.

C# structs don’t have a counterpart in Java: they define objects which live on the stack and which, like local or block

variables, are automatically created and destroyed on function call and function return. Also, structs cannot be inherited,

there are no base structs and derived structs. Structs are reserved for small simple structured types. Value semantics

apply.

Significantly, C# structs are also different from C++ structs. In C++, struct is almost identical to class.

C# has adopted a uniform syntax for instantiating struct objects and class objects, so that it can be hard to impossible to

tell from code usage alone whether a data type was defined using a class or a struct. To be sure whether an object is

defined by a class or a struct, you should check the API or other documentation for the formal definition.

Look at the following program and note its output:

Page 11: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 11

using System; class Record { public int x; public int y; public void Print() { Console.WriteLine("x={0}, y={1}",x,y); } } struct Pt { public int x; public int y; public void Print() { Console.WriteLine("x={0}, y={1}",x,y); } } class StructTest { public static void Main() { Console.WriteLine("Hello, World!"); Record r1 = new Record(); r1.x = 3; r1.y = 4; r1.Print(); Pt p1 = new Pt(); p1.x = 5; p1.y = 6; p1.Print(); Record r2 = new Record(); r2.x = 8; r2.y = 9; r2.Print(); Pt p2 = new Pt();

p2.x = 12; p2.y = 13; p2.Print(); r2 = r1; r2.Print(); // #1 r2.x = 18; r2.y = 19; r1.Print(); p2 = p1; p2.Print(); // #2 p2.x = 23; p2.y = 24; p1.Print(); } }

Output is Hello, World! x=3, y=4 x=5, y=6 x=8, y=9 x=12, y=13 x=3, y=4 x=18, y=19 x=5, y=6 x=5, y=6

The explanation is that the assignment on line #1 performs a reference copy, while the assignment on line #2 performs a

memberwise copy between objects. This is a direct consequence of the how the objects in question were declared, either

as structs or classes.

Page 12: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 12

Classes and Structs in the .NET Class Libraries

In Java, primitives are represented by datatypes that are not part of any class hierarchy. In cases where strict objects are

required rather than a primitive, Java provides a corresponding “wrapper” class for each primitive:

Primitive Wrapper

int Integer

long Long

float Float

double Double

char Character

boolean Boolean

… …

In C#, the primitive or built-in types are each represented by an underlying .NET type. The C# types are aliases for the

underlying types. Here’s a table of the correspondences from https://msdn.microsoft.com/en-us/library/ya5y69ds.aspx

C# Type .NET Framework Type

bool System.Boolean

byte System.Byte

sbyte System.SByte

char System.Char

decimal System.Decimal

double System.Double

float System.Single

int System.Int32

uint System.UInt32

long System.Int64

ulong System.UInt64

object System.Object

short System.Int16

ushort System.UInt16

string System.String

The aliases and the underlying .NET types are fully interchangeable in a C# program. The following two lines are

equivalent:

int x = 123; System.Int32 x = 123;

Page 13: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 13

The .NET types are all represented by a struct or class definition in the FCL. In this sense, C# doesn’t have primitive

types in the sense that Java uses the term primitive. For example, even a variable of type “int” can have methods applied

to it. This can lead to some C# code that looks unusual to a Java programmer:

int x = 12345; string s = x.ToString(); Console.WriteLine(s);

The explanation is that “int” is just an alias for “System.Int32” which is defined as a struct.

Passing Parameters to Methods

• The keyword “out” causes a parameter to be passed by reference.

• The keyword “ref” is similar, but the parameter must be initialized before being passed.

See the MSDN article for more info: http://msdn.microsoft.com/en-us/library/0f66670z.aspx

Page 14: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 14

Class Properties

In Java, standard OOD/OOP style recommends defining properties as private instance variables, with public accessor

and mutator methods for external access to the property value as needed.

class Time { private int hour; // instance var or property … public int getHour() { // accessor return hour; } public void setHour(int h) { // mutator hour = h; } } class Driver { public static void main(String[] args) { Time t = new Time(); t.setHour(3); // use mutator int x = t.getHour(); // use accessor } }

In C#, the instance variable is declared as in Java. A property is then separately defined. The property definition

controls access to the underlying instance variable through get and set operations. But from outside the class, the get and

set operations are invoked implicitly just by naming the property. No explicit reference to set and get is made.

class Time { private int hour; // instance var … public int Hour { // property get { return hour; // “return” is a keyword } set { hour = value; // “value” is a keyword } } } class Tester { public static void Main() { Time t = new Time(); t.Hour = 3; // uses set property int x = t.Hour; // uses get property } }

Page 15: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 15

Inheritance

Java uses the terms “superclass” and “subclass” to describe the inheritance relationship. It uses two keywords: one class

“extends” another class, and “implements” an interface. A class may extend only one class (single inheritance), but may

implement an arbitrary number of interfaces.

C# uses the terms “base class” and “derived class”. Like Java, C# enforces single inheritance of a class, arbitrary

inheritance of interfaces. But C# uses C++ style inheritance syntax and does not use the “extends” and “implements”

keywords. This makes it harder to tell if a base class is a class or an interface, but the C# convention is to choose

interface names that begin with capital “I”.

class A : B { … }

means class A (the derived class) inherits from class B (the base class).

C# uses C++ syntax to handle issues such as the derived class constructor calling the base class constructor. For

example (O’Reilly C# text):

class Window { // base class public Window(int top, int left) { … } // constructor } class ListBox : Window { // derived class public ListBox(int top, int left, String contents) : base(top,left) { … } }

The derived class calls the base class constructor (named base) using the “member initializer list” syntax, which is a

special expression starting with a colon “:” inserted between the argument list and the body of the method, ie, between

the “)” and the “{”. This syntax is borrowed directly from C++.

Page 16: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 16

Polymorphism

Polymorphism is a feature of most OOP languages that ensures that the execution environment determines what type of

object a reference holds dynamically at runtime. The alternative would be to force the compiler to assume the type

always matches the statically declared type of the object. Here’s a Java example.

class Window { public void print() { System.out.println("Window"); } } class ScrollableWindow extends Window { public void print() { System.out.println("Scrollable Window"); } } class ResizableScrollableWindow extends ScrollableWindow { public void print() { System.out.println("Scrollable Resizable Window"); } } public class Poly { public static void main(String[] args) { Window[] examples = { new Window(), new ScrollableWindow(), new ResizableScrollableWindow() }; for (Window w:examples) w.print(); } }

Polymorphism is demonstrated by the usage of the reference variable “w” in the “main” method. If the compiler were

forced to make typing decisions at compile time, since the declared type of “w” is “Window”, then the “print()” method

can only refer to the “print()” method of class “Window”. If there were no polymorphism, the output would be Window Window Window

But polymorphism means that the type decision is made at runtime. Reference “w” can legally refer to objects of any

subclass of “Window”. The type of object being referenced by w is determined by the interpreter at runtime, then the

“print()” method for that type is called. The output is actually Window Scrollable Window Resizable Scrollable Window

This second output demonstrates that Java supports polymorphism. The difference in behavior is sometimes referred to

as static binding vs. dynamic binding. Static binding means that decisions about what type of an object is referenced are

made by the compiler, while dynamic binding means that the decisions are made by the runtime environment. Runtime

decisions clearly give the program the ability to behave more flexibly, at the cost of perhaps slightly worse performance

because of the increase in runtime checking.

Some authors say that polymorphism is the feature or concept, while dynamic binding is a detail implementation that

supports the concept.

Page 17: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 17

The equivalent example in C# is

using System; class Window { public virtual void Print() { Console.WriteLine("Window"); } } class ScrollableWindow : Window { public override void Print() { Console.WriteLine("Scrollable Window"); } } class ResizableScrollableWindow : ScrollableWindow { public override void Print() { Console.WriteLine("Scrollable Resizable Window"); } } public class Poly { public static void Main() { Window[] examples = { new Window(), new ScrollableWindow(), new ResizableScrollableWindow() }; for (int i=0; i<examples.Length; i++) { Window w = examples[i]; w.Print(); } } }

Virtual Methods and Overrides

The common meaning of a virtual method is that the class containing the virtual method can be subclassed, and the

subclass can override or redefine the virtual method.

In Java, all methods are virtual. To prevent a method from being overridden, it can be declared final.

In C#, methods must be explicitly declared as virtual, they are not virtual by default. As in C++, the usual practice is to

declare a method as virtual in the base class when it is first introduced. After this point, in the derived classes that

override it, the virtual keyword is not repeated. Instead, the override (or new) keyword is used.

Page 18: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 18

Overriding Inherited Methods in C#

• In C#, in the derived class, virtual methods being overridden carry the keyword “override”.

• In C#, in the derived class, a method that is intended to hide the inherited virtual method, not override it, uses

the keyword “new”. This is the default, but the compiler generates a warning that the “new” keyword is

implied.

Example: 4-level Class Hierarchy in Java

class Window { public void pr() { System.Console.WriteLine("Window"); } } class ScrollableWindow : Window { public void pr() { System.Console.WriteLine("Scrollable Window"); } } class ResizableScrollableWindow : ScrollableWindow { public void pr() { System.Console.WriteLine("R/S Window"); } } class Frame : ResizableScrollableWindow { public void pr() { System.Console.WriteLine("Frame"); } } public class PolyTest { public static void Main() { // polymorphic behavior disabled Window w = new Window(); w.pr(); ScrollableWindow sw = new ScrollableWindow(); sw.pr(); ResizableScrollableWindow rsw =

new ResizableScrollableWindow(); rsw.pr(); Frame f = new Frame(); f.pr(); // polymorphic behavior enabled (if present) Window w2; w2 = sw; w2.pr(); w2 = rsw; w2.pr(); w2 = f; w2.pr(); ScrollableWindow sw2; sw2 = sw; sw2.pr(); sw2 = rsw; sw2.pr(); sw2 = f; sw2.pr(); } }

Page 19: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 19

General Rules for C#

• Non-virtual functions are not marked in the base class. No dynamic binding possible (no polymorphism) in base

classes.

• For “typical” polymorphic behavior, mark first function in the chain as “virtual”, all others in the chain marked

“override”.

• To break the chain at some point, mark the function “new”, not “override”. The function can still be marked virtual

or not, depending on what behavior is desired for the remainder of the chain.

• If the base function is not marked “virtual”, the derived class cannot mark it as “override”.

• If the base function is marked “virtual”, the derived class should mark it as either “new” or “override”.

• The “override” tag implies “virtual”, and it can’t be repeated (can’t declare “virtual override”).

class Window { public virtual void pr() { System.Console.WriteLine("Window"); } } class ScrollableWindow : Window { public override void pr() { System.Console.WriteLine("Scroll Window"); } }

See another example at

http://www.akadia.com/services/dotnet_polymorphism.html.

Page 20: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 20

Function Pointers in C (Precursor to C# Delegates)

An interesting feature of C is its ability to store the entry point address of a function in a variable and invoke it later.

This is called a function pointer. The hardest part is to correctly declare the variable which is to hold the pointer. Here’s

an example from http://www.newty.de/fpt/intro.html#why. The 4 functions at the top are selected and invoked in two

programming styles: using a “switch” statement with a character selector, and using a function pointer.

float Plus (float a, float b) { return a+b; } float Minus (float a, float b) { return a-b; } float Multiply(float a, float b) { return a*b; } float Divide (float a, float b) { return a/b; } void Switch(float a, float b, char opCode) { float result; switch(opCode) { case '+' : result = Plus (a, b); break; case '-' : result = Minus (a, b); break; case '*' : result = Multiply (a, b); break; case '/' : result = Divide (a, b); break; } cout << result << endl; } void Switch_With_Pointer(float a, float b, float (*pt2Func)(float, float)) { float result = pt2Func(a, b); // call using function pointer cout << result << endl; } int main(void) { Switch(2, 5, '-'); // use switch Switch_With_Pointer(2, 5, &Minus); // use function pointer }

The function input parameter float (*pt2Func)(float, float)

defines “pt2Func” as a pointer to a function which takes two float arguments and returns a float result.

The value passed to the parameter is &Minus This is the same as the assignment pt2Func = &Minus; In some C compilers, the “&” address operator is optional.

The invocation of the “Minus” function indirectly through the pointer is float result = pt2Func(a, b);

Page 21: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 21

Delegates

A C# delegate is an abstraction that allows a method to be passed around as an object and invoked indirectly when

needed. It is similar to a function pointer in C. Java achieves a similar effect with listeners which allow the programmer

to define a method to be called at a later time in response to an event. There are three steps to using delegates. Some of

these steps have been streamlined in the latest versions of the .NET SDK.

Step 1: declare the delegate as a datatype using the delegate keyword.

Examples: delegate void myDelegate1(); delegate void myDelegate2(string);

In the first case, the symbol myDelegate1 is now a delegate type that represents any method with return type void and no

parameters, while MyDelegate2 represents any method with return type void and one argument of type string. For the

programming required to develop C#/.NET GUIs, you will not need to introduce any new delegate types yourself, you

will only need to use delegate types that have already been defined by .NET. It will still be useful for you to see a

complete example to understand how delegates work.

Step 2: Declare a delegate type variable, instantiate a delegate object of the declared type, and assign it to the variable.

delegate long binop(long,long); public long add(long a, long b) { return a + b; } binop op = new binop(add);

• Line 1 declares a delegate type named binop. The delegate name appears in the position of a function call. The

return type and argument list complete the declaration, indicating what kind of function the delegate can

represent.

• Line 2 is a method that happens to conforms to the binop signature.

• Line 3 instantiates an instance of the binop delegate and stores a reference to it in variable op. So op can now

be used as an indirect function reference back to the add() method.

Step 3: use the delegate to indirectly invoke the original method

long x = op(3,5);

So this is an indirect invocation of the add() method, accessed indirectly through the op() delegate instance. The real

utility of the delegate instance is that it can be passed around from method to method as a parameter, and invoked only

when needed. Here’s the definition of a method that accepts a delegate as a parameter:

void someMethod(int x, long y, binop someop) { … }

Here’s a program that shows how to use someMethod()

Page 22: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 22

using System; public class MathClass {

public static long Add (int i, int j) { return (i+j); } public static long Multiply (int i, int j) { return (i*j); }

} public class DelegateTest {

delegate long myDelegate (int i, int j); // define delegate

public static void Main(string[] args) {

Console.WriteLine("Call to Add method through delegate"); myDelegate operation = new myDelegate(MathClass.Add); // instantiate long l = operation(10, 20); // invoke Console.WriteLine("Sum of 10 and 20 is " + l);

Console.WriteLine("Call to Multiply method thru delegate"); operation = new myDelegate(MathClass.Multiply); // instantiate l = operation(1639, 1525); // invoke Console.WriteLine("1639 multiplied by 1525 equals " + l);

} } Or more compactly:

using System; public class MathClass {

public static long Add (int i, int j) { return (i+j); } public static long Multiply (int i, int j) { return (i*j); }

} public class DelegateTest {

public delegate long binop(int i, int j);

public static long eval(binop op, int x, int y) { return op(x,y); }

public static void Main(string[] args) { Console.WriteLine(eval(new binop(MathClass.Add),20,30)); Console.WriteLine(eval(new binop(MathClass.Multiply),1639,1525));

} }

In these examples, the delegate objects are initialized with static methods from class MathClass. Instance methods can

also be used to initialize a delegate object by first creating an instance of the object, then referencing the method in the

context of the object of the class.

Page 23: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 23

Shortcut for Instantiating Delegates

The full syntax for instantiating a delegate object from its definition is similar to instantiation of any object with the

“new” operator. This first statement is merely a definition of a delegate template named “MyDelegate”: delegate long myDelegate (int i, int j);

This next statement instantiates a delegate object from this template and stores a reference to it: myDelegate operation = new myDelegate(MathClass.Add);

Finally, the third statement invokes the “MathClass.Add” method indirectly through the delegate long l = operation(10, 20);

The second statement can now be abbreviated as follows: myDelegate operation = MathClass.Add;

Although this syntax makes the delegate look more like a simple function pointer (as in C), it is really just a shortcut for

the earlier full version. It is understood that a delegate object is still instantiated implicitly.

Here’s the previous example with the shortcut for delegate instantiation added:

using System; public class MathClass {

public static long Add (int i, int j) { return (i+j); } public static long Multiply (int i, int j) { return (i*j); }

} public class DelegateTest {

public delegate long binop(int i, int j);

public static long eval(binop op, int x, int y) { return op(x,y); }

public static void Main(string[] args) { Console.WriteLine(eval(MathClass.Add,20,30)); Console.WriteLine(eval(MathClass.Multiply,1639,1525));

} }

Page 24: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 24

Delegates and Events

Delegates are central to event handling in C#. In Java, an object fires events, and the response is provided by an event

listener attached to that object. In C#, instead of a listener, a delegate is registered with the source of the event. The

delegate is called when the event is triggered, so the response to the event is assigned to the delegate.

Before discussing how to define your own events and delegates (something that you will not need to do very often for

the projects in this course), let’s get a preview of how some existing events and delegates that will be used in GUI

programming work.

In WinForms, the top-level container class is called class Form. The form object accepts a wide range of events such as

mouse clicks. Here’s a section of the API on class System.Windows.Forms.Form:

Selected Events for class Form

Name Description

Activated Occurs when the form is activated in code or by the user.

AutoSizeChanged Occurs when the AutoSize property changes.

Click Occurs when the control is clicked.(Inherited from Control.)

ClientSizeChanged Occurs when the value of the ClientSize property changes. (Inherited from Control.)

Closed Occurs when the form is closed.

Closing Occurs when the form is closing.

ControlAdded Occurs when a new control is added to the Control.ControlCollection.(Inherited from Control.)

ControlRemoved Occurs when a control is removed from the Control.ControlCollection.(Inherited from Control.)

Deactivate Occurs when the form loses focus and is no longer the active form.

Disposed Occurs when the component is disposed by a call to the Disposemethod. (Inherited from Component.)

DoubleClick Occurs when the control is double-clicked.(Inherited from Control.)

DragDrop Occurs when a drag-and-drop operation is completed.(Inherited fromControl.)

DragEnter Occurs when an object is dragged into the control's bounds.(Inherited from Control.)

DragLeave Occurs when an object is dragged out of the control's bounds.(Inherited from Control.)

DragOver Occurs when an object is dragged over the control's bounds.(Inherited from Control.)

Enter Occurs when the control is entered.(Inherited from Control.)

FormClosed Occurs after the form is closed.

FormClosing Occurs before the form is closed.

GotFocus Occurs when the control receives focus.(Inherited from Control.)

Page 25: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 25

Invalidated Occurs when a control's display requires redrawing.(Inherited fromControl.)

KeyDown Occurs when a key is pressed while the control has focus.(Inherited fromControl.)

KeyPress Occurs when a character. space or backspace key is pressed while the control has focus.(Inherited

from Control.)

KeyUp Occurs when a key is released while the control has focus.(Inherited fromControl.)

Layout Occurs when a control should reposition its child controls.(Inherited from Control.)

Leave Occurs when the input focus leaves the control.(Inherited from Control.)

Load Occurs before a form is displayed for the first time.

LocationChanged Occurs when the Location property value has changed.(Inherited fromControl.)

LostFocus Occurs when the control loses focus.(Inherited from Control.)

MouseClick Occurs when the control is clicked by the mouse.(Inherited fromControl.)

MouseDoubleClick Occurs when the control is double clicked by the mouse.(Inherited fromControl.)

MouseDown Occurs when the mouse pointer is over the control and a mouse button is pressed.(Inherited from Control.)

MouseEnter Occurs when the mouse pointer enters the control.(Inherited fromControl.)

MouseHover Occurs when the mouse pointer rests on the control.(Inherited fromControl.)

MouseLeave Occurs when the mouse pointer leaves the control.(Inherited fromControl.)

MouseMove Occurs when the mouse pointer is moved over the control.(Inherited from Control.)

MouseUp Occurs when the mouse pointer is over the control and a mouse button is released.(Inherited

from Control.)

MouseWheel Occurs when the mouse wheel moves while the control has focus.(Inherited from Control.)

Move Occurs when the control is moved.(Inherited from Control.)

Paint Occurs when the control is redrawn.(Inherited from Control.)

Resize Occurs when the control is resized.(Inherited from Control.)

SizeChanged Occurs when the Size property value changes.(Inherited from Control.)

Page 26: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 26

As an example, you can see that objects of class Form generate MouseDown events (roughly equivalent to Java

mousePressed). The MouseDown event is associated with a delegate called MouseEventHandler, which is defined like

this:

public delegate void MouseEventHandler( object sender, MouseEventArgs e )

The declaration introduces a delegate type called MouseEventHandler. It represents a function with a return type of void

and two arguments, the first of type object and the second of type MouseEventArgs. Any concrete function with this

signature can be used as the delegate instance to respond to the event. For example:

using System; using System.Windows.Forms; class Tester { public static void f(object obj, MouseEventArgs args) { // 1 Console.WriteLine("mouse down"); } public static void Main() { Form f = new Form(); f.MouseDown += new MouseEventHandler(Tester.f); // 2 Application.Run(f); } }

At comment 1, we define a method named f with the appropriate signature. At comment 2, we instantiate a

MouseEventHandler instance from f and assign it as the handler for the MouseEvent event for Form f.

In order to use the .NET framework class libraries to write your code, you will not be defining new events and delegates,

only using existing event and delegate definitions from the libraries.

Here is one more example of how to write your own.

Page 27: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 27

Example from URL given above:

using System; public class EventClass { // Declare the Delegate Datatype public delegate void CustomEventHandler(object sender, EventArgs e); // Declare Event using Delegate Datatype + “event” keyword public event CustomEventHandler CustomEvent; public void InvokeEvent() { CustomEvent(this, EventArgs.Empty); } } class TestClass { static void Main(string[] args) { EventClass myEventClass = new EventClass(); // Associate the handler with the events myEventClass.CustomEvent += new EventClass.CustomEventHandler(CustomEvent1); myEventClass.CustomEvent += new EventClass.CustomEventHandler(CustomEvent2); myEventClass.InvokeEvent(); myEventClass.CustomEvent -= new EventClass.CustomEventHandler(CustomEvent2); myEventClass.InvokeEvent(); } private static void CustomEvent1(object sender, EventArgs e) { Console.WriteLine("Fire Event 1"); } private static void CustomEvent2(object sender, EventArgs e) { Console.WriteLine("Fire Event 2"); } }

Output is Fire Event 1 Fire Event 2 Fire Event 1

Page 28: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 28

In the definition of the EventClass class, objects of this type are given an event of type CustomEvent. As a programmer,

you need to be familiar with the features of each predefined class that you use, including its methods, properties, and

events.

When the “InvokeEvent” method of this class is called, it creates or “fires” an event of type CustomEvent.

The statements that register delegates with the event

myEventClass.CustomEvent += new EventClass.CustomEventHandler(CustomEvent1); myEventClass.CustomEvent += new EventClass.CustomEventHandler(CustomEvent2);

can be abbreviated using the shortcut discussed earlier:

myEventClass.CustomEvent += CustomEvent1; myEventClass.CustomEvent += CustomEvent2;

Delegates Used as Event Handlers

In Java, we saw a pairing between an event and a listener. A Java event is an object and a listener is any object that

provides the necessary methods.

In C#, the pairing is between events and event handlers or delegates. The delegate used in the example above has a

signature that is representative of many event handlers. Here’s the definition of a very common event called the Paint

event.

The delegate for the Paint event looks like this (in the System.Windows.Forms namespace):

public delegate void PaintEventHandler(object objSender,

PaintEventArgs pea);

Any method that has this signature can act as the event handler for the Paint event.

static void MyPaintHandler(object objSender, PaintEventArgs pea) { … }

The Form class contains a property or field named Paint. This is where you attach or register handlers that implement

responses to the Paint event for that Form:

Form form = new Form(); form.Paint += new PaintEventHandler(MyPaintHandler);

This can be abbreviated to: form.Paint += MyPaintHandler;

The “+=” operator is used in the same sense as the “addListener()” methods in Java.

Page 29: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 29

Anonymous Methods/Delegates and Lambda Expressions

Delegates are the mechanism for responding to events in both Windows Forms and WPF. For example, the Paint event

for a Form uses the PaintEventHandler delegate. The complete process for defining and assigning the delegate might

look like this:

public void DoPaint(object sender, PaintEventArgs args) { // paint/draw operations here } PaintEventHandler p = new PaintEventHandler(DoPaint); Form f = new Form(); f.Paint += p;

A delegate method can be created from an anonymous method using the “delegate” keyword:

f.Paint += delegate(object obj, PaintEventArgs args) { // paint/draw operations here };

Another kind of anonymous method can be defined using lambda expressions. Lambda expressions are a mathematical

notation for describing functions that predates C#. Here is a simple example

x => x*x

uses a lambda expression to describe a function of x, namely x2. It could be used in a program like this:

using System; public class LambdaDemo { delegate int F(int x); delegate double G(double x, double y); public static void Main(string[] args) { F f = x => x * x; Console.WriteLine(f(5)); G g = (x,y) => Math.Sqrt(x*x + y*y); Console.WriteLine(g(3.0,4.0)); } }

The previous anonymous method could be defined as follows using a lambda expression:

f.Paint += (object obj, PaintEventArgs args) => { // paint/draw operations here };

Page 30: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 30

Parameter types can be frequently omitted when they can be determined through type inference:

f.Paint += (obj, args) => { // paint/draw operations here };

And a common convention is to use the parameter name “_” for a single parameter that is not used in the body of the

lambda:

f.Paint += (_, args) => { // paint/draw operations here };

Here’s the equivalent in C#. Compared to Java, the main differences are these:

• C# supports static nested classes, but not inner classes (non-static nested classes).

• However, the keyword “static” is not used with the nested class, it must be implicit.

Declaring a C# class to be static means something entirely different, discussed next.

C# Static Classes Similar to Java Interfaces with Data Members

Adding the keyword “static” to a class in C# simply means that the class consists solely of static data and cannot be

instantiated.

Partial Classes

C# GUI building in WPF can be optionally divided into 2 parts: markup for layout and code for event handling. The

two types of notation must be defined in separate files, followed by various preprocessing and linking steps before the

complete executable application is built. Because of this initial separation of partial definitions, the keyword “partial” is

required to tag the class definition in a code file. The markup file defines a “x:Class” attribute for the top-level markup

tag. Its value then corresponds to a partial class defined in a corresponding code file. This feature of WPF will be

discussed in detail later.

Page 31: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 31

Intro to Programming Windows Forms

The focus of GUI development for the Microsoft .NET platform is gradually shifting away from Windows Forms and

toward the Windows Presentation Foundation (WPF). Nevertheless, Windows Forms is not dead, and is worth a brief

look because at a minimum it serves as a “gentle” intro to WPF. Windows Forms is discussed briefly here, but the main

focus of GUI building for .NET is WPF, which will be covered later in more depth.

Namespaces

A namespace is a logical collection of predefined symbols. The concept was introduced by C++. They are somewhat

analogous to packages in Java. The contents of a namespace are made available to a source file with the “using”

directive instead of the “import” command. Typical Form-based GUIs require the following namespaces:

using System; using System.Drawing; using System.Windows.Forms;

These statements will appear at the top of most source files. Others will be introduced later (e.g.,

System.ComponentModel).

The .NET Framework Class Library

Access to the .NET FCL online documentation was described above. Here is a list of relevant namespaces for programs

in this course. Even this list is a little long, we will probably only use a subset of these.

• System

• System.Collections

• System.Collections.Generic

• System.Data

• System.Drawing

• System.IO

• System.Net

• System.Security

• System.Text

• System.Threading

• System.Web

• System.Windows.Forms

• System.Xml

Within each namespace is a list of classes. The title of the namespace should be a general guide to the kinds of classes it

contains. The documentation for each class includes sections for the following:

• Constructors

• Properties

• Methods

• Events

Because of the heavy use of inheritance within the framework classes, it may take some study to determine answers to

questions such as “from which base class was the BackColor property of class Form first inherited?” The expandable

tree view menu on the left is generally restricted to features defined in the current class. The more complete page

displayed on the right includes features present via inheritance.

Page 32: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 32

Class Control

The Control is analogous to the Component/JComponent classes in Java. It is the base class for most objects used in the

creation of a GUI. It introduces many properties and events that are inherited throughout the classes of the GUI-related

namespaces.

Class Form

The Form is similar to a JFrame/JPanel class in Java. It acts as the top-level container for a .NET-based GUI. An

application can either

• create a generic Form instance and customize it by changing its properties on the fly, or

• extend class Form, customize the class by setting properties in a constructor and/or overriding methods, then

create the customized object by calling the class constructor.

The first is a “quick-and-dirty” way to create a “one-shot” object. The second is better if a template for multiple objects

is needed. In addition, some methods of class Form are “protected” and can be customized only by subclassing and

overriding.

The Application.Run() Method

This method defines an entry point to a GUI-based application. The argument to the method is the main Form for the

application.

C# Properties VS Java Instance Variables Java Example C# Example JFrame f = new JFrame(); Form f = new Form();

f.setSize(300,200); f.ClientSize = new Size(300,200);

Objects in Java are instantiated, then customized by changing the values of instance variables via the appropriate set or

get methods. Objects in C# are instantiated, then customized by direct assignment to the appropriate property (which

implicitly invokes the “set” block for the property).

Page 33: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 33

Java Events

In Java, both events and event listeners are organized around composites of low-level “atomic” events. For example, the

MouseEvent and MouseListener are composites that represents 5 atomic events:

• mousePressed

• mouseReleased

• mouseClicked

• mouseEntered

• mouseExited

Each atomic event and listener is handled by a single method within this composite. In contrast, Windows Forms defines

only the atomic events. Each atomic event is handled by a delegate with the appropriate signature (return type void, 2

parameters, one of type object, one of type EventArgs or one of its derived classes).

Interface Methods Adapter Event

ActionListener actionPerformed n/a ActionEvent

MouseListener mousePressed MouseAdapter MouseEvent

mouseReleased

mouseClicked

mouseEntered

mouseExited

MouseMotionListener mouseMoved MouseAdapter MouseEvent

mouseDragged

WindowListener windowOpened WindowAdapter WindowEvent

windowClosing

windowClosed

windowIconified

windowDeiconified

windowActivated

windowDeactivated

In C#/WinForms, low-level events are handled individually by delegates. There is no grouping of related events into a

higher-level handler like a Java listener. To add event handling to a C# program:

• Determine the type of the object being customized (for example, Form or Button).

• Look up the events that the object supports (for example, MouseUp or Paint).

• Determine the delegate for that event type (for example, MouseEventHandler, PaintEventHandler).

• Write a handler for that event that matches the signature of the delegate.

• Register the handler for that event with the object (for example, form.Paint += myPaintMethod; )

Here are some of the most common events and handlers. For each handler type, there is a corresponding event argument

type. The number of possible combinations is much less than it appears, because most events use a generic

EventHandler delegate. Only a few events have custom handlers.

Page 34: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 34

Event Handler Event Argument

MouseUp MouseEventHandler MouseEventArgs

MouseDown

MouseMove

MouseWheel

MouseClick

MouseDoubleClick

MouseEnter EventHandler EventArgs

MouseLeave

MouseHover

MouseCaptureChanged

Paint PaintEventHandler PaintEventArgs

KeyUp KeyEventHandler KeyEventArgs

KeyDown

KeyPress

Click EventHandler EventArgs

DoubleClick

ClientSizeChanged

SizeChanged

Resize

ControlAdded

ControlRemoved

LostFocus

GotFocus

VisibleChanged

Disposed

Note the difference between the MouseClick and the Click events, and the MouseDoubleClick and DoubleClick events.

A Click event is a “high level” event and a MouseClick is a “low level” event. For example, clicking the mouse on a

control generates the following sequence:

MouseDown � Click � MouseClick � MouseUp

Double clicking generates:

MouseDown � Click � MouseClick � MouseUp � MouseDown � DoubleClick � MouseDoubleClick

� MouseUp

Click and Double Click events are “high level” because other user actions such as pressing the <ENTER> key can

generate a “Click” event. This is counter-intuitive since the mouse is not involved.

Java provides many window-specific events, while C# provides only generic control events. But a Form is a Control, so

you can infer how to respond to changes to window state (for example, Java windowActivated can be approximated by

C# GotFocus).

Also note the absence of a “MouseDrag” event in C#/WinForms. The program must keep track of MouseUp and

MouseDown events, and keep track of the state of the mouse buttons to respond to this situation.

Event Handling A specific class defines a subset of the possible event types. The programmer has two choices for implementing a

response to an event for that class:

• Register a delegate for the event property of an object of that class.

• Subclass the class and override the “On” method for that event.

For example, the Form class defines the “Paint” event as a class property, and it defines a protected method named

OnPaint which is the built-in handler for the Paint event.

To create a form and customize its response to the Paint event, you have several choices:

Page 35: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 35

Approach #1: Define a Delegate for the Paint Event for a Generic Form void myHandler(object objSender, PaintEventArgs pea) { … }

Form form = new Form(); form.Paint += new PaintEventHandler(myHandler);

Approach #2: Subclass Form and Override OnPaint Method class MyForm : Form { protected override void OnPaint(PaintEventArgs pea) { … } } … MyForm form = new MyForm();

Approach #3: Do Both

When doing both, it is important for the “On” method to call its inherited counterpart: class MyForm : Form { protected override void OnPaint(PaintEventArgs pea) { base.OnPaint(pea); // <= call inherited method … } } The inherited method is responsible for calling any externally registered delegates. They will not get executed if the

override method omits the call to the original inherited method.

A generic response to an event then looks something like this:

class SomeControl

supports SomeEvent

with handler SomeHandler

and event args SomeEventArgs

Approach #1 SomeControl ctrl = new SomeControl(); … void MyHandler(Object obj, SomeEventArgs args) { … } … ctrl.SomeEvent += MyHandler;

Approach #2 class MyControl : SomeControl { protected override void OnSomeEvent(SomeEventArgs args) { base.OnSomeEvent(args); … } } … MyControl ctrl = new MyControl();

Page 36: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 36

Here are two implementations of a simple GUI whose main form tracks the MouseMove event and outputs mouse

coordinates to the console for each detected event.

Approach #1: Generic Form with Event Handling Delegate using System; using System.Windows.Forms; using System.Drawing; public class ClickTest2 { public static void RespondToMouseMove(object obj, MouseEventArgs a) { System.Console.WriteLine(a.X + " " + a.Y); } public static void Main() { Form form = new Form(); form.MouseMove += RespondToMouseMove; Application.Run(form); } } Approach #2: Derived Class with Method Overrides using System; using System.Windows.Forms; using System.Drawing; public class ClickTest : Form { protected override void OnMouseMove(MouseEventArgs a) { System.Console.WriteLine(a.X + " " + a.Y); } } public class Driver { public static void Main() { ClickTest form = new ClickTest(); Application.Run(form); } }

Page 37: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 37

Example

Here’s a C# version of a greatly simplified version of the Java paint application exercise.

using System; using System.Windows.Forms; using System.Drawing; using System.Collections; // for class ArrayList public class Shape { private int xul,yul,width,height; public Shape(int x1, int y1, int x2, int y2) { xul = (x1<x2)?x1:x2; yul = (y1<y2)?y1:y2; width = (x1<x2)?x2-x1:x1-x2; height = (y1<y2)?y2-y1:y1-y2; } public int Xul { set { xul = value; } get { return xul; } } public int Yul { set { yul = value; } get { return yul; } } public int Width { set { width = value; } get { return width; } } public int Height { set { height = value; } get { return height; } } public void draw(Graphics g) { g.DrawRectangle(Pens.Black,xul,yul,width,height); } } public class PaintForm : Form { private ArrayList shapes; private Shape currentShape; private int startx,starty; private bool shapeInProcess; public PaintForm() { shapes = new ArrayList(); currentShape = null; startx = starty = 0; shapeInProcess = false; } public void startShape(int x, int y) { startx = x; starty = y; shapeInProcess = true; } public void stopShape(int x, int y) { currentShape = new Shape(startx,starty,x,y); }

Page 38: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 38

protected override void OnMouseDown(MouseEventArgs evt) { startShape(evt.X,evt.Y); } protected override void OnMouseUp(MouseEventArgs evt) { stopShape(evt.X,evt.Y); shapes.Add(currentShape); currentShape = null; shapeInProcess = false; Invalidate(); } protected override void OnMouseMove(MouseEventArgs evt) { if (shapeInProcess) { stopShape(evt.X,evt.Y); Invalidate(); } } protected override void OnPaint(PaintEventArgs evt) { Graphics g = evt.Graphics; if (currentShape!=null) currentShape.draw(g); for (int i=0; i<shapes.Count; i++) ((Shape)shapes[i]).draw(g); } } public class Driver { public static void Main() { PaintForm form = new PaintForm(); Application.Run(form); } }

Page 39: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 39

Summary: Events and Delegates

A Windows Forms component defines events that it receives. Events are atomic, not aggregated into related groups as in

Java.

Mouse Events

• MouseUp, MouseDown, MouseClick, MouseDoubleClick, MouseMove, MouseEnter, MouseLeave,

MouseHover, MouseWheel

Window Events

• Activated, Closed, Closing, Deactivated, Disposed,

Others

• Click, DoubleClick, Paint, Load, Resize, SizeChanged

Each event has a corresponding delegate and corresponding “On” method

Example: Paint

• Delegate: public delegate void PaintEventHandler(object objSender, PaintEventArgs args);

• On Method protected void OnPaint(PaintEventArgs args) { … }

To customize the component’s response to the event, either define a delegate and register it with the object’s Paint event,

or override the “OnPaint” method in a subclass of the component.

Similar to anonymous class objects in Java, C# delegates may be instantiated with anonymous methods.

One Subtlety When Overriding …

There is a small asymmetry regarding these two ways of adding event responses if the classes also involve inheritance.

The “On” methods are responsible for calling the registered delegates. So when you create a subclass and override an

“On” method, the “On” method should call the inherited version. Otherwise the override turns off the ability to keep any

delegates “in the loop”. Remember that in C#, the superclass is called the “base” class, so the superclass constructor is

called “base()” not “super()”.

class MyForm : Form { … protected override void OnPaint(PaintEventArgs args) { base.OnPaint(args); … } } class AnotherForm : MyForm { } … AnotherForm f = new AnotherForm(); f.Paint += someDelegate; // won’t work unless MyForm method

// calls base.OnPaint() …

Connecting Controls To Forms

When attaching a component to a container in Java, the “child” is added to the “parent”: parent.add(child) // Java Swing

When attaching a control to a form in C# and Windows Forms, there are two approaches. The first approach is similar

to Java, in which the child is attached to the parent. In C#/Windows Forms, the child must be explicitly added to the

parent’s array of controls: parent.Controls.Add(child); // C# and Windows Forms

This is an interesting statement because it reflects more accurately what happens “behind the scenes” in Java with the

“parent.add(child)” statement. The “add” statement is actually inserting the child component into the parent’s array of

child controls in this case too.

Page 40: COMP 585 Noteset #8 Microsoft APIs for GUI App Development

COMP 585 Noteset #8 40

The second approach in C#/Windows Forms is to set the “parent” property of the child component:

class MyForm : Form { public MyForm() { Control c = new Control(); c.Parent = this; // attaches “c” to “this” … } … }

Telling the control who is its parent is the same as adding the control to the parent. This second style is more common in

the Petzold code examples.

Absolute Positioning

The default style in Windows Forms programming for arranging controls on a form is absolute positioning. This style is

inherited from older versions of the Visual Basic GUI builder. Once a control has been positioned on a form, it is

assumed that it will remain in that position. Button btn = new Button(); btn.Parent = this; btn.Text = "Click me!"; btn.Location = new Point(50, 25); // set location btn.AutoSize = true; // set size btn.Click += ButtonOnClick;

Complete Example (2nd Petzold Text): Simple Form + Button //----------------------------------------------- // FormWithButton.cs (c) 2005 by Charles Petzold //----------------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class FormWithButton: Form { [STAThread] // compiler directive public static void Main() { Application.EnableVisualStyles(); Application.Run(new FormWithButton()); } public FormWithButton() { Text = "Form with Button"; Button btn = new Button(); btn.Parent = this; btn.Text = "Click me!"; btn.Location = new Point(50, 25); btn.AutoSize = true; btn.Click += ButtonOnClick; } void ButtonOnClick(object objSrc, EventArgs args) { MessageBox.Show("The button was clicked!", "Button"); } }