Professional Documents
Culture Documents
Introduction
C# is Microsofts branded new language, designed for its brand new platform, the .NET Framework. As such as, C# is likely to be the language of choice for developing applications in the Microsoft world. That alone would make C# a great choice as a first language to learn. But, perhaps more importantly, C# is a very elegantly designed language, which encountered good programming practice (in particular with regard to object oriented programming). C# is descended directly from the powerful but complex C++ language, and inherits most of the power without the complexity. C# has also been deeply influenced by other languages, including Java and Delphi, and its fans believe that it has been able to take the best of these languages while avoiding their mistakes. C# is a C- based language that gives developers a language choice for developing with the .NET Framework. Some C, Java, And C++ development will move to C# to take advantage of the .NET features. Visual Basic programmers looking to learn a C language might also move to C#. Visual Basic.NET and C# both support Object Oriented development with the .NET Framework. No matter what language you choose for developing, being able to read code in either language will double your access to Microsoft Visual Studio documentation. And this book will also help you to guide you through step by step examples. The C# language is disarmingly simple, with only about 80 keywords and a dozen builtin datatypes, but C# is highly expressive when it comes to implementing modern programming concepts. C# includes all the support for structured, component-based, object-oriented programming that one expects of a modern language built on the shoulders of C++ and Java. The C# language was developed by a small team led by two distinguished Microsoft engineers, Anders Hejlsberg and Scott Wiltamuth. Hejlsberg is also known for creating Turbo Pascal, a popular language for PC programming, and for leading the team that designed Borland Delphi, one of the first successful integrated development environments for client/server programming. At the heart of any object-oriented language is its support for defining and working with classes. Classes define new types, allowing you to extend the language to better model the problem you are trying to solve. C# contains keywords for declaring new classes and their methods and properties, and for implementing encapsulation, inheritance, and polymorphism, the three pillars of object-oriented programming. In C#, everything pertaining to a class declaration is found in the declaration itself. C# class definitions do not require separate header files or Interface Definition Language (IDL) files. Moreover, C# supports a new XML style of inline documentation that simplifies the creation of online and print reference documentation for an application.
C# also supports interfaces, a means of making a contract with a class for services that the interface stipulates. In C#, a class can inherit from only a single parent, but a class can implement multiple interfaces. When it implements an interface, a C# class in effect promises to provide the functionality the interface specifies. C# also provides support for structs, a concept whose meaning has changed significantly from C++. In C#, a struct is a restricted, lightweight type that, when instantiated, makes fewer demands on the operating system and on memory than a conventional class does. A struct can't inherit from a class or be inherited from, but a struct can implement an interface. This book has been designed to teach you C# form first principles, without assuming any prior programming experience. Well give you a through grounding in the syntax of the C# language itself, and then well look at the most common different types of application you can build with C# - Windows applications, ASP.NET web applications, and web services. Its important to stress from the outset that C# programming cannot be separated from .NET Programming (in fact, the C# compiler comes as part of the .NET Framework), and everything you do in C# will rely very heavily on the .NET Framework. Therefore, this book goes beyond the more syntax of the C# language and shows you how to use the .NET classes from within C# to build real applications. As a result, once, youve learned C#, you wont have too much difficulty picking up other .NET languages, such as Visual Basic. NET or Managed C++. This book has been written to be your complete Visual Studio (either 2003 or 2005 or 2008) support package. It has been designed to be the one you turn to first, the one that gives you more of what you want than any other. Weve crammed as much Visual C# into this book as possible, broken down into hundreds of easily accessible topics, each short and to point, and each with an example and the example with step by step guidance. The format here is like no other computer book series, and its deigned to give you exactly what you want, when you want it. And thats not an easy job, because the subject of this book, Visual C# is huge, Theres much more material here, in grater depth, and there are many more of the programming nuggets that programmers what to see.
And best of all, theres a working example in code for almost every programming topic in the book. The actual process of programming is not abstract; its very applied, and so instead of vague generalities, we get down to the specifies all the specifies that give you everything you need to understand and use C#. Programmers are most interested in performing useful tasks , like adding buttons,
menus, list boxes, or ToolStrip to window; creating graphics animation; creating dialog boxes; creating setup programs; working with files; linking to Web pages; multi- threading and so on. And this book is written for programmers.
Because this book is written for programmers, each chapter is broken up into dozens of practical programming tasks. After selecting the chapter you want, you can turn to the Table of Contents, the Summary of Contents in the chapter to find the task youre interested in. Hundreds of tasks are covered in this book chosen specifically for programmers.
Getting Started In the first two chapters we quickly introduce the major concepts you need to understand
before witting a C# application, and then go on to create a very simple C# program using Visual Studio.NET 2005 to do most of the hard works for us.
C# Language Basics Some of the Chapters in this book will be introduce the basic building blocks of the C#
language. This section looks at how we store data, in C# variables, how we control the flow of our program with conditional branches and loops, and how we structure code with functions.
Programming with objects Objects and the principles of Object Oriented Programming (OOP) play a
fundamental role in C#, so we will introduce the notation of OOP and the philosophy behind it, and look at how we use objects with our C# code.
Working with Windows Forms The First sections concentrate mostly on creating simple Console applications and
simple Windows Application in order to give you a through grounding in the C# language itself. In this section, we go beyond those to look in detail at how we create real Windows Application in C#
Programming on the .NET Framework As already mentioned, almost everything we do in C# is totally dependent on the .NET
Framework. This section looks at some important topics where we need to use classes form the .NET Framework, including accessing database and working with files to use classes from the .NET Framework, including accessing databases and working with files on the local machine or network. We also take a more detailed look at two features specific to .NET programming assemblies (the actual unit of deployment of .NET program), and attributes (a features of .NET that allows us to provide additional information about parts of our program).
C# and the Web Once weve come so far, well take a quick look at a whole new topic, but one thats
integral to the whole idea of the .NET Framework programming for the Internet. In this section of the book we look as ASP.NET and web services. ASP.NET allows us to write dynamic web pages in C#, and web services enable applications to exchange information across the internet.
Things Need to Use This Book The most important thing you need to write C# programs in the C# compiler itself.
This comes with the .NET Framework SDK, which, can be downloaded from the Microsofts site the following URL: http://msdn.microsoft.com/downloads/default.asp?URL=/code/sample.asp?url=/MSDNFILES/027/000/976/msdncompositedoc.xml
However, in this book we will be making heavy use of the Visual Studio.NET
development environment, which simplifies writing C# code in many years, but is particularly useful for writing Windows applications because it contains a visual from designer. If you are not using Visual Studio.NET (either 2003, or 2005, or 2008), then you will not be able to get full value from this book.
System Requirements
Youll need the following hardware and software to complete the examples and to learn the stuff form this book: Microsoft Visual Studio.NET 2003, 2005 or 2008 edition or Microsoft Visual C # 2005 Express Editions. You must purchase it separately and install it before you can complete the examples in this book. A computer capable of running Microsoft Visual Studio.NET. The following hardware configuration is recommended by the Microsoft Visual Studio.NET Web site, at http://msdn.microsoft.com/vstudio/nextgen/ Computer/Processor PC with a Pentium II class processor, 450 megahertz (MHz); Pentium III- class processor, 600 MHZ or above recommended. Operating System Microsoft Windows 2000, 2003, 2008 Server, or Professional Microsoft Windows XP Home or Professional Microsoft Windows Vista Microsoft Windows NT 4.0 Server Memory Windows 2000, 2003, 2008 Professional, 96 megabytes (MB) or higher of RAM; 256 MB recommended Windows 2003, 2003, 2008 Server, 192 MB of RAM; 512 MS recommended Windows XP Professional, 128 MB or RAM; 256 Recommended Hard Disk 1 GB on System Drive and 3.0 gigabyte (GB) on the installation drive Drive CD-ROM or DVD-ROM Drive Display VGA or higher resolution monitor Input Device Microsoft Mouse or Compatible pointing device
Conventions
There are a few conventions in this book that you should know about. Weve used a number of different styles of text and layout in this book to help different between the differentiate between the different kinds of information. Here are examples of the styles we used and expiation of what they mean. Code has several styles. If its a word that were talking about in the text for example, when discussing a for () loop, its in this font. If its a block of code that can be typed as a program and run, then its also in a gray box: private void btnMessage_Click(object sender, EventArgs e) { MessageBox.Show ("Hello! Eagles", "EaglesGroup",MessageBoxButtons.OK, MessageBoxIcon.Information ); } Some times well see code in mixture of styles, like this: private void btnMessage_Click(object sender, EventArgs e) { this.lblDisplay.Text = "Hello Eagles!"; } In case like this, the code with a white background is code we are already familiar with; the line highlighted in gray is a new addition to the code we last looked at it. Tips, DENOTES, and background information comes in this type of font. Important pieces of information come in like this Happy Programming Bullets appear indented, with each new bullet marked as follows: Using in the Table for the controls Important words are in this type
Customer Support
We always value hearing from our readers, and we want to know what you think about this book; what you liked, what you didnt like, and what we can do better next time. You can send us your comments, either by returning the replay card in the book, or by e mail to eaglesbookfeedback@hotmail.com. Please be sure to mention the book title in your message
E-Mail Support
If you wish to directly query a problem in the book with an expert who knows the book in details then e mail eaglessbook@hotmail.com, eaglessiddhu@hotmail.com, with the title of the book and the number which is you e-name of the book printed in you book in the subject field of the e mail. The e name of the book can be found like this : QWERTY 12345 some thing like this
10
The choice between C# and VB.NET is largely one of subjective preference. Some people like C#'s terse syntax, others like VB.NET's natural language, case-insensitive approach. Both have access to the same framework libraries. Both will perform largely equivalently (with a few small differences which are unlikely to affect most people, assuming VB.NET is used with Option Strict on). Learning the .NET framework itself is a much bigger issue than learning either of the languages, and it's perfectly possible to become fluent in both - so don't worry too much about which to plump for There are, however, a few actual differences which may affect your decision
11
C# XML documentation generated from source code comments. (This is coming in VB.NET with Whidbey (the code name for the next version of Visual Studio and .NET), and there are tools which will do it with existing VB.NET code already.) Operator overloading again, coming to VB.NET in Whidbey.
VB.NET Support for optional parameters very handy for some COM interoperability.
Support for late binding with Option Strict off - type safety at compile time goes out of the window, but legacy libraries which don't have strongly typed interfaces become easier to use. Support for named indexers.
Language support for unsigned types (you can use them from VB.NET, but they aren't in the language itself). Again, support for these is coming to VB.NET in Whidbey. The using statement, which makes unmanaged resource disposal simple.
Various legacy VB functions (provided in the Microsoft.VisualBasic namespace, and can be used by other languages with a reference to the Microsoft.VisualBasic.dll). Many of these can be harmful to performance if used unwisely, however, and many people believe they should be avoided for the most part.
12
Explicit interface implementation, where an interface which is already implemented in a base class can be re-implemented separately in a derived class. Arguably this makes the class harder to understand, in the same way that member hiding normally does. Unsafe code. This allows pointer arithmetic etc, and can improve performance in some situations. However, it is not to be used lightly, as a lot of the normal safety of C# is lost (as the name implies). Note that unsafe code is still managed code, i.e., it is compiled to IL, JITted, and run within the CLR
The with construct: it's a matter of debate as to whether this is an advantage or not, but it's certainly a difference.
Simpler (in expression - perhaps more complicated in understanding) event handling, where a method can declare that it handles an event, rather than the handler having to be set up in code.
The ability to implement interfaces with methods of different names. (Arguably this makes it harder to
find the implementation of an interface, however.)
The VB.NET parts of Visual Studio .NET compiles your code in the background. While this is considered as an advantage for small projects, people creating very large projects have found that the IDE slows down considerably as the project gets larger.
13
Programming Difference between C# & VB.NET Keyword Differences Programming Difference Operators Differences Data types Differences
14
15
Keyword Differences
VB.NET
C#
Private, Public, declarations (keywords Friend, include user-defined types Protected, and built-in types) Static1, Shared, Dim const new void
Function/method does not Sub return a value Overload a function or method (Visual Basic: overload a procedure or method) Overloads
Refer to the current object Me Make a nonvirtual call to MyClass a virtual method of the current object Retrieve character from a GetChar string Function
this n/a
[]
16
Declare a compound data Structure struct, class, interface type (Visual Basic: <members> End Structure) Structure Initialize an object (constructors) Terminate an object directly Sub New() Constructors, or system default type constructors n/a
n/a
Method called by the Finalize system just before garbage collection reclaims an object7
destructor
Dim x As Long // initialize to a value: =5 int x = 123; Dim c As New _ // or use default // constructor: Car(FuelTypeE int x = new int(); num.Gas) AddressOf (For delegate class members, this operator returns a reference to a function in the form of a delegate instance) volatile
17
Force explicit declaration Option Explicit n/a. (All variables must be of variables declared prior to use) Test for an object variable obj = Nothing that does not refer to an object Value of an object variable that does not refer to an object Test for a database null expression Test whether a Variant variable has been initialized Nothing obj == null
null
IsDbNull
n/a
n/a
n/a
Define a default property Default Refer to a base class Declare an interface MyBase Interface
18
Specify that a class can only be inherited. An instance of the class cannot be created. Specify that a class cannot be inherited Declare an enumerated type
MustInherit
abstract
NotInheritable
sealed
Enum enum <members> End Enum const (Applied to a field declaration) class C1 : C2
Declare a class constant Const Derive a class from a base Inherits C2 class Override a method Overrides
override abstract
Declare a method that MustOverride must be implemented in a deriving class Declare a method that can't be overridden
Declare a virtual method, Overridable property (Visual Basic), or property accessor (C#, C++)
19
Hide a base class member Shadowing in a derived class Declare a typesafe reference to a class method Delegate
n/a delegate
Specify that a variable WithEvents can contain an object whose events you wish to handle
Specify the events for Handles (Event n/a which an event procedure procedures can will be called still be associated with a WithEvents variable by naming pattern.) With objExpr Evaluate an object expression once, in order <.member> <.member> to access multiple End With members Structured exception handling n/a
Try <attempt> try, catch, finally, throw Catch <handle errors> Finally <always execute> End Try Select Case ..., switch, case, default, goto, Case, Case Else, break End Select
Decision structure (if ... If ... Then, if, else then) ElseIf ... Then, Else, End If
20
While, Do do, while, continue [While, Until] ..., Loop [While, Until] For ..., [Exit for, foreach For], Next For Each ..., [Exit For,] Next Dim a() As Long int[] x = new int[5];
Dim a() As int[] x = new int[5] { Long = {3, 4, 5} 1, 2, 3, 4, 5}; Redim n/a public
Visible outside the project Public or assembly Invisible outside the assembly (C#/Visual Basic) or within the package (Visual J#, JScript) Visible only within the project (for nested classes, within the enclosing class) Accessible outside class and project or module Friend
internal
Private
private
Public
public
21
Accessible outside the class, but within the project Only accessible within class or module
Friend
internal
Private
private protected
Only accessible to current Protected and derived classes Preserve procedure's local Static variables Shared by all instances of Shared a class Comment code ' Rem
n/a
static
Case-sensitive? Call Windows API Declare and raise an event Threading primitives Go to
No
Declare <API> use Platform Invoke Event, RaiseEvent SyncLock Goto event
lock goto
22
Programming Difference
Purpose Declaring Variables Comments C# int x; int x = 10; VB.NET Dim x As Integer Public x As Integer = 10 ' comment x = 1 ' comment Rem comment nVal = 7 If nCnt <= nMax Then ' Same as nTotal = ' nTotal + nCnt. nTotal += nCnt ' Same as nCnt = nCnt + 1. nCnt += 1 Else nTotal += nCnt nCnt -= 1 End If Select Case n Case 0 MessageBox.Show ("Zero") ' Visual Basic .NET exits ' the Select at ' the end of a Case. Case 1 MessageBox.Show ("One") Case 2 MessageBox.Show ("Two") Case Else MessageBox.Show ("Default") End Select
23
// comment //Siddhu /* multiline comment Siddhu*/ Assignment nVal = 7; Statements Conditional if (nCnt <= nMax) Statements { nTotal += nCnt; nCnt++; } else { nTotal +=nCnt; nCnt--; } Selection switch(n) Statements { case 0: Console.WriteLine(" Zero"); break; case 1: Console.WriteLine(" One"); break; case 2: Console.WriteLine(" Two");
break; default: Console.WriteLine(" ?"); break; } for (int i = 1; i <= 10; i++) Console.WriteLine( "The number is {0}", i); foreach(prop current in obj) { current=42; } public class BaseCls { // The element to be hidden public int Z = 100; public void Test() { System.Console.Writ eLine( "Test in BaseCls"); } }
FOR Loops
For n = 1 To 10 MessageBox.Show("The number is " & n) Next For Each prop In obj prop = 42 Next prop
Public Class BaseCls ' The element to be shadowed Public Z As Integer = 100 public Sub Test() System.Console.WriteLine( _ "Test in BaseCls") End Sub End Class
Public Class DervCls Inherits BaseCls ' The shadowing element. Public Shadows Z As String = "*" public class DervCls : public Shadows Sub Test() BaseCls { System.Console.WriteLine( _ // The hiding "Test in DervCls") element End Sub
All Rights Reserved To EaglesGroup
24
public new string Z = "*"; public new void Test() { System.Console.Writ eLine( "Test in DervCls"); } } public class UseClasses { // DervCls widens to BaseCls BaseCls BObj = new DervCls(); // Access through derived //class DervCls DObj = new DervCls(); public void ShowZ() { System.Console.Writ eLine( "Accessed through "+ "base class: {0}", BObj.Z); System.Console.Writ eLine( "Accessed through"
End Class Public Class UseClasses ' DervCls widens to BaseCls. Dim BObj As BaseCls = New DervCls() ' Access through derived ' class. Dim DObj As DervCls = New DervCls() Public Sub ShowZ() System.Console.WriteLine( _ "Accessed through base "&_ "class: " & BObj.Z) System.Console.WriteLine(_ "Accessed through derived "&_ "class: " & DObj.Z) BObj.Test() DObj.Test() End Sub End Class
25
+ " derived class:{0}", DObj.Z); BObj.Test(); DObj.Test(); } } while (n < 100) n++;
WHILE Loops
' Test at start of loop While n < 100 . ' Same as n = n + 1. n += 1 End While ' /* DENOTE that ' The argument Y is there is 'passed by value. no way to pass Public Sub ABC( _ reference ByVal y As Long) types (objects) strictly 'If Siddhu changes y, the by value. You can changes do not affect x. choose End Sub to either pass the reference Siddhu(x) ' Call the (essentially a procedure. pointer), or ' You can force parameters to a reference to the ' be passed by value, reference ' regardless of how (a pointer to a ' they are declared, pointer).*/ ' by enclosing // The method: ' the parameters in void siddhu(int x) extra parentheses. { Siddhu((x)) ... } // Calling the method: siddhu(i); /* DENOTE that Public Sub Siddhu(ByRef y there is no As Long) way to pass reference ' The parameter y is declared
All Rights Reserved To EaglesGroup
26
types (objects) strictly by value. You can choose to either pass the reference (essentially a pointer), or a reference to the reference (a pointer to a pointer).*/ // Note also that unsafe C# //methods can take pointers //just like C++ methods. For //details, see unsafe. // The method: void siddhu(ref int x) { ... } // Calling the method: siddhu(ref i); // try-catch-finally try { if (x == 0) throw new System.Exception( "x equals zero"); else throw new System.Exception( "x does not equal zero");
'by referece: ' If ABC changes y, the changes are ' made to the value of x. End Sub Siddhu(x) ' Call the procedure.
Try If x = 0 Then Throw New Exception( _ "x equals zero") Else Throw New Exception( _ "x does not equal zero") End If Catch err As System.Exception MessageBox.Show( _ "Error: " &
27
} catch (System.Exception err) { System.Console.Writ eLine( err.Message); } finally { System.Console.Writ eLine( "executing finally block"); } o = null;
Set an Object Reference to Nothing Initializing System.DateTime dt Value = Types new System.DateTime( 2001, 4, 12, 22, 16, 49, 844);
o = Nothing
28
Operators Differences
Purpose Integer division Modulus (division returning only the remainder) Exponentiation Integer division Assignment Concatenate Modulus Bitwise-AND Bitwise-exclusiveOR Bitwise-inclusiveOR Equal Not equal Compare two object reference variables Compare object reference type Concatenate strings Shortcircuited Boolean AND Shortcircuited Boolean OR Scope resolution Array element Type cast Postfix increment Postfix decrement C# / % n/a /= += %= &= ^= |= == != == x is Class1 + && || . and base [] (type) ++ -VB.NET \ Mod ^ \= &= NEW n/a n/a n/a n/a = <> Is TypeOf x Is Class1 & AndAlso OrElse . () Cint, CDbl, ..., CType n/a n/a
29
Indirection Address of Logical-NOT One's complement Prefix increment Prefix decrement Size of type Bitwise-AND Bitwise-exclusiveOR Bitwise-inclusiveOR Logical-AND Logical-OR Conditional Pointer to member
* (unsafe mode only) & (unsafe mode only; also see fixed) ! ~ ++ -Sizeof & ^ | && || ?: . (Unsafe mode only)
n/a AddressOf Not Not n/a n/a n/a And Xor Or And Or If Function () n/a
30
31
Chapter 01
32
Now lets see some of the new productivity features of Visual C# 2005
AutoCorrect
33
Exception assistant
Snap lines
Use this feature to handle runtime exceptions in Visual C# 2005. The Exception assistant provides standard information about the runtime exception and suggests the methods that can be used to handle them. It may at most time provide the location of the line of code that has caused the runtime exception to occur. This is new feature that has been added to Windows Forms in Visual C# 2005. With snap lines features, you can easily align controls according to the alignment of other controls in Windows forms. Visual C# 2005 provides support for inserting XML based comments in a source code file. You can easily extract, parse, and convert these XML code comments into documentation.
Generics
34
Partial Classes
With the support for unsigned Integer Types in Visual C# 2005, you can create and use .NET Framework unsigned types and also perform mathematical operations on the values of unsigned Integer Type. Visual C# 2005 not, only supports unsigned Integers Types fully, but also allows conversions between them. Use partial class features to split a single class into multiple files. This feature of the Visual C#2005 is most useful for code generators, such as Visual Studio that generate code in a file instead of as user written code. This feature helps handle asynchronous processing and ensure that the callback procedure runs in the correct thread. Background Worker Object is a component in Visual C# 2005 that you can easily drag from the Toolbox and drop it on the design surface to run slow running processes as background tasks.
1.3 The .NET Framework 2.0 and the Common Language Runtime
Visual C# 2005 is a component of revolution in Windows the .NET Framework. This framework provides the new support for softwares development and operating system support in Windows, and its more extensive than anything we have seen in Windows before. The .NET Framework wraps the operating system with its own code, and you Visual C# 2005 programmers actually deal with .NET code instead of dealing with the operating system itself. And it is specially designed to male working with the internet easy. At the base of the .NET Framework is the Common language Runtime (CLR). The CLR is the module, that is actually runs your .NET Application. When you create a Visual C# 2005 application, what really happens is that you r code is complied into the CLRs Intermediate Language (named MSIL, or IL for short), much like byte codes in Java. When you run the application, the IL code is translated into binary code that your code into something that your machines hardware, (or other software), can deal with directly. In this way, Microsoft may create a CLR for operating systems other than Windows, and your Visual C# 2005 applications, compiled into IL, will run on other platforms also.
35
The .NET Framework class library is the second major part of the .NET Framework. The class library holds an immense amount of prewritten code that all the applications you create with Visual Basic, Visual C++, C #, and other Visual Studio languages are build on. The class library gives you program the support it needs for example, your program may create several forms, and as there is a class forms from scratch. All your code has to do is declare a new form, and the CLR compilers can get the actual code that supports forms from the .NET Framework class library. In this way, your programs can be very small compared to the earlier Windows applications because you can rely on the millions of lines of code already written in the class library not everything has to be in your applications executable (EXE) file.
All this assumes that you are working on a machine that has the .NET Framework, and therefore the CLR and the .NET Framework class library, installed. The code for elements we use in a Visual C# 2005 application forms, buttons, menu, and all the rest comes from the class library. And other programming, even in the same application. Also, distributing applications is easier, because all the support you need is already on the machine you installed you application to.
As mentioned, the .NET Framework organizes its classes into namespaces. For example, the .NET Framework includes the namespaces Microsoft.VisualBasic, Microsoft.Jscript, Microsoft.CSharp, and Micorsoft.Win32. In fact, these namespaces contain relatively few classes; the real way well interact with the .NET Framework class library in this book is through the System namespace.
1.4 So what Kind of Applications we can write Using the .NET Framework?
Writing an application using the .NET Framework means writing code (using any of the languages that support the framework) using the .NET code library. In this book well be using Visual Studio 2003 and 2005 for our development, which is powerful Integrated development environment that supports C# as well as managed and unmanaged C++, Visual Basic .NET, and some other languages. The advantages of this environment are the ease with which .NET features may be integrated into our code. The code that we will create will be entirely C#, but will use the .NET Framework throughout, and well make use of the additional tools in VS where necessary. In order for C# code to execute it must be converted into a language that the target operating system understands, know as native code. This conversion is called compiling code, an act that is performed by a compiler. Under the .NET Framework, however, this is a two stage process. 36
All Rights Reserved To EaglesGroup
1.6 Assemblies
When we compile an application, the MSIL code created is stored in an assembly. Assemblies include both executable application files that we can run directly form Windows without the need for any other programs (these have an .exe file extension), and libraries for use by other applications (which have a .dll extension). As well as containing MSIL, assemblies also contain Meta information that information about the information contained in the assembly, also known as metadata and optional resources additional data used by the MSIL, such as sound files and picture. This Meta information allows assemblies to be fully self descriptive. We need no other information in order to use an assembly, meaning that we avoid situations such as failing to add required data to the system registry and so on, which was often a problem when developing using other platforms.
37
You combine assemblies to form .NET application and, although we wont deal with them directly very often, we need to get the terminology down. An assembly holds the Intermediate Language (IL) modules for your application. When you create an Application in Visual C# 2005 and run it, Visual C# 2005 creates one or more assemblies, which are run by the CLR. That is, assemblies are how applications are interacting with the .NET Framework, instead of the EXE or DLL files of Visual C # 2005. Heres what in the .NET Assembly first is the manifest, which is similar to a table of contents, giving the name and version of the assembly. The manifest also lists the other assemblies needed to support this one, and explains how to handle security issues. The actual meat of the assembly is made up of modules, which are internal files of IL code, ready to run. Thats how Visual C# 2005 stores the IL is create. In module inside assemblies. Each module, in turn, contains types the classes and interfaces that you e code has denied, and that the assembly has to know about to let the various modules interact with each other. Although a lot happens behind the scenes with CLR and the .NET Framework takes care of most of the issues, getting most out of .NET and understanding how .NET works requires a through understanding of assemblies. This means that deploying applications is often as simple as copying the files into a directory on a remote computer. Since no additional information is required on the target systems, we can just run an executable file form this directory and assuming the .NET CLR is installed away we go. Of course, we wont necessarily want to include everything required to run an application in one place. We might write some code that performs tasks required by multiple applications. In situations like this, it is often useful to place this reusable code in a place accessible to all applications. In the .NET Framework, this is the Global Assembly Cache (GAC). Placing in the cache is simple we just place the assembly containing the code in the directory this cache but we will be looking more about the Assemblies in the Detailed Chapter named .NET Assemblies.
38
Name System
System. Collections
System.Data
Description It includes essential classes and base classes that define commonly used data types, events and event handlers, interfaces, attributes, exceptions, and so on. This namespace includes interfaces and classes that define various collections of objects, including such collections as lists, queues, hash tables, and dictionaries. It includes classes that make up ADO.NET; ADO.NET Lets you build data handling components that manage data from multiple distributed data sources. It includes classes that support the OLE DB.NET data provider. This namespace includes classes that support the SQL Server .NET data provider. It includes classes that support namespace in the .NET Framework data provider for ODBC This namespaces includes classes that support namespaces in the.NET Framework data provide for ODBC. It includes classes that allow you to debug your application and to step through your code. It also includes code to start system processes, read and write to event logs, and monitor system performance. It is used to provide access to the GDI+ graphical packages that give you access to drawing methods. It includes classes that support advanced two dimensional and vector graphics. It includes classes that support advances GDI+ imaging. It includes classes that allow you to customize and perform printing. It includes classes that support advanced GDI+ typography operations. The classes in this namespace allows user to create and use collections of fonts.
39
System. Globalization
It includes classes that specify culture related informatics, including the languages, the country / region, calendars, the format patterns for dates, currency and numbers, the sort order for string, and so on. This namespace includes types that support synchronous and asynchronous reading from and writing to both data streams and files. This namespaces provides an interface to many protocols used on the Internet. This namespaces includes classes that support the Windows Sockets interface. If you have worked with the Winsock, API, you should be able to develop applications using the Socket class. It includes classes and interfaces that return information about types, methods and fields, and also have the ability to dynamically create and invoke types. It provides classes and interfaces that allow developers to create and configure distuburted applications. Well use the classes in the namespace heavily in .NET Assemblies chapter. It includes classes that support the structure of the Common Language Runtime (CLR) security system. It contains classes that can be used for serializing and deserialization objects. Serialization is the process of converting an object or a graph of objects into a liner sequencing of bytes for either storage of transmission to another location. Deserialization is the process of taking in stored information and recreating objects form it. It includes classes and interfaces that enable multithread programming.
System.IO
System.net System.net.Sockets
System. Reflection
System.Runtime.Remoting
System.Security System.Runtime.Serialization
System.Threading
40
System. Web
System.Web.Security System.Web.Services
System.Windows.Forms
System.Xml
It includes classes and interfaces that supports browser/server communication. This namespace includes such as that manages HTTP output to the client; and the HTTPServerUtility class that provides access to server side utilities and processes. You can also use cookies, support file transfer, etc, with these classes. This namespace includes classes that are used to implement ASP.NET security in Web Server applications. This namespaces includes classes that let you to build and use Web services, programmable entities on the Web Server that the code can communicate with using standard Internet protocols. It includes classes for creating Windowsbased forms that make use of the user interface controls and other features available in the Windows operating system. It includes classes that support processing of XML
These, along with the many other System classes, from the foundation on which Visual C# 2005 applications rest. Its time now to start taking a look at how to build these applications. DENOTE: in todays scenario, organizations are faced with the growing demand for typical applications which requires user friendly interface that support 2D and 3D graphics. These applications should be based on process. Oriented architecture and address the problems of digital identities and support checking for phishing scams and communication with applications bases on other platforms using Service Oriented Architecture (SOA). To overcome all the problems of complex application requirements. Microsoft has introduced .NET Framework 3.0, which comprises of four different foundations with support of .NET 2.0. Try checking out these new foundations discussed at Chapter named called Overview of .NET Framework 3.0 Architecture
41
42
DENOTE: C and C++ programmers take note: A destructor is not necessarily called when an object goes out of scope but when it is garbagecollected (which may happen much later). This is known as nondeterministic finalization. Java also implements garbage collection, but in a slightly different way. In Java, you must let the system to decide when to collect orphaned memory. This requirements leads to problems, such as slowing down of the system and then bogging down a time- critical section of code that is begin executed. In addition, because Java waits until the garbage collection is absolutely necessary, gathering up all the memory being freed can take some time, resulting in a wait for allocations. C# gets around these problems by allowing programmers to decide whether they want to force the issue of collecting the garbage or decide on a good time to do so .C# works better with garbage collection because that process was well thought out to begin with. C# implements the idea of generations in the code, which allow the classes to segment themselves so that garbage collection is done more easily. The memory and resources management has become very easy with the .NET Framework. Garbage collection is one such feature of the .NET technology that managess and allocates the resources. In all object oriented languages including C#, every type need to be allocated some memory space and requires some resources like screen, buffer, and memory network connections and so on. To use a resources, you first need to allocate memory so that the type thats need resources can be represented. A resource can be accessed by using the following steps:
Allocate memory for the type that represents the resource Initialize the instance members of that type to use the resource become usable Access the instance members of that type to use the resources Clean up and stake of resources And finally free the memory
With the Garbage Collector, the user does not have to worry about tracking how much memory is in use and when can it be free. Since memory id finite, some sort of collection is required to free the memory. The optimizing engine of the Garbage Collector determines when a collection should be preformed. It checks for the objects that are not being used by the application when a collection should be performed. It checks for the objects that are not being used by the application and then frees that part of the memory for being allocated to some other objects. The Microsoft .NET CLR (Common Language Runtime) allocates resources from managed heap, so that the user does not need to free the objects. It is done automatically when the application does not need the objects anymore. The Garbage Collector can know which objects are not in use by Metadata. Metadata describes the data type being used. With Metadata the CLR knows the layout of the objects in the memory which helps the Garbage Collector performs collection, it checks the object in managed heap that are no longer being used by the
43
application and then reallocates that portion of memory to some other object. Most of the work done by the garbage collection mechanism is done through the System.GC object. DENOTE: The garbage collector destroys objects on the stack sometime after the stack frame they are declared within ends. Typically a stack frame is defined by a function. Thus, if you declare a local variable within a function, the object will be marked for garbage collection after the function ends. .NET Frameworks garbage collection implicitly keeps track of the lifetime of the objects that an application creates, but fails when it comes to the unmanaged resource (example a file, a window or a network connection) that objects encapsulate. In case of unmanaged resources encapsulated by objects, Object.Finalize method is used. This object contains a large number of methods that allow you to do things, such as force immediate garbage collection throughout the system (GC.Collect). You can suppress the call to Finalize for a given object (probably because it was called immediately) in the GC.SuppressFinalize method. Finally, you can call ReRegisterForFinalize method, which allows you to undo the result of SuppressFinalize for the given object. DENOTE: Unlike in Java, the call to Finalize ( ) in C# is actually guaranteed to happenunless the programmer explicitly permits it to be skipped. The garbage collector maintains a list of objects that have a destructor. This list is updated every time such an object is created or destroyed. When an object on this list is first collected, it is placed on a queue with other objects waiting to be destroyed. After the destructor executes, the garbage collector then collects the object and updates the queue, as well as its list of destructible objects.
44
Description If can be a basic Windows form or a code file for storing functions, a user control, a data form, a custom control, an inherited form, a Web custom control, an inherited user control, a Windows service, a custom setup file, an image file for creating a custom icon, or an AssemblyInfo file used to store assembly information such as version and assembly name. It is an XML schema provided to crate typed datasets. It is an XML document file It is an HTML document It is a text file. It is an XSLT stylesheet file, to transform XML document and XML schemas. It is a cascading style sheet file. It is a Crystal Report It is a bitmap file. It is a JScript file(Microsofts version of JavaScript) It is Windows scripting file. It is a Web form It is an active server pages It is a Web service class It is a dynamic discovery project; .vsdisco provides a means to enumerate all Web services and all schemas in a Web project.
All Rights Reserved To EaglesGroup
45
It is a Web configuration file; .Web configures Web settings for a Web project It is a global application class, used to handle global ASP.NET application level events. It is a resource file used to store resource information These are application configuration files and contain settings specific to an application. This file contains configuration settings that the common language runtime reads (such as
assembly binding policy, remoting objects, and so on), and setting that the
46
Above the properties window in that case, we have created our Visual C# project called Eagles WindowsApplication and you can see the project in the Solution explorer but note that Visual C# has also placed that project inside a solution with the same name, Eagles WindowsApplication. If we were to add new projects to the current solution which you can do with the New Project dialog box), those new properties would appear in the Solution Explorer as part of the current solution. This is a change from the previous version, where each project, such as the files form a form, items. So the terminology here is that solutions contain projects, and these in turn the projects contain items.
47
interact with the debugger in you program when it runs, and this not only makes the corresponding assembly larger, but also slower. In the release version of your program, the program doesnt have all that added data, and can run as a stand alone program, without needing to be launched form Visual C# although it still needs the .NET Framework, of course. When you create a new solution, Visual C# creates it in Debug mode, meaning that you launch it from the Debug menu as we have been doing. However, you can switch to release mode in several ways like many things in Visual C# 2005, theres more than one way to do it. Select the Configuration Manger option in the Build menu. Then select Release in the Active Solution Configuration list box and click Close.
Select the solution you want to set the mode for by clicking it in the Solution Explorer, and find its Active Configuration property in the Properties Window.
48
When you click the right handed column in the Properties window next to this property, a drop down list box will appear; select Release in that list box. Select the Solution you want to set the mode for by clicking it in the Solution Explorer, and select the Properties option in the Project menu, opening the solutions Property pages. Select the Configuration Properties node in the box at the left, and the Configuration item in that node.
Then select Release from the drop down list box in the Configuration column of the table that appears, and then click Close. Probably, the easiest way to set the Solution mode to release or Debug is simple to use the drop down list box that appears in the Visual C#.NET standard toolbar, at the top of the IDE. When you create a new solution or project, this list box displays the word Debug and all you need to do to switch to Release mode is to select Release instead. When you have set mode for a solution to Release, you build it using the Build menus Build option (the build option causes Visual C# to compile only the items it thinks have been newly changed. To force it to compile all items in the solution, choose the Rebuild All option, instead of Build). This builds the solution in a way so that others can use it, and you can deploy your program this way usually with the help of deployment project that you build in Visual C#, as well do later in the book. Now that we have the background we need on Visual C# 2005 solutions and projects, we can move ahead into the following chapters, where well assume this knowledge and put it to work. Well also take for granted that you know your way around Visual C# 2005 itself, so in this introductory chapter, well also take at the Visual C# Integrated Development Environment the Visual C# IDE.
49
There are so many independent windows in the IDE thats likely that you might misplace them if you try to rearrange them inadvertently. The IDE windows are docking windows, which means that you can use the mouse to move windows around as you like; when the windows are near an edge, theyll dock adhere to that edge, so you can reconfigure the IDE windows are you like. If you want the IDE windows inadvertently, dont panic; just use the mouse to move them back. Also note that the windows in the IDE come with a Close button (X) button at the upper left window. Dont click these buttons when we dont mean to, otherwise a window we wanted disappears. Its easy to panic: The toolbox is gone! Well have to reinstall everything, oh my god what I did to my self? In fact, in such a situation, all you have to do is to find that window in the View menu again (such as View | Toolbox or press Ctrl + Alt + X you will be having the toolbox in the Visual Studio.NET to make it reappear.
50
DENOTE: That some windows are hidden in the View | Other Windows menu item, which opens a submenu of additional windows there are simple too many windows to fit them all into one menu without needing to use a submenu. Theres so much packed into the IDE that Microsoft has started to make windows share space, and you can keep them separate using tabs such as those you can see above the form at the center of picture above. If you click the Form1.cs[Design] tab, you see the form itself as itll appear when the program runs; if you click the Form1.cs, tab youll the forms code and if you click the Start Page tab, youll see the Start page, which lets you select from among the recent solutions to open. Also not that at the lower right Properties window and Dynamic Help windows a Visual C# 2005 feature are sharing the same space, and you can select between them using tabs. The IDE is a very crowded place, and in an effort to uncluttered the cluttered IDE a little, Visual C# 2005 adds a new button in doable IDE windows a little Thumb tack button at the upper right as you see in the various windows in the above picture, next to the Close button (X). This is the auto hide feature, which lets you reduce a window to tab connected to the edge its docked on.
As we see in the above picture, the Solution Explorer which lets you explore data sources on servers window is hidden and has become a tab in the IDE. If we click that tab, the full Solution Explorer window will glide open, covering most of the Toolbox. You can auto hide most windows like this; for example, if we were to click the Thumb tack button in the Toolbox, it would close and become a tab under the Server Explorer tab in the IDE. To restore a window to stay open status, just click the Thumb tack again. And, of course, you can customize the IDE as well. For example, to customize IDE options, such as the fonts and color used to display code, select the Tools | options option and use the various items in the Environment node. As shown in the below picture. To customize menus and toolbars, such as specifying the toolbars to display, or what toolbars, use to Tools | Customize option.
51
DENOTE: The Visual Studio.NET 2005 works only with the .NET Framework 2.0. IF you need to develop applications for the .NET Framework Version 1.1 you need to Installed which means you need to have Visual Studio 2003 on your machine. Visual C# 2.0 language version for creating a Visual C# 2005 0 based application. But in case you have a project or an application which has been created using the Visual Studio 2003 .NET Environment. No problem here the Visual Studio 2005 will over come the problem for you by automatically when you try to open the Project version of 2003 in 2005 the Visual Studio 2005 Will automatically open the Upgrade wizard to you so you can use the Wizard for the upgrade the 2003 to 2005. For more familiar please follow the following steps:
52
Step1:
Click the File | Open | Project/Solution and select the project version of Visual C# 2003 and in the select the .sln file
Step2:
Select the file with the extension of .sln and then click OK button.
53
Step3:
You should probably see the Visual Studio Conversion Wizard which will automatically convert the Visual 2003 Version of project to Visual C# 2005 Project.
54
Step4:
The Wizard will ask you to create a back up or not you can either select on you choice, if click ye, create a back up you will can see the back up files in the exact folder where you the old version project you choose. There will be a folder called Backup so you still have a back up of the old version Visual C# 2003. But if you choose the Wizard will not create the Backup in the folder it will go the next procedure
55
Step5:
Following by the step 4 after you click the Next button the wizard should show the complete summary of the conversion of the file which you selected to convert. The Visual C# 2003 Version of project which you have selected has almost converted
56
Step6:
Now the Visual Studio Conversion Wizard will ask you either you want to see the logs of the conversion or not by providing the check box, if you click the check box the wizard will show you the logs which has been created while the Visual Studio Conversion Wizard running. If you didnt click the check box and press the Close button and you r Visual C# 2003 Version project now open in the Visual 2005 IDE.
57
58
59
Because the IDE displays tool tips those small yellow windows with explanatory text that appears when you let the mouse reset over controls such as buttons in a toolbar, its easy to get to know what the buttons in the toolbars do. As mentioned, you can also customize the toolbars with the IDE, selecting which toolbars to display or customizing which buttons to appear in which toolbars with Tools | Customize option, or you can right click a toolbar itself to get a menu of the possible toolbars to display the bottom item in this popup menu is Customize which lets you customize which buttons go where, or you can open the toolbars submenus in the View menu to do the same thing as is often in Visual C#, theres more than one way to do it. Toolbars provide a quick way to select menu items, and although we usually stick to using the menu system, theres no doubt that toolbar buttons can be quicker. For example, to save the file you are currently working on, you only need to click the Diskette button in the Standard toolbar as you seen in the above picture.
60
61
Windows Form Designers Component Designers XML designers You can have noticed or, may already know that Windows forms display a grid of dots around the form. To set the grid spacing, whether or not the controls should snap to the grid thats the position their corners on grid points, you can use the Tools | Options, options to open the Options dialog box, and select the Windows Form Designer node, displaying the possible options for you to set.
62
You can use the tabs at the top center of the IDE to switch between Graphical Designer, such as tabs Form1.cs[Design] that will display a Graphical Designer, and the Form1.cs tab that display the corresponding Code designer. You can also switch between Graphical and Code Designer using the Designer and Code options in the View menu, or you can use the top two buttons at left in the Solution Explorer. Note the two drop down list boxes at the top of the Code designer the one on the left lets you select what objects code you are working with, and the one on the right lets, select the part of the code that you want to work on, letting you select between the declarations are, functions, and method all of which well see on the Chapter 2,. The declarations area, which you select by selecting the Declarations item in the right handed list box, is where you can put declaration of objects. When you double click a control in a Graphical designer, its Code designer will open and Visual C# creates an event handler for its default such as Click event for button which is a procedure that is called when the event occurs. To add code to a different event handler, select the object you want to work with in the left handed drop down list box in the Code designer, and the event you want to add code to in the right hand drop down list box; Visual C# will create an event handler for the event. Which you are see in the below picture
All Rights Reserved To EaglesGroup
63
Also note the + and -boxes in the Code designers text area, at the left. Those are new in Visual C# 2005, and were introduced Visual C# 2005 now writes a great deal of code for your forms and components automatically. You can use the + and buttons to show or hide that code.
64
1.21 IntelliSence
One of the best and useful features of Visual C# 2005 Code Designers is Microsoft IntelliSence. IntelliSence is whats responsible for those boxes that open as you start to type or write you code, listing all the possible options and even completing youre typing for you. IntelliSence is one of the first things you encounter when you use Visual C# 2005, and you can see an example of this in the following screenshot. Where we are looking at all the members of a text box object. DENOTE: If you enter some code that Visual C# 2005 consider as syntax error, it will underline the error with a wavy red line. You can rest the mouse over the underlined text to see a tool tip explaining what Visual C# 2005 thinks is wrong. Thats not part of the IntelliSence package, although it also useful.
IntelliSence is made up of number of options, including the following feature: List Members It lists the members of an object. Parameter Info It lists the argument of procedure calls. Quick Info It display information in tool tips as the mouse resets on element in your code. Complete Word It completes types word. Auto Brace Matching It adds parentheses or braces as needs.
65
Theres also a Visual C# - specific IntelliSence, which offers tips that displays the syntax of the statement you are typing. Thats grate if you know what statement you want to use but dont recall its exact syntax, because its syntax is automatically displayed. IntelliSence is particularly useful when you cant remember what arguments a built in Visual C# procedure accepts, because itll display those arguments as you type in the call to the procedures. IntelliSence is something you quickly get used, to, and come to rely on. However, you can turn various parts of IntelliSence off id you want just select the Tools | Options option, and then select the Text Editor node, then the C# item and finally the General item. Youll see a number of IntelliSence options you can turn on and off with the Check boxes.
DENOTE: IntelliSence has improved in the new Version of .NET such as Visual Studio .NET 2003, IntelliSence provided you the list of possible options from the very first item in the list. Now it remember you preferred to choice once you make a selection and start from there only the next time it appears.
66
IntelliSence is useful because it tells you what syntax is correct automatically, or lists all the members of an object that are available. Another useful tool thats often overlooked by Visual C# programmer is the Object browser. This toll lets you look at all the members of an object at once, which is invaluable to pry into the heart of objects you have added to your code. The Object browser helps open up any mysterious object that Visual C# has added to your code so you can see whats going on inside. To open the Object Browse, Select View | Object Browser can see the above picture. The Object Browser shows all the objects in your program and gives you access to whats going on in all of them. For example, in the above picture, we are looking at a Windows form, Form1 and all its internal members and the parameters they are made visible. To close the Objects browser, just click the Close button at its upper right.
67
With the help of the advanced toolbox the programmer or the user can choose what controls they want to have it in the proper manner so they either no need to confuse.
The tabs available as you might guess depend on the types of project you are working on and even the types of designer you are working with. The All Windows Forms,
Common Controls, Container, Menu & Toolbars, Data, Components, Printing, Dialogs, Crystal Reports. Appear when you are working with the Windows Form
Designer only. However when you are in the Code Designer you can use the Toolbox as a clipboard to copy and past the codes.
68
When you working on a Web Application, you will able to see the Standard, Data,
Validation, Navigation, Login, WebParts, HTML, General.
69
The Data tab displays tools for creating datasets and making data connection the All Windows forms tab displays tools for adding controls to Windows Forms the Standard tab display tools for adding server control and so on. The General tab is empty by default, and is a place to store general controls, and fragments of code in. Even you can add more tabs to the Toolbox by right clicking the Toolbox and selecting the Add Tab option. In fact, there are many controls that even when you click a tab in the Toolbox, youll still mostly likely get a list that you have to scroll to see everything thats available.
70
This tool displays a hierarchy with the solution at the top of the hierarchy, the projects one step down in the hierarchy, and the items in each projects as the next step down. You can set the properties of various items in a project by selecting them in the Solution Explorer then setting their properties in the Properties Windows. And you can set properties of solution and projects by right clicking them, and selecting the Properties option in the menu that appears, or you can select an item and click the Properties button which is the right most buttons at the top of the Solution Explorer. There is an option called Show All Files in the Solution Explorer. If you click the option it will show all the Files in the Project.
71
If you are working on an object that has both a user interface and code, you can switch between the Graphical and Code Designer by using the buttons appears at the top left in the Solution Explorer when that object has been selected. You can right click a solution and add a new project to it by selecting the Add | New Project option in the popup menu that appears. And you can specify which of the multiple project to run first the startup project or projects by right- clicking the project and selecting the Set As Startup Object option, or by right clicking the solution and selecting the Set Startup Projects option. Much of what goes in the Visual C# 2005 IDE depends on which solution or project is the current one, and you set that by selecting it in the Solution Explorer. For example, you can specify what icon you want to an application to use in Windows if you dont like the plain default one. To do that, you select its project in the Solution Explorer, select Properties option in the Project Menu, open the Application tab, then browse to the .ico file you want and click OK.
72
The Solution Explorer tracks the items in your project to add new items you can use the menu items in the Project menu such as Add Windows form and Add User Control. To add new interface, user control, or class to a project. But we will be seeing more in details in the coming chapters, you can use the Project | Add New option.
73
The Solution Explorer see things in terms of files, as you can see in the following picture. There, the References node holds the currently referenced item such as namespaces in a project, Assembly Info.cs is the file that holds information about the assembly you are creating, and Form1.cs is the file that holds the code for the form under design. However theres another way of looking at Object Oriented Programs in terms of classes and the Class View window does that. The data in AssemblyInfo.cs gives all kinds of information about the assembly, such as its version number. To set the version number of the assembly you are creating. Open the AssemblyInfo.cs and edit the line which is highlight in the Gray color box using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Eagles WindowsApplication")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("EaglesGroup")] [assembly: AssemblyProduct("Eagles WindowsApplication")] [assembly: AssemblyCopyright("Copyright EaglesGroup 2008")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("88cade17-f410-412d-8963-062518acafef")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
74
This View presents solution and projects in terms of the classes they contain, and the members of these classes. Using the Class View Window gives you an easy way of jumping to a member of class that you want to access quickly just find it in the Class View Window and double click it to bring up in a Code designer.
75
The Properties window as shown in the above picture is another old favorite in Visual C#, although now it shares its space with the Dynamic Help Window. You set the properties of various objects in Visual C# to customize them. For example, we have set the Text property of a the Form1 to Eagles Form1 to do that we need to right click the Window Form and look for the Text property and the Type the Eagles Form1 so it will appear in the Form1.cs. To set object properties when you are designing your program in Visual C# - called design time as opposed to runtime you can select that object by clicking a control or form, or project, or a solution and then set the new property values you want in the Properties window. The Properties Window is divided in to two columns of text with the properties on the left, and their settings on the right. The object you are setting properties for appear in the drop down list box at the top of the Properties window, and you can select from all the available objects using that list box. When you select a property, Visual C# will give you an explanation of the property in the panel at the bottom of the Properties Window, as you see in above picture.
76
You can display the properties alphabetically by clicking the second button from the left at the top of the Properties window, or in categories by clicking the left most buttons. To change a propertys setting, you only have to click the right handed column next to the name of the property, and enter the new setting. Often properties can have only a few specific values, in which case Visual C# will display a drop down list box next to the propertys name when you click the right- handed column, and you can select values from the list, Sometimes, Visual C# requires more information, say to create data connection, instead of list box, a button with an ellipsis (..) appears. In that case when you click that button, Visual C# will usually walk you through the steps it needs to get that information. Note also that, as usual with properties and methods in Visual C#, not all properties of a form or control will be available at design time in the Properties window when you are designing your code some will be available only at runtime. In fact, there arent many changes in the Properties window from previous versions of Visual C# something Visual C# programmers might be placed to hear, so if you have used it before, you are all set.
77
Visual C# 2005 looks up all kinds of help topics on the element you have selected automatically, for example, we have selected the Textbox on the Windows Form, and Dynamic Help Window has responded by displaying all kinds of helpful links to information on the buttons. This is more helpful than simply searching the whole system for the word TextBox. Because dynamic help will typically select introductory and overview help topics, not all the hundreds of topic with the word button in their text. If you click a help a help link in the Dynamic Help Window, the corresponding help topics is opened in the central space of the IDE where the designers appear you can switch between designers and help topics using tabs. Some times you may find it too cramped in the IDE to display help topics effectively. You can have Visual C# 2005 display help in an external IDE- Independent window instead. If you wish Select Tools | Options menu bar option and then Help option in the Environment node and the Click OK.
78
79
By using the Server Explorer, which appears in the above picture, which will help to explore the things in the Server, and its great tool to help make distant servers feel less distant, because you can see everything you need in an easy graphical environment. You can do more than just look using the Server Explorer too you can drag and drop whole items onto Windows forms or Web forms the Server Explorer. For example, if you dragged a data table onto a form, Visual C# 2005 would crate the connection and command objects you need to access that table from the code.
80
System.Diagnostics.Debug.Write("Welcome to EaglesGroup!");
81
The Task List window helps create and manage programming tasks. For example, it allows you to enter notes on tasks to be done as Under Tasks. It also allows you to display comments to the lines in your code files where some work needs to be done by you. In fact, you can create your own custom controls that the Task List will track. To so, select Tools | Options then select Task List item in the Environment node and enter the name of your custom comments in the Comment Token area. For example if we entered Siddhu there, then any comments beginning with Siddhu will be tracked in the Task List.
82
83
DENOTE: If the Error List is not displayed on you Visual Studio.NET 2005 then you can access it by selecting View | Error List, or by simply Pressing Ctrl + W, E. There are various columns in the Error List window like Description Filter Line and Column that help you to provide complete information about the errors and warning.
84
There are plenty of other windows available and the Command window is one of them. Selecting View | Other Windows | Command Window opens the Command Window, as you can see the above picture. This window is little like the immediate window in previous version of Visual C#, because you can enter commands like Macros.Samples.AddDirAsSlnFolder.GenerateSlnFolderOnDirStructure, File.AddNewProject, File.AddNewWebPoject here. Visual C# 2005 will display the Add New project. For example if you enter the following Command Macros.Samples.AddDirAsSlnFolder.GenerateSlnFolderOnDirStructure it will ask you to enter Enter a folder path to import the macros as we can see it in the following picture:
85
However, this window is not exactly like the immediate windows, because you cant enter Visual C# code in it and have it executed. There are other windows that well discuss later during debugging program section such as the Call Stack Window, and so on. The Break Points Windows, Watch, and Value display windows, Autos, and Locals macros to execute a series of commands in the Visual Studio Environment. If you want to give macros a try, take a look at the Macros in the Tools menu. Theres more to the IDE that bears its mention macros. You can use macros to execute a serious of commands in the Visual Studio environment. If you want to give a macros a cover here, but now we have gotten the foundation well need in the coming chapters.
86
Summary
In this chapter, we have covered an introduction of Visual C# and the improvements and added new features such as: Visual C# 2005 Introduction Productivity features of Visual C# 2005 Visual C# 2005 Language Improvements .NET 2.0 and CLR Applications Which can Support Using the .NET Framework MSIL and JIT Assemblies The System Namespace Managed Code Garbage Collection File Extension of Visual C# 2003 and Visual C# 2005 Solutions and Projects Debug and Release Version Visual C# 2005 IDE Upgrading Form Visual C#2003 to Visual C# 2005 The Start Page The Menu The Toolbars The New Project Dialog box Graphical Designers Code Designers IntelliSence The Object Browser The Solution Explorer The Class View Window The Properties Window The Dynamic Help Window Component Trays The Server Explorer The Output Window The Task List The Error List The Command Window
87
Chapter 02
88
89
90
The main window, which display an introductory start page when the Visual Studio is started, is the one where all our code will be displayed. This window is tabbed so that we can switch between several files with ease by clicking on their filenames. It also has other functions: it can display graphical user interfaces that we are designing for our projects, plain text files, HTML, and various tools that are built into Visual Studio. Well describe all of those as we come across them in the course of this book. Above the main window, we have toolbars and the Visual Studio menu. There are several different toolbars that can be placed here, with functionality ranging form saving and loading files, to building and running projects, to debugging controls. Again, well discuss these as and when we need to use them. Here are brief description s of each of the main features of Visual Studio. NET 2003 that you will use the most: The Server Explorer and toolbox pop us when the mouse over them, and provide various additional capabilities, such as providing access to server setting and services, and access to the user interface building blocks for Windows applications. The Solution Explorer window displays information about the currently loaded solution. A solution is Visual Studio .NET terminology for one or more projects along with their configuration. The Solution Explorer window displays various views of the projects in a solution, such as what files they contain, and what is contained in those files. The Properties window allows a more detailed view of the of the contents of a project, allowing us to perform additional configuration of individual elements. For example, we can use this window to change the appearance of a button in a Windows form. The same window is also used to display dynamic help information. The Task List and Output window displays information when projects are compiled, along with tasks to be completed (in similar kind of display as is found in the task list in Microsoft Outlook). These tasks might be entered manually, or may be automatically generated by the Visual Studio.NET.
This may seem like a lot to take in, but dont worry, it doesnt take long to get used to.
Lets start building the first of our example projects, which will involve the use of many of the Visual Studio.NET elements described above.
91
Example Try it Out Creating a Simple Console Application Step by Step Example:
1. Create a new Console Application project by selecting the File | New | Project... menu item:
2. Select the Visual C# Projects folder from the Project Types: pane of the windows that appears, and Console Application projects type in the Templates: pane (youll have to scroll down a bit.) Change the Location: text box to C:\EaglesVisualCSharp\Chapter 2 (this directory will be created automatically if it doesnt exist), and leave the default text in the Name: text box as it is:
92
3. Click the OK button. 4. Once the project is initialized, add the following line of code to the file displayed in the main window. using System; namespace ConsoleApplication1 { /// <summary> /// Summary description for Class1. /// </summary> class Class1 { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { // // TODO: Add code to start application here // You need to add the coding after this line // where ever you see the like TODO: start you coding after the green color line // the green color line are the comments //EaglesGroup //Siddhu //Sri jayesh Console.WriteLine ("Welcome to The EaglesGroup C# Programming!");
} } } 5. Select the Debug | Start without Debugging menu item or Press Ctrl + F5. After a few movements you should see the following:
93
94
The Solution Explorer view shows the files that make up our ConsoleApplication1 project. This file we added code to, Class1.cs, is shown along another code file, AssemblyInfo.cs. (All C# code files have a .cs file extension.) This other code file isnt one we have worry about for the moment; it contains, which initially contains a default icon for use with our application (since we are using console application, however, this icon will not be used in the rendering of the start bar tab the default console application icon will be used instead). We can use the window to change what code is displayed in the main window by double clicking on files, right clicking on them and selecting View Code, or selecting them and clicking on the toolbar button that appears at the top of the window. We can also perform other operations on files here, such as renaming them or deleting them forms our project. Other types of files can appear here as well, such as project resources (resources are files used by the project that might not be C# files, such as bitmap images and sound files, as well as the icon file App1.ico). Again, we can manipulate them through the same interface. The References entry contains a list of the .NET libraries we are using in our project. Again, this is something well look at later, as the standard references are fine for us to get started with.
95
The other view, Class View, presents an alternative view of our project by looking at the structure of the code we have created. Well come back to this later in the book, so for now the Solution Explorer display is our display of choice. As you click on files or other icons in these windows, you may notice that the contents of the window below changed. This is another window that has multiple views, but most important of these is the Properties view.
This window shows additional information about whatever we select in the window above it. For example, the above view is displayed when the Class1.cs file form our project is selected. This window will also display information about other things that might be selected, such as user interface components as we will see in the windows application of this chapter. Often, changes we make to entries in the Properties window will effect our code directly, adding lines of code or changing what we have in our files. With some projects, well spend as much time manipulating things through this window as making manual code changes. Next, lets take a look at the Output window. When we execute our example code you probably noticed that a section of text appeared here before the console window created by our application appeared. On my computer this appeared:
96
------ Build started: Project: ConsoleApplication1, Configuration: Debug .NET -----Preparing resources... Updating references... Performing main compilation... Build complete -- 0 errors, 0 warnings Building satellite assemblies...
---------------------- Done ---------------------Build: 1 succeeded, 0 failed, 0 skipped As you can probably guess, this is showing us a status report as our files compiled. This is also where we will get reports of any errors that occur during compilation. As an example, try removing the semicolon from the line of code we added in the last section and recompiling. This time you should see: ------ Build started: Project: ConsoleApplication1, Configuration: Debug .NET -----Preparing resources... Updating references... Performing main compilation... c:\eaglesvisualcsharp\chapter 2\consoleapplication1\class1.cs (24, 68): error CS1002: ; expected Build complete -- 1 errors, 0 warnings Building satellite assemblies...
97
This time the project wont run. DENOTE: In the next chapter, when we start looking at C# syntax, we will see how semicolons are excepted throughout our code at the end of most lines in actual fact. Since we have something to do now in order to get the code working, Visual Studio .NET 2003 automatically adds a task to the task list that shares with the Output window:
This window will help us eradicate bugs in our code, as it keeps track of what we have to do in order to compile projects. If we double click on the error shown here, the cursor will jump to the position of the error in our source code (the source file containing the error will be opened if it isnt already open), so we can fix it quickly. We will also see red wavy line at the positions of the errors in the code, so we can quickly scan source code to see where problem lie. Note that the error location was specified as a line number. By default line numbers arent displayed in the Visual Studio .NET 2003 text editor, but this something that is well worth turning on. To do this, we need to tick the relevant check box in the Options dialog, obtained through the Tools | Options... menu item. The check box is called Line Numbers, and is found in the Text Editor | C# | General category, as shown below:
98
There are many useful options that can be found through this dialog, and we will use several of them throughout this book.
99
2. Move the mouse pointer to the Toolbox on the left of the screen, then to the Button entry of the Windows Forms tab, and double click the left mouse button on the entry to add a button to the main form of the application (Form1):
3. Double click on the button that has been added to the form. 4. The C# code in the Form1.cs should now be displayed. Modify it as follows (only part of the code in the files show here for brevity): private void button1_Click(object sender, System.EventArgs e) { MessageBox.Show ("Welcome to EaglesGroup Programming Happy Programming!"); } 5. Run the Application. 6. Click the button presented to open a message dialog box:
100
101
The Text written on the button in Form1 should also change to reflect this.
There are many properties for this button, ranging from simple formatting of the color and size of the buttons to more obscure settings such as data binding settings, which allow links to database. As briefly mentioned in to later and upcoming chapters change in properties often results in direct change to code, and this no exception. Switch back to the code view of Form1.cs, and well take a little peek at the change we just made. At a cursory glance, you might not notice anything different in the code at all. This is because the section of C# code that deal with the layout and formatting of controls on a form are hidden form us (after all, we hardly need to look at the code if we have a graphical of the results).
102
Visual Studio.NET uses a system of code outlining to achieve this subterfuge. We can see this in the following screenshot:
Looking down the left hand side of the code (just next to the line numbers if youve turned them on), you may notice some gray line and boxes with + and symbols in them. These boxes are used to expand and contract regions of code. Around the middle of the file (line 48 in mine, although this may vary) is a box with a + in it and a box in main boy do the code reading Windows Form Designer generated code. This label basically is saying here is some code generated by Visual Studio.NET that you dont need to know about. We can look at it if we want, however, and see what we have done by changing the button properties. Simply click on the box within the + in it and the code will become visible, and somewhere in there you should see the following line: // // button1 // this.button1.Location = new System.Drawing.Point(112, 112); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(104, 32); this.button1.TabIndex = 0; this.button1.Text = "Click ME"; this.button1.Click += new System.EventHandler(this.button1_Click);
103
Without worrying too much about the syntax used here, we can see that the text we typed in to the Properties widow has popped up directly in our code. This outlining method can be very handy when we are witting code, as we can expand and contract many other regions, not just those that are normally hidden from us. Just as looking at the table of contents of a book can help us by giving us a quick summary of the contents, looking at a serious of collapsed regions of code can make it much easier for us to navigate through what can be vast amounts of C# code.
Summary
In this chapter, weve introduced some of the tools that well using thought the rest of the book. We have has quick tour around Visual Studio.NET development environment, and used it to build two types of applications. The simpler of these, the console application, is quite enough for most of our needs, and allows us to focus on basics of C# programming. Windows application is more complicated, but is visually more impressive and intuitive to use to anyone accustomed to a Windows environment (and lets face it, thats most of us). Now we know how we can create simple applications, we can get down to the real task of leaning C#. The next section of this book will deal with basic C# syntax and program structure, before we moving on to more advanced object oriented methods later. Once weve covered all that, we can start to look at how we use C# to gain access to the power available in the .NET Framework.
104
Chapter 03
105
106
107
Here the <code line x, statement y> sections are not actual pieces of C# code. Ive just used this text as a place holder for where C# statements would go. Note that in this case, the second and third lines of code are part of the same statement, as there is no semicolon after the second line. In this simple section of code, I have also used indentation to clarify the C# itself. This isnt some random invention of mine. It is standard practice and in fact vs will automatically do this for you by default. In general, each of code has its own level of indentation, meaning how far to the right it is. Blocks of code may be nested inside each other that are; blocks may contain other blocks, in which case nested blocks will be indented further: { <code line 1>; { <code line 2>; <code line 3>; } } <code line 4>;
Also, lines of code that are continuations of previous lines are usually intended further as well as in the third line of code in the first example above.
3.2 Comment
To make out comments using the first method, we use / * characters at the start of the comment and */ characters at the end. These may occur on a single line, in which case all lines in between are part of the comment. The only thing we cant type in the body of a comment is */, as this is interpreted as the end marker. So the following are Ok.
108
/* This is a comment Siddhu */ /* And so .. Shamu launch C# to EaglesGroup . */ But the following will cause problems: /* Comments after end with */ Characters */
Here the end of the comment, the characters after * will be interpreted as C# code, and errors will occur. The other commenting approach involves starting a comment with //. Next we can write whatever we like as long we keep to on line!. The following is OK: // this is eagles Siddhu // Welcome to C#.net // Welcome to EaglesGroup
But the following will fail however, as the second line will be interpreted as C# code. // eagles Siddhu Welcomes you to C#.net
This sort of commenting is useful to document statements, as both can be placed on a single line: <A statement >; // Eagle Siddhu
There is a third type of comment in C# which allows you to document your code. They are single line comments that start with three / symbols instead of two like this. /// Welcome to Eagles group /// Welcome to Eagles Visual C#.NET
109
Under normal circumstances, they are ignored by the compiler just like other comments, but you can configure vs to extract the text after these comments and create a specially formatted text file when a project is compiled, which we can then use to create documentation. Well look at this in detail. A very important point to note about C# code is that it is a case sensitive. Unlike some other languages, we must enter code using exactly the right case as simply using an upper case letter instead of a lower case one will prevent a project compiling.
Example Try it out Eagles ConsoleApplication Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles Console Application in the directory C:\EaglesVisualCSharp\Chapter 3 Variables and Expressions\Example Using Console Application
110
2. Now add the following code in the Program.cs as follows: namespace Eagles_Console_Application { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion class Program { static void Main(string[] args) { Console.WriteLine("Welcome to EaglesGroup Console Application in Eagles Visual C#.NET!"); } } } 3. Run the Application and you should have this output:
111
We can immediately see that all the syntactic elements discussed in the last section are present here. We see semicolons, curly braces, and comments, along with appropriate indentation. The most important section of code as far as usre concerned at the moment is the following: static void Main(string[] args) { Console.WriteLine("Welcome to EaglesGroup Console Application in Eagles Visual C#.NET!"); }
This is the code that is executed when we run our console application, or to be more precise, the code block enclosed in curly braces is what is executed. The only line of code that will actually do anything here is the one we added to the automatically generated code, which is the only line in the code block that isnt a comment. This code simply outputs some text to the console window, though the exact mechanisms of this shouldnt concern us for now. For now we wont worry about the other code in the example, as the purpose of these first few chapter is to explain basic C# syntax, so that exact method of how the application execution gets to the point where Console.WriteLine() is called is not our concern. Later on the significance of this additional code will be made clear.
3.4Variables
As discussed in the introduction to this chapter, variables are concerned with the storage of data. Essentially, we can think of variables in computer memory as boxes sitting on a shelf. With boxes we can put things in and take them out again. Or we can just look inside a box to see if anything is there. The same goes for variables; we place data in them and can take it out or look at it, as required.
112
Although all data in a computer is effectively the same thing a series of zero and ones, variables come in different flavors, known as types. Again using own box analogy we can imagine that our boxes come in different shapes and sizes and some things will only fit in certain boxes. The reasoning behind this type system is that different types of data may require different methods of manipulation and by restricting variables into individed type. We can avoid getting mixed up, it wouldnt for example, make such sense to treat the series of zeros and ones that make up a digital picture as an audio file. In order to use variables, we have to declare them. This means that we have to assign them a name and a type. Once we have declared variables we can use them as storage units for the type of data that we declared them to hold. The C# syntax for declaring variables simply involves specifying the type and variable name as follows : <type > <name> ;
If we try to use a variable that hasnt been declared, then our code wont compile, but in this case the compiler will tell us exactly what the problem was. So this isnt really a disaster error. In addition, trying to use a variable without assigning it a value will also cause an error, but again, the compiler will detect this. So, what is the type that we can use? Well, in actual fact there are an infinite number of types that we can use. The reason for this is that we can define our own types to hold whatever convoluted data use lime. Having said this, there are certain types of data that just about everyone will want to use at some point or another, such as a variable that stores a number, for example because of this there are a number of simple, pre-defined types that we should be aware of.
113
complex types. Most of the simple types available are numeric, which at first glance seems a bit strange surely we only need one type to store a number. The reason for the plethonce of numeric types is down to the mechanics of storing numbers as a series of zeros and ones in the memory of a computer. For integer values, we simply take a number of bits (individual digits that can be zero or one) and represents any number between 0 and (2n-1). Any number above this value will be too big to fit into this variable. As an early example, lets say we have variable that can store? Bits. The mapping between integers and the bit s representing those integers is therefore as follows: 0 = 00 1 = 01 2 = 10 3 = 11
If we want to be able to store more numbers, we need more bits. 3 bits will let us store the numbers from 0 to 7. For example, Instead, we have a number of different integers type that can be used to store various ranges of numbers, and take up different amounts of memory (up to 64 bits). The list of these is as follows: DENOTE: That each of these type make use of one of the standard type defined in the .net framework. As discussed in chapter 1, this use of standard type is what allows interoperability between languages. The names we use for this type in C# are allies for the defined in the framework.
114
The table lists the names of these types are referred to in the .net framework library. Type byte sbyte short ushort int uint long Alies for system.byte system.sbyte system.int16 system.vint16 system.int32 system.vint32 system.int64 Allowed Values Integer between 0 and 255 Integer between -128 and 127 Integer between -32768 and 32767 Integer between 0 and 65535 Integer between -2147483648 and 214748347 Integer between 0 and 4294962795 Integer between -9223372036854775808 and 9223372036854775807 Integer between 0 and 18446744073709551615
ulong
system.vint64
The U s before some variables name are shorthand for unsigned meaning that we cant store negative numbers in variables of those types, as can been seen in the allowed values column of the table.
Type
Alias for
Minm
Max.
Mine
Max
Float Double
system.single system.double
0 0 0
- 149 - 1075 - 28
104 970 0
Decimal system.decimal
115
In addition to numeric types there are three other simple types available. Type char Application system.char Allowed Values Single Unicode, character, stored as an integer between 0 and 65535. Boolean value, true or false A sequence of characters
bool string
system.boolean system.string
DENOTE: That there is no upper limit on the amount of characters making up a string as it can use varying amounts of memory. The Boolean type bool is one of the most commonly used variable types in C#, and indeed similar types are equally prolific in code in other languages. Having a variable that can be either true or false has important ramifications when it comes to the flow of logic in an application. As a simple example, consider how many questions there are, that can be answered with true or false as yes or no. Performing comparisons between variable values as validating input are just two of the programmatic uses of Boolean variables that will be examining very soon. Lets work it out Using Simple Type Variables
Example Try it out Eagles SimpleType Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles SimpleType in the directory C:\EaglesVisualCSharp\Chapter 3 Variables and Expressions\Example Using Simple Type Variables 2. Add the following in the Static void Main () method of the Program.cs as follows:
116
namespace Eagles_SimpleType { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion class Program { static void Main(string[] args) { int myInteger; string myString; myInteger = 18; myString = "\" myInterger \" is"; Console.WriteLine("{0} {1}.", myString, myInteger); } } }
3. Run the Program and you will get the output like this:
117
Now lets see how the above program works: The code we have added does three things. It declares two variables. It assigns values to those two variables. It outputs the value of the two variables to the console. Variable declaration occurs in the following code: int myinteger; string mystring; The first line declares a variable of type int with a name of myinteger, and the second line declares a variable at type string called mystring. DENOTE: That variable is restricted and we cant just use any sequence of characters will look at this in the section on naming variables below. The next two lines of code assign values: myinteger = 17; mystring = \ myinteger \ is;
118
Here we assign two fixed values know as literal value in code to our variables using the = assignment operator. We assign the interfere value 18 to myInteger, and the string myInteger is including the quotes to enclose the string. Due to this, there are certain characters that may cause problems if they are included in the string itself, such as the double quote characters, and we must escape some characters by substituting a sequence of characters that represents the characters we want to use in the above example, we use the sequence \ to escape a double quote:
If we didnt use these escape sequence and tired coding this: myString = "" myInterger" is";
We would get a complier error: DENOTE: That assigning string literals is another situation where we must be careful with the line breaks the C# compiler will reject string literals that span more than one line. If we want to add a line break we can use the escape sequence for a carriage return in our string \, which is \n. For example, the following assignment: //myString = "This string has a\nline break.";
Would be displayed on two lines in the console view as follows: This string has a Line break
All escape sequence consit of the backslash symbol followed by one of a small set of characters well look at the full set a liter later. Because this symbol is used for this purpose there is also an escape sequence for the backslash symbol itself, which is simply two consecutive backslashes. \\. Getting back to the code, there is one more line that we havent looked at: Console.WriteLine("{0} {1}.", myString, myInteger);
119
This looks similar to the simple method of writing out text to the console that we saw in our first example, but now we are specifying our variables. Now, we dont want to get ahead of ourselves here. The technique we will be using in the first part of this book to output to the console window. Within the brackets we have two things: A string A list of variables whose values we want to insert into the output string, separated by commas The string we are outputting {0} {1}. doesnt seem to contain much useful text. As you will have seen, however, this is not what you actually see when you run the code. The reason for this is that the string is actually a template into which we insert the contents of our variable. Each set of curly brackets in the string is a placeholder that we will contain the contents of each of the variables in the list. Each placeholder or format string is represented as an integer enclosed in curly brackets. The integers start at 0 and increment by 1, and the total number of placeholder should match the number of variables specified in the comma- separated list following the string. When the text is output to the console, each placeholder is replaced by the corresponding value for each variable. In this above example, the {0} is replaced with the actual value of the first variable, myString, and {1} is replaced with the contents of myInteger. This method of outputting text to the console is what we will use to display output from our code in the example that will follow:
3.6Variable Naming
As mentioned in the last section, we cant just choose any sequence of characters as a variable name. This isnt worrying as it might sound at first, however, as we are still left with a very flexible naming system.
120
The basic variable naming rules are as follows: The first character of a variable name must be either a letter, an under score character (_) or @. Subsequent characters may be letters underscore characters or numbers. In addition, there are certain keywords that have a specialized meaning to the C# compiler, such as the using and namespace keywords we saw earlier. If you should use one of these by mistake, the compiler will complain and youll soon know youve done something wrong. So dont worry about this too much. For example the following variable names as fine: myBigVar VAR1 _test
And remember, C# is case sensitive, so we have to be careful not to target the exact casing used when we declare our variables. References to them made later in the program with even so much as a single letter in the wrong case will prevent compilation. A further consequence of this is the fact that we can have multiple variables whose names differ only in casing. For example the following are all separate names: myVariable MyVariable MYVARIABLE
121
122
The following are camelCase variable name: age first Name time of Death
Then, the following are pascalCase: Age Last Name Winter of Discontent
For our simple variables we shall stick to camelCase, and use pascalCase for certain more advanced naming, which is the Microsoft recommendation. Finally, it is worth nothing that many part naming system involved frequent use of the underscore character, usually as separators between words of variable name, such as my-first-variable. This usage is now discouraged one thing i am eagle siddhu happy about is always though it looked ugly.
Suffix
123
u or V 1 or L
100 U 100 L
u1, uL, U1, UL, 100 UL 1U, 1u, or LU f or F d or D m or M None None 1.5 F 1.5 1.5 M a or escape sequence a a, mg include escape sequence
Single quote Double quote Back slash Null Alert cause a beep Back space Form feed New line
124
\r \t \v
The Unicode value column of the above table shows the hexadecimal values of the character as they are found in the Unicode character set. As well as the above, we can specify any Unicode character using a Unicode escape sequence. This consists of the standard \ character followed by all and a four digit hexadecimal value. For example the four digits after X is the above table. This means that the following strings are equivalent: Siddhu\s string Siddhu \u0027s string
Obviously, we have more versatility using Unicode escape sequence. We can also specify strings verbatim. This means that all characters contained between two double quotes are included in the string, including end of line characters and characters that would otherwise need escaping. The only exception to this is the escape sequence for the double quote character, which must be specified in order to avoid ending the string. To do this, we place a @ character before the string. @ Verbatim string literal
This string could just as easily to be specified in the normal way, but the following requires this method: @ A short list item 1 item 2
125
Verbatim string are particulary useful in filename, since these use plenty of backslash characters. Using normal strings we have to use double backslashes all the way along the string, for example: C:\\Eagles\\Siddhu\\eagles.doc
DENOTE: Remember that you will use this kind of command in ADO.NET section Verbatim string literals can make this more readable. The following verbatim string is equivalent to the above: @C:\Eagles\Siddhu\eagles.doc
DENOTE: That as well see later in this book string are reference types. Unlike the other types weve seen in this chapter which is value types. One consequence of this is that strings can also be assigned the value null, which means that the string doesnt reference a string. This will be explained in more detail later on this book.
126
Remember that variables must be initialized before we use them. The above assignment could be used as an initialization. There are a couple of other things we can do have that you are likely to see in C# code. The first, is declaring multiple variables of the same type at the same time, which we can do by separating this names with common after the type. For example int Xsize, Ysize;
Here Xsize and Ysize are both declared as integer types. The second technique you are likely to see is assigning value, to variables at the same time as declaring them, which basically means combining two limes of code: int age = 22;
int Xsize = 4, Ysize = 5; Here both Xsize and ysize are assigned different values. Note that the following: int Xsize, Ysize = 5;
3.11 Expressions
127
Now that weve seen how to declare and initialize variables, its time to look at manipulating them. C# contains a number of operators for this purpose, inducing the = assignment operators weve used already. By combining operators with variables and literal values together referred to as operand when used with operators, we can create expressions, which are the basic building blocks of computation. The operators available from range the simple to highly complex ones. Some of which you might never encounter outside of mathematical operators application. The simple ones include all the basic mathematical operations, such as the + operator to add two operands, and the complex ones include manipulations of variable content via the binary representation of this content. There are also logical operators specifying for dealing with Boolean values, and assignment operators like =. In this chapter, well concentrate on the mathematical and assignment operators leaving the logical ones to the next chapters. We will explain Boolean logic in the context of controlling program flow.
Operators can be roughly classified into 3 categories. They are as follows: Unary operators, which act as single operand. Binary operators, which act as two operands. Ternary operator, which act as three operands. Most operators fall into the binary category, with a few unary ones and a single ternary one called the conditional operators. The conditional operator is a logical one that is it returns a Boolean value, and well discuss it later.
128
Result var1 is assigned the value that is the sum of var2 and var3 var1 is assigned the value that is the value of var3 subtracted from the value of var2 var1 is assigned the value that is the product of var2 by var3
binary
binary
binary
var1 is assigned the value that is the result of dividing var2 by var3
binary
var1 is assigned the value that is the remainder when var2 is divided by var3 var1 is assigned the value of var2 var1 is assigned the value of var2 multiplied by -1.
+ -
unary unary
Ive shown examples using simple numeric types, since the result can be unclear when using the other simple type. What would you expect if you add two Boolean values together? For example, in this case nothing as the compiler will complain if you try to use + (or any of the mathematical operators) with bool variables. Adding char variables is also slightly confusing. Remember, char variables are actually stored as numbers, so adding two char variables together will also give you a number of type int, to be precise? This is an example of implicit conversion, and Ill have a lot more to say about this subject, and explicit conversion shortly, as it also applies to cases where var1, var2, and var3 are of. Having said all this, the binary + operator does make sense when used with string type variables. In this case, the table entry should read:
129
Result var1 is assigned the value that is the concatenation of two strings stored in var2 and var3
The other two operators we should look at here are the increment and decrement operators, both of which are unary operators that can be used in two ways; either immediately before or immediately after the operand. Lets take a quick look at the results obtained in simple expressions and then discuss them. Operator Category ++ -++ -unary Example Expression var1 = ++ var2; Result Var1 is assigned the value of Var2 +1. Var2 is incremented by 1. Var1 is assigned the value of Var2. Var2 is decremented by 1. Var1 is assigned the value of Var2. Var2 is incremented by 1. Var1 is assigned the value of Var2. Var2 is decremented by 1.
unary
var1 = -- var2;
unary
unary
The key factor here is that these operators always result in a change to the value stored in their operand. ++ Always results its operand being incremented by one. -- Always results in its operand being decremented by one. The differences between the results stored in var1 are a consequence of the fact that the placement of the operation determines when it takes effect. Placing one of these operators before its operand means that the operand is affected before any other computation takes place. Placing it after the operand means that the operand is affected after all other computation of the expression is completed.
130
This merits another example. Consider this code: int var1, var2 = 5; var3 = 6; var1 = var2 ++ * var3; Lets work it out Using Mathematical Operators
Example Try it out Eagles MathematicalOperators Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles MathematicalOperator in the directory C:\EaglesVisualCSharp\Chapter 3 Variables and Expressions\Example Using Mathematical Operators 2. Add the Following code into the Program.cs as follows:
131
namespace Eagles_MathematicalOperator { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// ALl Rights Reserved to EaglesGroup /// </Eagles> # endregion class Program { static void Main(string[] args) { double firstNumber, secondNumber; string userName; Console.WriteLine("Please Enter You'r Name:"); userName = Console.ReadLine(); Console.WriteLine("\n"); Console.WriteLine("Welcome {0} !", userName); // it will display the inputed name Console.WriteLine("Enter an a Number:"); Console.WriteLine("\n"); firstNumber = Convert.ToDouble(Console.ReadLine ()); Console.WriteLine("\n"); Console.WriteLine ("Enter an second number:"); Console.WriteLine("\n"); secondNumber = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("\t\n" + "******" + "Welcome!" + userName + "***************"); Console.WriteLine ("\n"); Console.WriteLine("The sum of the {0} and {1} is {2}. ", firstNumber, secondNumber, firstNumber + secondNumber); Console.WriteLine("\n"); Console.WriteLine("The Result of Subracting {0} and {1} is {2}, ", firstNumber, secondNumber, firstNumber - secondNumber); Console.WriteLine("\n"); Console.WriteLine("The Product of {0} and {1} is {2} . ", firstNumber, secondNumber, firstNumber * secondNumber); Console.WriteLine("\n"); Console.WriteLine ("The Reminder of {0} and {1} is {2} . ", firstNumber, secondNumber,firstNumber / secondNumber ); }
132
3. Now Execute the program.cs and you will have the output like this:
133
6. Enter the second number and you will the see something like this:
Now lets see how the above code works: As well as demonstrating the mathematical operators, this code introduces two important concepts, which we will come across many times in our worked example; User Input Type Conversion User input uses a similar syntax to the Console.WriteLine () command weve already seen. We use Console.Readline (). This command prompts the user for input, which is stored in a string variable.
134
string userName; Console.WriteLine("Please Enter You'r Name:"); userName = Console.ReadLine(); Console.WriteLine("\n"); Console.WriteLine("Welcome {0} !", userName); // it will display the inputed name
binary
var1 -= var2;
binary
var1 %= var2;
135
As you can see, the additional operators result in var1 being included in the calculation so, code like: var1 += var2; Gives exactly the same result as: var1 = var1 + var2;
DENOTE: That the += operator can also be used with strings, just like +. Using these operators, especially when employing long variable names, can make code much easier to read.
Here, the + operator acts before the = operator. There are other situations where operator precedence isnt so obvious, for example:
136
Here the * operator acts first, followed by the + operator, and finally the = operator. This is the standard mathematical order of doing things, and gives the same result as you would expect from working out the equivalence algebraic calculation on paper. Like such calculations, we can gain control over operator precedence by using parentheses, for example: var1 = (var2 + var3) * var4;
Here, the content of the parentheses is evaluated first, meaning that the + operator acts before the * operator. Of the operators we have encountered so for the order of precedence is as follows: when operators of equal precedence (such as * and /) are evaluated in a left to right manner.
Precedence Highest
Lowest
DENOTE: that parentheses can be used to over do this precedence order as described above.
137
3.15 Namespaces
Before we move, on, its worth spending some time on one more important subject namespace. These are the .Net way of providing containers for application code, such that code and its contents may be uniquely identified. Namespace are also used as a means of categorizing items in the .Net framework. Most of these items are type definitions such as the simple types detailed in this chapter (system Int32 and so on). C# code, by default, is contained in the global namespace. This means that items contained in this code are accessible from other code in the global namespace. Simply by referring to them by name, we can use the namespace keyword, however, to explicitly define the namespace for a block of code enclosed in curly brackets. Names in such a namespace must be qualified if they are to be used from code outside of this namespace. A qualified name is one that contains all of its hierarchical information. In basic terms, this means that if we have code in one namespace that needs to use a name defined in a different namespace, we must include a reference to this namespace. Qualified names use period character (.) between namespace levels. For example : namespace levelone { // code in level one namespace // name nameone defined } // code in global namespace
This code defines one namespace levelone, and a name in this namespace. Nameone note that I havent shown any actual code here in order to keep the discussion general; instead Ive placed a comment where this definition would go. Code written inside the levelone namespace can simply refer to this name using nameone. No classification is necessary. Code in the global namespace, however, must refer to this name using the classified name levelone.nameone.
138
Within a namespace, we can define nested namespaces, also using the namespace keyword. Nested namespaces are referred to via this hierarchy, again using periods to classify each level of the hierarchy. This is best illustrated with an example. Consider the following namespaces: namespace levelone { // code in levelone namespace namespace leveltwo { // code in levelone.leveltwo namespace namespace leveltwo { // code in levelone.leveltwo namespace // name nametwo defined } } // code in global namespace
Here, nametwo must be referred to as levelone.leveltwo. Nametwo the global namespace, leveltwo.nametwo levelone namespace, and nametwo from the levelone.leveltwo namespace. The important point to note here is that names uniquely defined by this namespace. We could define the name namethree in the levelone and leveltwo namespaces. namespace levelone { // name namethree defined namespace leveltwo { // name namethree defined } }
139
This define two separate names levelone.namethree and levelone.leveltwo.namethree, that can be used independently of each other. Once namespace we setup, we can use the using statement to simplify access to the names they contain. In effect, the using statement says OK, we need names from this namespace. So dont bother asking me to classify them every time. For example, in the following code we are saying that code in the levelone namespace should have access to names in the levelone.leveltwo.namespace without classification. namespace levelone { using leveltwo; namespace leveltwo { // name nametwo defined }
Code in the levelone namespace can now refer to leveltwo.nametwo by simply using nametwo.
140
Summary:
In this chapter, weve covered a fair amount of ground on the way to create usable if basic C# applications. Weve looked at the basic C# syntax and analyzed the basic console application code that VS generated for us when we create a console application project. The major part of this chapter concerned the use of variables. We have seen what variables are, how we create them, how we assign values in them, and how we assign values in them, and how we assign values in them, and how we manipulate them and the values that they contain. Along the way, weve also looked at some basic user interaction, by showing how we can output text to a console application and read user input back in. We have also seen how we can assemble operators and operands into expressions, and looked at the way these are executed, and the order in which this takes place. Finally, we looked at namespace, which will become more and more important on the book progress. By introducing this topic in a fairly abstract way here, the ground work is completed for later discussions. So far all of our programming has taken the form of line-by-line execution. In the next chapter see how we can make out code more efficient by controlling the flow of execution using looping techniques and conditional branching. So we covered the following topics: 3.0Introduction to Variables and Expressions 3.1 Basic C# Syntax 3.2 Comment 3.3 Basic C# Console Application Structure 3.4Variables 3.5 Simple Types 3.6Variable Naming 3.7 Naming Conventions 3.8 Literal Values 3.9 String Literals 3.10 Variable Declaration and Assignment 3.11 Expressions 3.12 Mathematical Operators 3.13 Assignment Operators 3.14 Operator Precedence 3.15 Namespaces
141
Chapter 04
142
Flow control
4.0 Introduction to Flow control
All of the C# Code weve seen so for has had one thing in common. In each case, program execution has proceeded from one line to the next in top to bottom order, missing nothing. If all applications worked like this then we would be very limited in what we could do. The syntax of a language works in the first step toward understanding how the language is best incorporated into your application development environment. The next step in learning how the system works is to understand the tools built into the language that you could use to develop your application. These tools take from of programming concepts that all languages support, such as controlling flow, naming, interfacing to other systems, and extending the language. Nearly all modern programming languages can do all these things. C# is certainly no exception to this rule. In this chapter, well examine all the built in components that make the language successful. Well also explore the special extensions of the language that make specific programming problems easier to solve. Determining which way a program executes based on certain criteria is called flow control. It has five different areas they are as follows: Selection Iteration Conditional Logic. Branching Looping
4.1 Selection
Selection allows you to take a variety of paths based on a given input value. For section handling, the main method C# allows is the switch statement, whose general form is shown as follows: switch (expression) { case value: statement break; case other value: break; default: }
143
Any programmer familiar with either C++ or Java should recognize this syntax. The difference in case of C# lie in the types of variables you an use in the expression statement, the way in which you break out of case, and the way in which you jump from one case to another. In C++ or Java, the switch statement can be used with integer or Boolean values. You may elect to test a value using the switch statement for virtually any data types, but the result must be an integer result. In C#, this restriction is not valid. You may elect to have string variables in the switch statement or use enumerated values. The one thing you cannot put in a switch statement is an object that does not equate to an integral value. Lets work it out Using the Switch Statement
Example Try it out Eagles SwithcStatement Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles SwithcStatement in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the Switch Statement 2. Add the following code in the program.cs as follows: amespace Eagles_SwithcStatement { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program {
144
public static void MakeADecision(string s) { switch (s) { case "Hello": System.Console.WriteLine("Hello yourself!"); break; case "Goodbye": System.Console.WriteLine("Goodbye!!"); break; default: System.Console.WriteLine("Huh?"); break; } } public static void MakeANumericDecision(string s) { int nVar = 0; if (s == "Hello") nVar = 1; if (s == "Goodbye") nVar = 2; if (s[0] == '#') { string temp = ""; for (int i = 1; i < s.Length; ++i) temp += s[i]; nVar = Convert.ToInt16(temp); } switch (nVar) { case 0: goto default; case 1: case 2: MakeADecision(s); break; default: System.Console.WriteLine("Number {0}", nVar); break; } }
145
static void Main(string[] args) { if (args.Length > 0) MakeADecision(args[0]); MakeANumericDecision("#0"); MakeANumericDecision("#1"); MakeANumericDecision("#2"); MakeANumericDecision("#3"); } 4. Now run the application and you should have the output something like this:
Now lets see how the above code works: As you can see from the below code switch (nVar) { case 0: goto default; case 1: case 2: MakeADecision(s); break; default: System.Console.WriteLine("Number {0}", nVar); break; }
146
Switch statement allows you to jump around to different labels withing the switch. These statement s can also have muiliple labels that handle a single case. One interesting different between C++ and C# is that you can do the following: switch (x) { case 0 : Console.WriteLine(case 0); case 1: Console.WriteLine(case 1); }
4.2Iteration
Iteration, one of the most powerful forms of programming flow control, means repeating and repeating in a programming language means some from of loop construct. C# provides several different forms of loop constructs, including a new one, the foreach statement. Lets take a look at each from of loop construct, examines the reasons for its existence and the possible limitations of using it. The first loop construct is the for loop. The for loop in C# is closely related to for loops in C++ and Java; they permit you to initialize, text, and increment a variable within a single block. For loops were invented because the designers of the C programming language noticed a common them among programmers. When the designers of C# came along, they recognized the utility of the for loop and continued its existence in a way that was virtually unchanged from its C++ or Java cousins. Haha. The basic form from of for loop is follows: for (initial value statement; test statement ; increment statement ) Statement or bloc;
The major difference between the for loops in C++ and those in C# lies in the scope these loops have in these languages. In the original version of C++ and the one that Visual C++ still adhere to, the scope of the variables defined in a for loop went until it hit, the end of the block that contained the for loop; in other words: For (int I = 0; I < 10; ++I) Console.WriteLine (I = {0}, ,) // but the I is still valid here
147
In C# however, the for loop index counter would go out of scope immediately following the end of the for loop so that when the for loop is terminated by hitting one of its termination values, the variables would no longer be Valid.
4.3Conditional Logic
One of the most necessary aspects of the programming world is the ability to choose among different options in source code. The way this choice is usually accomplished is via an if statement. An if statement permities you to compare, contrast, or otherwise differentiate between two different choice after the comparison has been made, an if statement allows you to take the path that makes the most sense to you, giving the values of certain variables. C# allows you to use two different forms of if statement. First, it permits any variation of the standard if then else logic block. Secondly, it implements the C++ conditions also called the ternary operator. Both these constructs allow you to make choices based on variables types. As with the loop constructs, C# require that the content of an if statement be only a Boolean Type. In other word, you can do the following? If (I != 0) {}
4.4Branching
Where we execute code conditionally, depending on the outcome of an evaluation, such as only execute this code if my value is less that 10
4.5Looping
Looping is repeatedly executing the same statements for a certain number of times or until a test condition has been reached. Both of these techniques involve the use of Boolean logic. In the last chapter we saw the boll type, but didnt actually do much with it. In this chapter will be using it a lot and so we will start by discussing what we mean by Boolean logic so that we can use it in flow control Scenarios.
4.6Boolean Logic
The bool type introduced in the last chapter can hold one of only two values, true or false. This type is often used to record the result of some operation, such that we can act on this result. In particular, boll types are used to store the result of a comparison.
All Rights Reserved To EaglesGroup
148
DENOTE: As an historical aside, it is worth remembering and respecting the English mathematician George Boole, whose work in the mid nineteenth century forms the basis of Boolean logic. As an example, consider the situation (as mentioned in the introduction to this chapter) that we want to execute Code based on whether a variable, myVal, is less that 10. In order to do this we need some indication of whether the statement myVal is less than 10 is true or false, that is. We need to know the Boolean result of a comparison. Boolean comparisons require the use of Boolean comparison operators (also know as relational operators) which are shown in the table below. In all cases here var. l is 9 bool type variable, while the types of var. 2 and var. 3 my value.
Example Expression Var.1 = var.2 = var.3 Var.1= var.2 ! = var.3 Var.1= var.2 = var.3 Var.1= var.2 > = var.3 Var.1= var.2 = = var.3 Var.1= var.2 > = = var.3
Result for the above Example Expression Var.1 is assigned the value true if var.2 is equal to var.3 or false otherwise Var. 1 is assigned the value true if var.2 is not equal to var.3 or false otherwise. Var. 1 is assigned the value true if var.2 is less than var.3 or false otherwise. Var. 1 is assigned the value true if var.2 is greater than var.3 or false otherwise.
149
Var. 1 is assigned the value true if var.2 is less than or equal to var.3 or false otherwise. Var. 1 is assigned the value true if var.2 is greater than or equal to var.3 or false otherwise. We might use operators such as these on numeric values in code such as: bool isLessThan 10 ; islessThan 10 = myVal. < 10;
This code will result is LessThan10 being assigned the value true if my val.1 stores a value less than 10, or false otherwise. We can also use these comparison operators on other types, such as string: bool isSiddhu ; isSiddhu = myString == Siddhu,
Here isSiddhu will only be true if myString stores the string Siddhu We can also focus on Boolean Values:bool isTrue ; isTrue = my Bool == true ; Although here we are limited to use if == and! = operators. DENOTE: That a common code error occurs if you unintentionally assume that because Val1 Val 2 is false, then Val1 > Val 2 is true. If Val 1 == Val.2 than both these statements will be false. Im mentioning this here as its a mistake, Ive mad in the past!
150
There are some other Boolean operators that are intended specifically for working with Boolean values:Operator ! $ Category binary binary binary binary Example Expression Var.1 = ! var.2 Var.1= var.2 $ = var.3 Var.1= var.2 1 = var.3 Var.1= var.2 = var.3
Result for the above Example Expression Var1 is assigned the value true if Var2 is false or false if Var2 is true. (Logical Not) Var1 is assigned the value true if Var2 and Value are both true and false otherwise. (Logical AND) Var1 is assigned the value true if either Var2 or Var3 (or both) are true or false otherwise. (Logical OR) Var1 is assigned true if either Var2 or Var3, but not both, are true, or false otherwise. (Logical XOR, on exclusive OR)
151
So the last code snippet above could also be expressed as:bool isTrue ; isTrue = my bool $ true ;
Operator
Category
Example Expression
Result
$$
binary
||
binary
Var1 is assigned the value true if var.2 and var.3 are both true, or false otherwise (Logical AND) Var1 is assigned the value true if either Var2 are Var3 (on both) are true, or false otherwise (Logical OR)
The result of these operators is exactly the same as & and |, but there is an important difference in the way this result is obtained, which can result in better performance. Both at these look at the value of their first operand Var2 in the table above, and based on the value of this operand may not need to process the second operator Var3 above at all. If the value of the first open and of the && operator is false then there is no need to consider the value of the second open and, as the result will be false regardless. Similarly, the || operator will return true if its first open and is true, regardless of the value of the second operator. This isnt the case for the & and | operator. We saw above with these, both operands will always be evaluated. Because of this conditional evaluation of operands we will see a small performance increase if we use && and |. This will be particularly apparent in application that uses these operators a lot. As a rule of thumb, always use && and || where possible.
152
0 0
| is similar, but the result bits are different, as follows: Operand 1 bit 1 1 Operand 2 bit 1 0 1 0 | Result bit 1 1 1 0
0 0
153
For example, consider the operation shown in the following code int result, op1, op2 op1 = 4; op2 = 5; result = op1 & op2 ; Here we must consider the binary representations of op1 and op2; which are 100. And 101 respectively. The results are obtained by comparing the binary digits in equivalent positions in these two representations as follows: The left most bit of result is | if the left most bit of op1 and op2 are both | as 0 otherwise. The next bit of result is 1 if the next bit of op1 and op2 Continue for all remaining bits.
are
both 1 as 0 otherwise.
In the example the leftmost bits of op1 and op2 are both |, so the left most bit of result will be |, too. The next bits are both 0, and the third bits are | and 0 respectively. So the second and third bits of result will be O. The final value of result in binary representation is therefore 100, so result is assigned the value 4. The following illustrate this: 1 & 1 1 0 0 0 0 1 0 & 4 5 4
The same process occurs if we use the | operator except that in this case each result bit is 1 if either of the operand bits in the same position is 1 1 | 1 1 0 0 0 0 1 1 | 4 5 5
154
We can also use the operator in the same way, where each result bit is 1 one or other of the operand bits in the same. Position is one, but not both: Operand 1 bit 1 1 Operand 2 bit 1 0 1 0 ^Result bit 1 1 1 0
0 0
C# also allows the use of a unary bitwise operator , which acts on its operand by inverting each of its bits, such that the result is a variable having values of 1 for each bit in the operand that is 0, and vice versa ; Operand 1 bit 1 0 ~ Result bit 0 1
These bitwise operations are quite useful in certain situations; as they allow a simple method of making use of individual variable bits to stare information consider a simple representation of a color using three bits to specify red, green and blue content. We can set these bits independently to change the three bits to one of the following configurations.
155
Decimal Representation 0 4 2
Lets say we store these values in a variable of style int. Starting from a black color, that is an int. variable with the value of 0, we can perform operation like: int. my color = 0; bool contains Red ; my color = my color |2 ; || Add green bit, my color now my color = my color |4 ; || Add red bit, my color now contains Red = (my color $4) ==4; || check value of red bit The final line of code assigns a value of true to contains Red, as the red bit of my color is 1. This technique can be quite useful for making efficient use of information, particularly as the operations induced can be used to check the values of multiple bits simultaneously 32 in the case at int. value. However, they are better ways to storing extra information in single variables. In addition to these four bitwise operators there are two others that Id like to look at in this section. These are as follows: Operator Category binary Example Expression Var.1= var.2 var.3 Var.1= var.2 var.3
binary
156
Result for the above Example Expression Var1 is assigned the value obtained when the binary content of Var2 is shifted Var3 bits to the rights Val1 is assigned the value obtained when the binary content of Var2 is shifted Var3 bits to the left. This operator commonly called bitwise shift operands are best illustrated with a quick example: int. var.1, var.2 = 10, var.3 =2 ; var.1 = var.2 var.3 ;
Here, var.1 is assigned the values 40. This can be explained by considering that the binary representation of 10 is 1010, which shifted to the left by two places is 101000, binary representation of 40. In effect what we have done is carried out a multiplication operation. Each bit shifted to the left multiplies the value by 2, so two bit shifts to the left results in multiplication by 4. Conversely each bit shifted to the right has the effect of dividing the operands by 2 with any integer remainder bring lost: int. Var1, Var2 = 10; Var1 = Var2 1;
In this example, Var1 contains the value 5, whereas the following code gives a value of 2; int. Var1, Var2 = 10; Var1 = Var2 2;
You are unlikely to use these operators in most code, but it is worth being aware of their existence. Their primary use is in highly optimized code, where the overhead of other mathematical operations just wont do. For this reason they are often used in, for example, device drives or system code.
157
Operator & |
Result for the above Example Expression Var1 is assigned the value that is the result of Var1 &ofVar2. Var1 is assigned the value that is the result of Var1|of Var2 Var1 is assigned the value that is the result of Var1 of Var.2
These work with both Boolean and numeric values in the same way as &, |, and. DENOTE: That & = and | = use & and |, not && and ||, and get the overhead associated with these simples operators. The bitwise shift operators also have assignment operator as follows:
Operator
Category
Example Expression
Result Var1 is assigned the value obtained when the binary content at Var1 is shifted Var2 bits to the right.
binary
Var1= Var2 ;
158
==
binary
Var1= Var2 ;
Var1 is assigned the value obtained when the binary content at Var1 is shifted Var2 bits to the left.
Example Try it out Eagles BooleanOperators Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles BooleanOperators in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the Boolean and Bitwise Operators 2. Add the following code in the Program.cs as follows: namespace Eagles_BooleanOperators { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion class Program { static void Main(string[] args) { Console.WriteLine("Enter an Interger:"); int myInt = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("Interger less then 10? {0}", myInt < 10); Console.WriteLine("Integer between 0 and 5 ? {0}", (0 <= myInt) && (myInt <= 5)); Console.WriteLine("Bitwise AND of Integer and 10 = {0} ", myInt & 10); } }
159
Now lets see how the above code works: The first two lines of code prompt have and accept an integer value using techniques weve already seen: console.WriteLine("Enter an Interger:"); int myInt = Convert.ToInt32(Console.ReadLine());
We use convert To Int 32( ) to obtain an integer from the string input, which is simply another conversion command in the same family as the convert, To Double ( ) command we used previously. The remaining three lines of code perform various operations on the number obtained and display results, will work through this code assuming that the user enters 9, as shown in the program execution.
160
Precedence
Highest
+, , , , =, =
161
This adds quite a few more levels, but explicitly defines how expressions such as the following will be evaluated. Var1 = Var2 = 4 & & Var2 = 2; Where the && operator is processed after the = and = operators. One point to note here is that it doesnt hurt to add parentheses to make expression such as this one clearer. The compiles knows what order to process operators in, but we humans are prove to forget such things and we might want to change the order. writing the above expression as : Var1 = (Var12 = 4) & & (Var2 = 2) ; Solves this problem by being explicit about the order computation.
For example, consider the following: int myInteger = 5; goto myLabel ; my Integer + = 10; myLabel ; Console.WriteLine (myInteger = {0}, myInteger);
162
Execution proceeds as follows: my Integer is declared as an int type and assigned the value 5 The go to statement interrupts normal execution and transfers control to the line marked myLabel: The value of my Integer is written to the console The line of code highlighted below is never executed; int myInteger = 5 ; go to myLabel ; myInteger + = 10; myLabel : Console.WriteLine(myInteger = {0}, myInteger);
In fact, if you try this out in an application you will see that this is noted in the task list as a warning when you try to compile the code, labeled unreachable code detected along with a line number. goto statement have their uses, but they can make things very confusing indeed. As an example of some eagles code arising from the use of go to, consider the following start : int myInteger = 5; goto addVal; writeResult ; Console.WriteLine (my Integer = {0}, my Integer); goto start ; addVal: myInteger + = 10; goto writeResult ;
This is perfectly valid cod, but very difficult to read! You might like to try this out for yourself and see what happens. Being doing that, thoughts, try and work out what this code will do by looking at it, so you can give yourself part on the back if youre right.
163
4.11Branching
Branching is the act of controlling which line of code should be executed next. The one to jump to is controlled by some kind of conditional statement. This conditional statement will be based on a comparison between a test value and one as more possible value using Boolean logic. In this section we will look at the three branching technique available in C#: The ternary operator The if statement The switch statement.
Here, test is evaluated to obtain a Boolean value, and the result of the operator is either resultIfTrue or resultIfFalse based on this value We might use this as follows: String result string = (my Integer 10)? Less than 10 :Greater than or equal to 10; Here the result of the ternary operator is one of two strings, both of which may be assigned to result string. The choice of which string to assign is made by comparing the value of my Integer to 10, where a value of less than 10 result in the first string being assigned, and a value of greater than or equal to 10th second string.
For example, if my integer is 4 then result string will be assigned the string Less than 10.
164
This operator is fine for simple assignment such as this, but isnt really suitable for executing larger amounts of code based on a comparison. A much better way of doing this is to use the if statement.
4.13The if statement
The if statement is a far more versatile and useful way of making decisions. Unlike? Statements, if conditionally execute other statements. The simple use of on if statement is as follows: if ( test) code executed if testis true;
Where test is evaluated it must evaluate to a Boolean value for the code to compile and the line of code shown below the statement is executed if test evaluates to true. After this code is executed, or if it isnt executed due to test evaluating to false, program execution resumes at the nest line of code. We can also specify additional code using the else statement in combination with an if statement. This statement will be executed if test evaluate to false: if test code executed if testis true; else code executed if testis false;
Both sections of code can span multiple lines using blocks in braces: if ( test); { code executed if testis true; } else { code executed if testis false; }
165
As a quick example, lets rewrite the code from the last section that used the ternary operator: String result string = (My Integer 10); Less than 10 : Greater than 10; Since the result of the if statement cannot be assigned to a variable we have to assign a value to the variable in a separate step: String result string; if (My integer 10); result string = Less than 10; else result string = Greater than or equal to 10; Code such as this, although more verbose, if far easier to read and understand than the equivalent ternary form, and allows far more flexibility. Lets work it out Using the if Statement
Example Try it out Eagles IFStatement Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles IFStatement in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the if Statement 2. Add the following code in the Program.cs as follows: namespace Eagles_IFStatement { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EalgesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program
166
{ static void Main(string[] args) { string comparison; Console.WriteLine("Enter a Number:"); double var1 = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("Enter another number:"); double var2 = Convert.ToDouble(Console.ReadLine()); if (var1 < var2) comparison = "less then"; else { if (var1 == var2) comparison = "equal to"; else comparison = "greater than"; } Console.WriteLine ("The First number is {0} the second number .",comparison); } 3. Now run the application and enter two number at the runtime when it is promoted:
167
Now lets see how the above code works: The first section of code is familiar, and simply obtaining two double values from lesser input. string comparison; Console.WriteLine("Enter a Number:"); double var1 = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("Enter another number:"); double var2 = Convert.ToDouble(Console.ReadLine());
Next we assign a string to the string variable comparison. Based on the values obtained for Var1 and Var2. First we check to see if var.1 is less than var.2: if (var1 < var2) comparison = "less then";
If this isnt the case then Vr1 is either greater than as equal to Vr2. In the else section of the first comparison. We need to rest a second comparison: else { if (var1 == var2) comparison = "equal to";
The else section of this second comparison will only be reached if Var1 is greater than Var2. else comparison = "greater than";
Finally we write the value of comparison to the console: Console.WriteLine ("The First number is {0} the second number .",comparison);
168
The resting we have used here is just one way of doing this. We could equally have written: if (var1 < var2) comparison = "less then"; else { if (var1 == var2) comparison = "equal to"; else comparison = "greater than"; }
The disadvantage with this method is that we are performing these comparisons regardless of the value of Var1 and Var2 with the first method we only perform one comparison. If Var1 Var2 is true and two comparisons otherwise we also perform the Var1 == Var2 comparison, resulting in fewer lines of code being executed. The difference in performance here will be slight, but would be significant in application where speed of execution is social.
169
{ if (Var1 ==3 || Var| = = 4) { // do something else } else { // do something else } } } DENOTE: That it is a common mistake to write conditions such as the third condition as if (var.1 ==3) || 4). Her, owing, to operator precedence, the == operator is processed first, leaving the || operator to operate on a Boolean and a numeric operand. This will cause an error. In these situations it can be worth using a slightly different indentation scheme and contracting the block of code for the else blocks that is, using a simple single line of code after the else blocks rather than a block of code 1. When we do this we end up with a structure involving else if statements: if (Var1 == 1) { // do something } else if (Var1 ==2) { // do something else } else if (Var1 ==3 || Var1 ==4) { // do something else } else { // do something else }
170
These else if statement are really two separate statements, and the code is functionally individual to the above code. However, this code is much easier to read. When making multiple comparisons such as this, it can be worth considering the switch statement as an alternative branching structure.
The value in siddhuVar is compared to each of the comparisonVal values specified wish case statements and if there is a match then the code supplied for this match is execrated. If there is no match then the code in default section is executed if this block exists. DENOTE: That this behavior is one area where C+ differs from C++, where the processing of case statements is allowed to run from one to another. The break statement here simply terminates the switch statements, and processing continues on the statement following the structure.
All Rights Reserved To EaglesGroup
171
There are alternative methods of preventing flow from one case statement to next in C# code. We can use the return statement, which results in termination of the current function rather than just the switch structure or goto statement as detailed earlier work jeer, since case statements in effect define in C# code. For example: switch (<testVar>) { case <comparisonVal>; <code to execute if <textVar> == <comparisonVal1> goto case <comparisonVal1>: <code to execute if <textVar> == <comparisonVal2>> Break; There is one execution to the rule that the processing of one case statement cant run freely into the next. If we place multiple case statement stack them before a single block of code, we are in effect checking for multiple conditions at once. If any of these conditions is met the code is executed, for example: switch (<testVar) { case <comparsionVal1>: case<comparsionVal2>: <code to execute if <textVar> == <comparsionVal1> or <testVar> == <comparsionVal1> break;
DENOTE: That these conditions also apply to the default statement. There is no rule saying that this statement must be the last in the list of comparisons, and we can stack it with case statement if we wish. But mostly rules are men to be broken. Adding a break point with break , goto, or return ensures that a valid execution path thought the structure in all cases. Each of the <comparsionValX> comparisons must be a constant value. One way of doing is to provide literal values, for example:
172
switch (myInteger) { case 1: <code to execute if myInteger ==1> Break; case -1; <code to execute if myInteger == -1> break; default: <code to execute if myInteger != comparisons> break; } Another way is to use constant variables. Constant variables are just like any other variables, except for one key factor: the value contains never changes. Once we assign a value to a constant to a constant variable that is the value it will have for the duration of code execution. Constant variables can come in handy here, as it is often easier to read code where the actual values being compared are hidden from us at the time of comparison. We declare constant variables using the const keyword in addition to variable type, and must assign those values at this time, for example: Const int intTwo = 2;
This code is perfectly valid, but if we try: Const int intTwo; IntTwo = 2; We will get a compile error. This also happens if we try and change the values of a constant variables thought any other means after initial assignment:
173
Example Try it out Eagles SwithcStatment2 Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles SwithcStatement2 in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the Switch Statement 2. Add the following code in the program.cs as follows:
namespace Eagles_SwithcStatment2 { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion class Program { static void Main(string[] args) { const string myName = "siddhu"; const string dogName = "blacky"; const string phoneName = "sony"; string name; Console.WriteLine("What is you name?"); name = Console.ReadLine (); switch (name.ToLower ()) { case myName: Console.WriteLine("You have the same name as me!"); break ; case dogName : Console.WriteLine ("Oh Boy, My dog name!"); break ; case phoneName : Console.WriteLine ("Your Phone is Good"); break ; } Console.WriteLine ("Hello {0}!" , name ); }
174
3. Now run the program and enter the name and you should have the output like this:
Our code sets up three constant strings, accepts a string from the user, and then out text to the console based on the string entered. In this case the strings are name. When we compare the name entered in the variable name to our constant value we first it into lower case with name.ToLower(). This is a standard command that will work with all string variables, and comes in handy when youre not sure what have been entered by the user. Using the technique the string Siddhu, SidDhuand siddhu, and so on will all match the test string siddhu. The switch statement itself attempts itself to match the string entered with the constant values we have defined. And writes out a personalized message, if successful, to greet the user. If no match is made we simply greet the user. Switch statement have no limit on the amount of case: section they contain, so you could extend this code to cover every name you can think have should you wish... But it might take a while!
175
4.16Looping
Looping is where statements are executed repeatedly. This technique can come in very handy, as it means we can repeat operations as many times as we want without having to write the same code each time. As a simple example, consider the following code for calculating the amount of money in a bank account after 10 years, assuming that interest is paid each year and no other money flows into on out of the account
double balance = 1000; double interest Rate = 1.05; // 5% interest 1 year balance * balance * balance * balance * balance * balance * balance * balance * balance * balance * = = = = = = = = = = interest Rate; interest Rate; interest Rate; interest Rate; interest Rate; interest Rate; interest Rate; interest Rate; interest Rate; interest Rate;
Writing the same code out 10 times seems a bit wasteful, and what if we want change the duration from 10 years to some other value? We have to manually copy the line of code the revived amount of times, which would be a bit of a pain!
Luckily we dont have to do this. Instead we can just have a loop that executes the instruction we want the required number of timers. Another important type of loop is one where we loop until a certain condition is fulfilled. These loops are slightly simpler then the situation detailed above, so well start them.
176
4.18Do loops
Do loops operate in the following way? The code we have marked out for looping is execrated, then 0; a Boolean test is performed, and the code executes again if this test evaluates to true, and so on. When the test evaluates to false the loop exists. The structure of a do loop is as follows: do { code to be looped } While ( Test );
Where Test evaluates to a Boolean value. The semicolon after the while statement is required, and its a common error to miss this out. For example. We could use this to write out the numbers from 1 to 10 in a column; int i = 1; do { console. write line ({0} ; i ++) ; } while (i T= 100);
Here we use the suffix version of the ++ operator to increment the value of i after it is written to the seen so we need to check for i = 10 in order to include ten in the numbers Lets use this for a slightly modification version of the code in the introduction to this section, where we calculate the balance in an account after 10 years. Here we will use a loop to calculate how many years it will take to get a specified amount of money in your account based on a stating amount and an interest.
177
Example Try it out Eagles doloops Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles doloops in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the do Loops 2. Add the following code into the program.cs as follows:
namespace Eagles_doloops { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program static void Main(string[] args) { double balance, interestRate, targetBalance; Console.WriteLine("What is your current balance?"); balance = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("What is you current annual interest rate (in %) ? "); interestRate = 1 + Convert.ToDouble(Console.ReadLine()) / 100.0; Console.WriteLine("What balance would you like to have?"); targetBalance = Convert.ToDouble(Console.ReadLine()); int totalYears = 0; do { balance *= interestRate; ++totalYears; } while (balance < targetBalance); Console.WriteLine("In {0} year {1} you'll have a balance of {2}.", totalYears, totalYears == 1 ? "" : "s", balance); }
178
3. Now run the code and enter some values and you should see the output like this:
Now lets see how the above program works: This code simply replaces the simple annual calculation of balance with a fixed interest rate as many time as is necessary for the balance to satisfy the terminating condition. We keep count of how many years have been accounted for by incrementing a counter variable with each loop cycle: int totalYears = 0; do { balance *= interestRate; ++totalYears; } while (balance < targetBalance); We can then se this counter variable as part of the result output: Console.WriteLine("In {0} year {1} you'll have a balance of {2}.", totalYears, totalYears == 1 ? "" : "s", balance); DENOTE: That is perhaps the most common usage of the? Ternary operator to conditionally format text with the minimum of code. Here we output ans after year if totallYears isnt equal to 1.
179
But this code isnt perfect. Consider that the situation where the target balance is less than the current balance here the output will be along the lines of:
Do loops always execute at least once. Sometime, as in this situation, this isnt ideal. Of course, we could add an if statement: int totalYears = 0; if (balance < targetBalance) { do { balance *= interestRate; ++totalYears; } while (balance < targetBalance); }
180
4.19WHILE LOOPS
While loops are very similar to do loops, but have one important difference. The Boolean test in a while loop takes place at the stand of the loop cycle, not the end. If the test evaluates to false then the loop cycles is never executed. Instead, program execution jumps straight to the code following the loop. While loops are specified in the following way: while (Test) { code to be looped }
And can be used in almost the same way as do loops; for example int i = 1 ; while (i = 10) { console. write line ({0}, i ++); } This codes gives the same result as the do loop we saw earlier, as it outputs the number 1 to 10 in a column.
Example Try it out Eagles Whileloops Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles Whileloops in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the While Loops 2. Add the following code in the program.cs as follows:
181
namespace Eagles_Whileloops { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { static void Main(string[] args) { double balance, interestRate, targetBalance; Console.WriteLine("What is your current balance?"); balance = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("What is you current annual interest rate (in %) ? "); interestRate = 1 + Convert.ToDouble(Console.ReadLine()) / 100.0; Console.WriteLine("What balance would you like to have?"); targetBalance = Convert.ToDouble(Console.ReadLine()); int totalYears = 0; while (balance < targetBalance ) { balance *= interestRate; ++totalYears; } Console.WriteLine("In {0} year {1} you'll have a balance of {2}.", totalYears, totalYears == 1 ? "" : "s", balance); }
3. Now run the program and when the output come enter a target balance less than the starting balance and see the output :
182
This is simple change from the do loop to a while loop has solved the problem in the last example. By moving the Boolean test to the start we provide for the circumstance where no looping is required, and we can jump string to the result. There are, of course, other alternatives in the this situation. For example, we could check the user input to ensure that the target balnce is greater that the starting balance. In this situation like this we can place the user inputes section in a loop as follows:
This will reject the value that doesnt make sense, se we l l gets the output as follows:
183
4.20FOR LOOPS
The last type of loop well look at in this chapter is the for loop. This type of loop is one that excretes a set number of times, and maintains its own counter. To define a for loop we need the following information: A starting value to initialize the outer variable A condition for containing the loop, involving the counter variable An operation to perform on the counter variable at the end of each loop cycle. For example, if we want a loop with a counter that increments from 1 to 10 in steps of an then the starting value is 1, the condition is that the counter is less than or equal to 10. And the operation to perform at the end of each cycle is to add one to the counter. This information must be placed into the structure of a for loop as follows: for ( initialization ; condition ; operation) } code to loop }
This works in exactly the same way as the following while loop: initialization while ( condition) { code to loop operation } But the format at the for loop makes the code easier to read, as the syntax involves the complete specification of the loop in one place, rather than being divided over several statements in different areas of the code. Earlier we used do and while loops to write out the numbers from 1 to 10. Lets look at the code required to do this using a for loop: int i ; for (i =1; i=10; ++i) { Console.WriteLine ({0},i); }
184
The counter variable, an integer called i, starts with a value of 1, and is incremented by 1 at the end of each cycle. During each the value of i is written to the console. DENOTE: That when code resumes after the loop i has a value of 11. This is because at the end of the cycle where i was equal to 10, i gets incremented to 11. This happens belong the condition that i = 10 is processed, at which paint the loop ends. As with while coops, for loops only execute if the condition evaluates to true before the first cycle.So the code in the loop doesnt necessary run at all. As a final not, we can declare the counter variable as part of the for statement, rewriting the above code as: For (int i ; i=10; ++i) { Console.WriteLine ({0},i); }
If we do this, though, the variable; wont be accessible from code outside this loop (see the section on variable scope in the up coming chapter) Lets look at an example using for loops.Since we have used loops quite a bit now. Ill make this example a bit more interesting; it will display a Mandelbrot set using plain text characters, so it wont look that spectacular) Lets work it out Using the for Loops
Example Try it out Eagles forLoops Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles forLoops in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the for Loops\Eagles forLoops 2. Add the following code in the Program.cs as follows:
185
namespace Eagles_forLoops { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { static void Main(string[] args) { {// Illustrate a simple for loop that counts from 1 to 5 for (int i = 0; i < 5; ++i) System.Console.WriteLine("I = {0}", i); // Illustrate two loops to first find a letter in a string // and then to print it out until a space is encountered. // This shows you how to skip initialization in the second // loop int nPos = 0; string s = "this is a test of the emergency broadcast system"; for (nPos = 0; nPos < s.Length; ++nPos) if (s[nPos] == 'b') break; for (; nPos < s.Length; ++nPos) { if (s[nPos] == ' ') break; System.Console.Write(s[nPos]); } System.Console.WriteLine("\n"); / Finally, illustrate how to use the for loop for something // other than an integer and how to change the increment int state = 0; for (double d = 0.0; d < 5.0; ) { System.Console.WriteLine("D = {0}", d);
186
switch (state) { case 0: d += 0.1; break; case 1: d += 0.2; break; case 2: d += 0.5; break; } state++; if (state > 2) state = 0; } }
3. Now run the program and you should have the output like this:
Now lets see how the above code works: As you can see, the incrementing of a floating point number is a tad strange in C#, which is something to be aware of while working with floats. You can never be quite sure how the compiler will generate instructions to add fractional numbers. The printing of the word broadcast shows how you can easily parse a string in C#, of course, the first block illustrates the most basic use of a for loop.
187
4.21FOREACH LOOP
The foreach loop allows programmers to quickly and easily work their way through array in order to process each element in the array. Although the foreach statement is new to C++ and Java programmers, it is quite familiar to VBScript programmers. This statement, a simple shorthand technique for loop, automatically uses the Get Enumerator interface to step through a given array or collection. The following example of iterating over one of the C# CLR collections the directory class. Lets work it out Using the foreach Loops
Example Try it out Eagles foreachLoops Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles foreachLoops in the directory C:\EaglesVisualCSharp\Chapter 4 Flow Control\Example Using the foreach Loops 2. Add the following code in the program.cs namespace Eagles_foreachLoops { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program {
188
static void Main(string[] args) { // First, an array of integers int[] arrayOfInt = { 1, 2, 3, 4, 5 }; foreach (int i in arrayOfInt) { Console.WriteLine("Int {0}", i); } // Now, how about an array of strings? string[] arrayOfStr = { "Hello", "Goodbye", "Why me?" }; foreach (string s in arrayOfStr) { Console.WriteLine("String {0}", s); } / Finally, let's look at a dictionary collection System.Collections.Generic.Dictionary<string, string> d = new System.Collections.Generic.Dictionary<string, string>(); //the Dictionary class d.Add("100", "Science"); d.Add("200", "Math"); d.Add("300", "English"); d.Add("400", "History"); d.Add("500", "Gym"); foreach (System.Collections.Generic.KeyValuePair<string, string> de in d) { Console.WriteLine("Entry Key {0} Value {1}", de.Key, de.Value); } }
189
3. Now run the program and you will have the following output:
Now lets see how the above program works: As you can see, the foreach statement is quite powerful. Because it is scripting shorthand for using the C# enumeration facilities, it allows you to create your own class that support a for each statement. All you need to do is to implement the Get Enumerator method in your class and provide the appropriate type of enumerator to retrieve data. Then, you can use foreach as if your class were built into the language.
4.22Interrupting Loops
There are times when we want fires grained control over the processing of looping code. C# provides four command that help us here, three of which we seen before in other situations. Break - causes the loop to end immediately continue - causes the current loop to end immediately (excretion continues with the next loop cycle) go to - allows jumping out of a loop to a labeled position not recommended if you want your code to be easy to read and understand) Return - jumps out of the loop and its containing function.
The break command simply exists the loop, and excretion continues at the first line at code after the loop for example
190
int i ; while (i=10;) { if (i= =6) break; Console.WriteLine ({0},i++); } This code will write out the numbers from 1 to 5, as the beak command causes the loop to exit when i reach 6. Continue only stops the current cycle, not the whole loop, for example; int i ; for (i =1; i=10; ++i) { if (1i%2) ==0) continue; Console.WriteLine (i); } In the above example, whenever the remained of i divided by 2 is zero, the continue statement stops the excretion of the current cycle, and so only the numbers 1, 3, 5, 7, 9 are displayed. The third method of interrupting a loop is to use go to us we saw earlier, for example: int i =1 ; while (i=10) { if (i==6) go to exit point; Console.WriteLine ({0},i ++); } Console.WriteLine (This code will never be reached.); exit point Console.WriteLine (This code is run when the loop is exited using go to :);
DENOTE: That exiting a loop with go to is legal if slightly messy, but it is illegal to use go to jump into a loop from outside.
191
4.23INFINITE LOOPS
It is possible, through both coding errors and design, to define loops that never end, so called infinite loops. As a very simple example, consider the following: While (true) { // code in loop }
This situation can be useful at times and we can always exit such loops using code such as break statements. However, when this occurs by accident it can be annoying. Consider the following loop, which is similar to the for loop in the last section: int i ; while (i=10) { if ((i %2) ==0) continue; Console.WriteLine ({0},i++); } Here i doesnt get incremented until the last line of code in the loop, which occurs after the continue statement. If this continue statement is reached which it will be when i is 2, the next loop gets will be using the same value of i, continuing the loop, testing the same value of i, and continuing the loop and so on. This will cause the application to freeze. Not that its still possible to quit the frozen application in the normal way, so you wont have to reboot your computer if this happens.
192
4.24UNSAFE CODE
Perhaps this heading should be in a warring block. Do not use unsafe code, its unsafe. In C#, however the unsafe code label is applied whenever you want to use elements the new language does not allow, but in order to get your job done you need to use these elements. For example, if you want to call out to a Windows API function from C#, you might need to use a pointer to iterate through a returned block of structures. The problem is, of course, that C# does not have pointers. Only C++ has them. Yet, you need the ability to call that function to get your job done. This is where C# really shines. It helps you get your job done, as long as you understand the risk you are taking. The purpose of unsafe code is to accomplish something that is, by its nature, an unsafe thing to do. One good example is in using pointers. Another is in using memory that cannot be safely collected by the garbage collection mechanism in the C# runtime environment. Something worth nothing is that even in an unsafe environment; C# does not allow you to violate type safety with one notable exception: void pointers. Thus, you can write: unsafe { Int[] x = new int int [10]; Int*px = &x; }
In this, case you have defined an unsafe block that allows you to assign a pointer an array so that you can step through it in typical array fashion, by incrementing the pointer. However, you still cannot do the following: unsafe { Int *x = new int[10]; } An integer pointer is not array; therefore you cannot assign an array to it. You cannot delete the array under any circumvents you must allow it to be garbage collected. Sometimes, you need to be able to create a pointer to call an eternal function. The problem of course is that the pointer at a block level of memory that can be garbage collected or moved in the memory without your knowledge about it. In case like this C#
193
provides for fixed statement, which allows you to pin a pointer in memory until you are done with it. Heres how you use it: Ussafe { Int [] x = new int [10]; Fixed (int xp = &x) { CallAFunctionwthAPointer(xp); } }
Public struct Eagles Unsafe bloc { Public fixed char EmplyName[50]; Public int RmpID; }
194
4.27Managed C++
First, a word of expiation, managed C++ is not really C#. it happens to be compiler that ships with Visual C# and allows, C++ development to use many of the same technique and library components as they fins in C#. However, managed C++ is a different compiler and is rally C++ in the .NET environment rather than a C# extension. The reason it covered in this section is that managed C++ is a natural extension of the use of the C# programming concepts in the .NET environment. Well what is managed C++? Simply, managed C++ is the way in which you can run C++ programs in a managed environment, as C# does, managed C++ gives you access to many C# extensions, such as garbage collection, the CLR, and exception handling from the ground up. Managed C++ does follow standard C++ rules, in that you can use the new operator to create objects. However, classes marked, as being available for garbage collection may not use the delete operator to delete those objects. C++ classes in a managed environment can also contain properties and use the managed components of the C# library, such as the String class. To utilize the managed C++ environment, you must use the newest version of the C++ compiler, which ships with the Visual Studio.NET and the .NET SDK Framework on it own. SDK versions of the compiler. You must further use the COM+ enchantments to the C++ language by using the /com+ comelier directive. Rather than going into greater detail here about managed C++ because it is not really a part of the C# system.
4.28COM Components
The Common Object Model (COM) and Windows is a topic that evokes greater emotion from developers. In general, people either love the idea or hate it. Bu no middle ground seems to exist. However, COM is here to say, whether you like it or not. Because the COM component is here to stay, you should leverage the capabilities it offers you whenever you can take advantage of them in you own development work. C# is built around a core of COM and exposes that functionality wherever it can,. Interfaces, binary components, and versioning are all obvious facets of the COM like nature of C#. C# makes creating COM components easy. It also makes utilizing existing COM component sin new application easy. This ease of use is important because many companies have best stake in their legacy COM components. Using a COM component in C# is a simpler matter of converting it into a type library that the C# runtime environment and compiler understand, and then linking the resulting metadata into your application, from there you simply use the COM library as if it were just another C# namespace.
195
SUMMARY
In this chapter we have developed our programming knowledge by considering various structures, is essential when we start making more complex applications, and we will see them time and again through this book. First we spent some time looking at Boolean logic with a bitwise logic thrown in for good measure. Looking back on their after working through the rest of the chapter confirms the starting assumption that we made, which is that this topic is very important when it comes to implementing branching and looping code in our programs. It is essential to become very familiar with the operators and techniques detailed in this section. Branching enable us to conditionally create code, which, when combined with looping, allows us to create controlled structured in our C# code. When you have loops inside if structures inside loops, you start to see why code indentation is so useful! If we shift all our code to the left of the screen it instantly becomes difficult to purse by eye, and even more difficult to debug. It is well worth making youve got the hang of indentation at this stage - youll appreciate it later on! OK, so we do a lot of this for us. But its a good idea to indent code as you type it any way. So far we have been see the following topics: 4.0 Introduction to Flow control 4.1Selection 4.2Iteration 4.3Conditional Logic 4.4Branching 4.5Looping 4.6Boolean Logic 4.7Bitwise operators 4.8Boolean Assignment operators 4.9Operator precedence updated 4.10The goto statement 4.11Branching 4.12The ternary operator 4.13The if statement 4.14More conditions using if statements: 4.15The switch statement 4.16Looping 4.18Do loops 4.19WHILE LOOPS 4.20FOR LOOPS 4.21FOREACH LOOP 4.22Interrupting Loops 4.23INFINITE LOOPS
196
4.24UNSAFE CODE 4.25Fixed size Buffers 4.26Extending the Language 4.27Managed C++ 4.28COM Components
197
Chapter 05
198
5. 1 Introduction to Functions
Functions
All the code we have seen so for has taken the Form of a block, perhaps with some looking to repeat lines of cook and branching to execute statements conditionally. It weve needed to perform an operation on own data then this has meant placing the code required right. Where we want it to work. This kind of code structure is limited. We will often find that some tasks for exam finding the highest value is an array may need to be performed at several paints in a program. We can just place identical as near identical sections of code in own application whenever necessary, but this is own problems changing even one minor detail
concerning a common task, to correct a code for example, may require change to multiple sections of code, which may be spread throughout the application. Missing one of these could have dramatic, and cause the whole applications to. In addition, the application could get very lengthily. The solution to this problem is to functions. Functions in C# are a means of providing blocks of code that can be executed at any point in an application. Functions of the specific type we are considering in this chapter are known as methods. However, this term has a very specific meaning in, Net programming that will only become clear later in the book, so for now well avoid the use of this term. For example we could have a function that calculates the maximum value in an array. We can use this function from any point in own code, and use the same lines of code in each case. Since we only need to sunny this one any changes we make to its will affect this calculation whenever it is used. This function can to thought of as containing reusable code. Functions also have the advantage of making over code more readable, as we can use then to related code together. If we do this then own application body it can be made very short, as the inner workings of the code are set out. This is similar to the way in
199
which we can collapse regions of code together in visual studio. Net using the outline, view, and gives a mare logical structure to own application. Functions can also be used to create multi purpose code, allowing them to perform the same operations on varying data. We can supply a function in the form of return values. In the above example, we could supply a way to search as a parameter and obtain the maximum value in the array as a return value. This means that we can use the same function to work with a different array time. Two parameters and return value of a function collectively define the signature of a function. In this chapter well start by looking at the way in which we can define and use simple functions that dont accent on return and data. After this well move on to look at the way in which we active transfer of data to and form functions. Next well take a book at the issue at variable scope. This concerns the way in which data in a C# application is localized to specific regions of code an issue that becomes especially important when we are separating own code into multiple functions. After this, well take an in depth look at an important function in
C# applications main well see how are can use the built in behavior of this function to make use of command line arguments which enable us to transfer information into applications when we run them. Next, well take a look at an additional features of the struct type that we saw in the last chapter, the fact that you can supply functions as members of strut types.
Finally well turn own attention to two more advanced topics: 1. 2. Function own loading Delegates.
Function over loading is a technique that allows us to provide multiple functions with the safe none but different signatures. A delegate is available type that allows us to used
All Rights Reserved To EaglesGroup
200
functions indirectly. The same delegate can be used to call any function that matches a specific signature, giving the us the ability to choose between several functions at run time.
Example Try it out Eagles BasicFunction Step by Step Example: Using Version 2005
1. Create a new Console application name it as Eagles BasicFunction in the directory C:\EaglesVisualCSharp\Chapter 5 Function\Example Defining and Using a basic Function 2. Add the following code in the Program.cs as follows: namespace Eagles_BasicFunction { # region EaglesGroup /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program static void Siddhu() { Console.WriteLine("Welcome to EaglesGroup!"); }
201
3. Now Run the program and you should have the output like this:
Now lets see how the above program works: The following four lines of our code define a function called Write ();
The code contained here simply outputs some text to the Console window. However, this behavior isnt that important to us at the moment, as were more concerned with the mechanisms behind function definition and use.
202
The function definition here consists of the following: Two keywords, static and void. A function name followed by parentheses, Write (). A block of code to execute enclosed in curly braces. The code that defines the Write () function looks very similar to the other code in our application: Static void Main (string [] args) { . }
This is because all the code we have written so far apart from type of a function. This function, Main (),is a suggested by the comment in the auto generated code the entry contains is called, and when this function completes the application terminates. All the C# executable code must have an entry point. The only difference between the main ( ) function and our writes ( ) function (apart form the liner of code they contain), is that there is some code inside the parentheses after the function name main. This is how we specify parameters, which well discuss in more detail shortly. As mentioned above, both main ( ) and write ( ) are defined using static and void keywords. The static keyword relates to object oriented concepts, which well come back to later in the book. For, now you only need to remember that all the functions well use in own applications in this section of the book must use this keyword. Void, on the other hand is much simpler to explain. This keyword is to indicate the function does not return a value. Later on in this chapter, well see. What we need to write when a function has a return value. Moving on, the code that calls our function is as follows: Siddhu();
203
We simply type the name of the function followed by empty parentheses. When program execution reaches this point the code in the Write () function will run.
DENOTE: That the parentheses used, both in the function definition and where the function is called, are mandatory. Try removing them if you like the code wont compile.
Alternatively, we might have a function called get Val ( ) that returns a double valve, which we could use in a mathematical expression: Double my val ; double multiplier = 5.3 Myval = get val ( ) * multiplier ;
204
When a function in two ways: Specify the type of the return valve in the function declaration instead of using the void keyword. Use the return keyword to end the function execution and transfer the return value to the calling code. In code terns this looks like the following in a console application function of the type weve been looking at: Static < return type > < function name > ( ) { return < return valve >; }
The only limitation here is that < return valve > most be a valve that is either of type < return type > as can be implicitly converted to that type. However, < return type > can be type we want, including the more complicated types well see. More complicated types weve see. This might be as simple as:Static double get val ( ) { return 3.2 ; } But, wait ; However value are usually the result of some processing carried out by the function; as the above could be achieved just as easily by using a cost variable.
205
When the return statement reached the program execution return, to the calling code immediately, No lines of code after this statements will be executed. However this doesnt mean that return statements can only be placed on the last line of a function body. We can use return earlier in the code, perhaps after performing some branching logic. Placing return in for loop and it block, or any other structure causes the structure to terminate immediately and the function to terminate for example. Static double getVal ( ) { double checkVal ; //checkVal assigned a valve through some logic if (checkVal < 5) return 4.7; return 3.2; }
Here one of two values may be returned depending on the value of checkVal. The only restriction here is that a return statement must be processed before reaching the closing } of the function. The following is illegal:Static double getVal ( ) { double checkVal ; // checkVal assigned a valve through some logic if (checkVal < 5) return 4.7; }
206
If checkVal is > = 5 then no return statement is met, which isnt allowed. All processing paths must reach return statements. As a final note, return can be used in functions declared using the void keyboard that dont have return value. If we do so, then the function will simply terminate. When we so return in this was, it is an error to provide to return valve in between the return keyword and the semicolon that follows.
5.3 Parameters
When a function is to accept parameter, we must specify the followings: A list of the parameters accepted by a function in its definition, along, with the type of those parameters. A matching list of parameters in each function call. We can have any number of parameter, each with a type and a name. The parameters are separated using commas. Each of these parameters is accessible from code within the function as a variable. For example, a simple function might take two double parameters and return their product:
Static double product (double param1, double parm2) { Return param1 * param2; } Lets work it out Using Exchanging Data with a Function
Example Try it out Eagles ExchaningFunction Step by Step Example: Using Version 2005
207
1. Create a new Console Application and name it as Eagles ExchaningFunction in the directory C:\EaglesVisualCSharp\Chapter 5 Function\Example Using Exchanging Data with a Function 2. Add the Following code in the Program.cs namespace Eagles_ExchaningFunction { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGrpoup> # endregion class Program { static int MaxValue (int [] intArray) { int maxVal = intArray [0]; for (int i = 1; i < intArray.Length; i++) { if (intArray [i] > maxVal ) maxVal = intArray [i]; } return maxVal ; } static void Main(string[] args) { int[] myArray = {0, 4, 2, 7, 2, 3, 1, 7, 3, 4, 3}; int maxVal = MaxValue (myArray ); Console.WriteLine ("The Maximum value in myArray is {0}", maxVal ); } }
208
3. Now run the program and you will have output like this:
Now lets see how the above code works: This code contains a function that does what the example function discussed in the introduction to this chapter hoped to do, It extents an array of integers as a parameter and returns the highest number in the array. The function definition is as follow: static int MaxValue (int [ ] intArray) { int maxVal = intArry [ 0 ]; For (int i = 1; i < intArray. Length ; i++ ) { if ( intArray [ ; ] > maxVal) maxVal = intArray [ i ] ; } return maxVal ; }
209
The function, MaxValve ( ), has a single parameter defined, an int, and array called int Array. It also is a return type of int. The calculation of the maximum valve is simple. A local integer variable called Max Val is initialized to the first valve in the array, and them Max Val, then this valve replaces the current valve of Max Value. When the loop finisher, Max Val contains the highest valve in the array, and is returned using the return statement. The code in Main ( ) declare and initializes a simple integer array to use with the Max Valve ( ) function: int[] myArray = {0, 4, 2, 7, 2, 3, 1, 7, 3, 4, 3}; The call to Max valve ( ) is used to assign a value to the int variable maxVal. int maxVal = MaxValue ( myArray ) ;
Next, we write thin value to the scan using Console.WriteLine (); Console.WriteLine (the maximum value in myArray is {0}; minVal}).
210
Here we are attempting to pass a double value, as the first parameter and a string valve as the second parameter, which is not the order is which the parameters are defined in the function definition. We also cant use: myFunction ( Hello) ;
Here we are only passing a single string parameter, where two parameters are required. Attempting to use either of the two function calls above will result in a combine error, as the compliers force us to match the signature, of the functions we use. Going back to our example, this means that MaxValue ( ) can only be used to obtain the maximum int in an array of int values. If we replace the code in main ( ) with the following code: static void Main (string [ ] args ) { double [ ] myArray = { 1, 3, 8, 9, 3.3, 6.5 } ; double maxVal = Max Value (myArray ) ; Console.WriteLine (The maximum value in myArray is {0} , maxVal); }
211
212
Here firstWord will be assigned the string this . string first word = getWord ( this is a sentence );
We might add a params parameter to getWord ( ) allowing us to optionally select alternative word to return by its index; String first word get word (This is a sentence., 2 );
We might also add the capability to limit the amount of characters returned in a third parameter, also accessible through the params parameter; string firstWord = getWord (Welcome to EaglesGroup, , 4, 3);
Here first word would be assigned the string siddhu. Lets work it out Using Exchanging Data with a Function Part2
Example Try it out Eagles ExchaningFunction2 Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles ExhchaningFunction2 in the directory C:\EaglesVisualCSharp\Chapter 5 Function\Example Using Exchanging Data with a Function Part2 2. Add the following code in the program.cs as follows:
213
namespace Eagles_ExchaningFunction2 { # region EaglesGroup Console Application /// <summary> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </summary> # endregion class Program { static int sumValue(params int[] vals) { int sum = 0; foreach (int val in vals) { sum += val; } return sum; } static void Main(string[] args) { int sum = sumValue (0, 5, 0, 9, 1, 9, 8,5); Console.WriteLine ("Summed Values = {0} ", sum ); } }
214
3. Run the program and you will have the output like this:
Now lets see how the above code works: In this example, the function sumVals ( ) is defined using the params keyword to account any number of int parameters (and no other); static int sumValue(params int[] vals) { }
The code in this function simply iterates through the value in the vals arrays, and adds the valves, together, returning the result. In main ( ) w, call this function with five integer parameters:-
215
However, we could just as easily have called this function with none, one, two, on a hundred integer parameters there is no limit to the amount we can specify.
Here the parameter, val is doubled in this function. If we call it in the following way; int my number = 5, Console.WriteLine (myNumber = {0}, myNumber); showDouble (myNumber ) Console.WriteLine (myNumber = {0}, myNumber);
216
My number = 5 val doubled = 10 my number = 15 Calling showDouble ( ) with my number as a parameter doesnt affect the vale of my number in main ( ), even through the parameter it is assigned to, val is doubled. This is all very well, but it if we want the valve of my number to change we have a problem. We could a function that returns a new valve for my number, and call it using.
It my number = 5 console writeline ( my number = { 0 }, my number ); my number = show double (my number); But this code is hardly intuitive and wont code with changing the value of multiple variable used as parameters as function have only one return value). Instead, we want to pass the parameter by reference. This means that the function will wont with exactly the same variable as the one used in the function call, not just a variable that has the same value. Any changes made to this variable will, therefore, be reflected in the value of the variable used as a parameter. To do this we simply have louse the ref keyword to specify the parameters. static void show double ( int val) {
217
And again in the function call (this is mandatory, as the fact that the parameter is ref parameter is part of the function signature) int my number = 5; console writeline ( my number = { 0 } my number ) showDouble (ref myNumber); Console.WriteLine (val doubled = {0}, val); Text output of the above code myNumber = 5 val doubled = 10 myNumber = 10
This time my number has been modified by showDouble ( ) There are two limitation on the variable used as a ref parameter. First, the function may result in a change to the value of a reference parameter so we must use a non-constant variable in the function all The following in therefore illegal const int my number = 5, Console.WriteLine (my number {0} my number) showDouble (ref my number) Console.WriteLine (my number = {0}
Second we must use an initialized variable doesnt allow is to assume that a ref parameter will be initialized in the function that use it. The following code is also illegal
218
int myNumber show double (ref myNumber ) Console.WriteLine (my number = { 0 } myNumber )
219
static int. maxValue (int. [ ] intArray, out int maxIndex) { int maxVal = intArray [0]; for (int i = 1; i intArray, Length i++) { if (int Array [i] maxVal) { maxVal = int Array [i] max Index = i; } } return maxVal; } We might use this function as follows: int [ ] my Array = { 1,8,3,6,2,5,9,3,0,2,} int max Index;
Console.WriteLine (The maximum value in my Array is {o} Maxvalue (my Array; o9ut max Index),} Console, write line (The first occurrence of this value is at element {o}; max Index +) The result is:
The maximum value in my Array is a The first occurrence of this value is at element 7
An important point to note here is that we must use the out key word in the function call, just as with the ref keyword.
220
Example Try it out Eagles DefiningbasicFunction Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles DefiningbasicFunction in the directory C:\EaglesVisualCSharp\Chapter 5 Function\Example Using Defining and using a basic Function 2. Add the Following code in the Program.cs as follows:
namespace Eagles_DefiningbasicFunction { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1979 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { static void Eagles() { Console.WriteLine("myString = {0}", myString); } static void Main(string[] args) { string myString = "String defined in Main ()" + " This is more fun haha"; Eagles(); } }
221
3. Now run the Program and you should have the Following error as follows:
Now let see how the above program works and what went wrong? So, what went wrong? Well, the variable myString defined in the main body of our application the Main () function isnt accessible from the Eagles () function. The reason for this inaccessibility is that variables have a scope within which they are valid. This scope encompasses the code block that they are defined in and any directly nested code blocks. The blocks of code in functions are separated from the blocks of code from which they are called. Inside Eagles () the name myString in undefined, and the myString variable defined in Main () is out of the scope it can only be used from witching Main () In fact, we can have a completely separate variable in write ( ) called my string. Try modifying the code as follows: amespace Eagles_DefiningbasicFunction { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1979 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup>
# endregion class Program { static void Eagles() {
string myString = "String defined in Eagles () " + "This is the Proper "; Console.WriteLine("Now in Eagles()"); 222
All Rights Reserved To EaglesGroup
Console.WriteLine("myString = {0}", myString); } static void Main(string[] args) { string myString = "String defined in Main ()" + " This is more fun"; Eagles(); Console.WriteLine("\nNow in Main()"); Console.WriteLine("myString = {0}", myString);
4. Now Build the program and run the application and the program will run and you will see the output like this:
223
Main ( ) defines and initializes a string variable called my string. Main ( ) transfers control to write ( ) Write ( ) defines and initializes a string variable called my string, which is a different variable to the my string defined in main ( ) write ( ) outputs a string to the console containing the value of my string as defined in write ( ) Write ( ) transfer control back to main ( ) Write ( ) transfer control back to main ( ) Main ( ) out puts a string to the console containing the values of my string as defined in main ( ) Variables whose scope covers a single function in this way are knows as local variable. It is also possible to have global variables, whose scope covers multiple functions. Modify the code as follows:namespace Eagles_DefiningbasicFunction { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1979 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { static string myString; static void Eagles() { // string myString = "String defined in Eagles () " + "This is the Proper "; string myString = "String defined in Eagles()"; Console.WriteLine("Now in Eagles()"); Console.WriteLine("myString = {0}", myString); Console.WriteLine("Global myString = {0}", Program.myString); }
All Rights Reserved To EaglesGroup
224
static void Main(string[] args) { //string myString = "String defined in Main ()" + " This is more fun"; string myString = "String defined in main()"; Program.myString = "Global string"; Eagles(); Console.WriteLine("\nNow in Main()"); //Console.WriteLine("myString = {0}", myString); Console.WriteLine("Local myString = {0}", myString); Console.WriteLine("Global myString = {0}", Program.myString);
} Now run this program and the output will be like this:
Here we have added another variable called my string, this time further up the hierarchy of names is the code. This variable is defined as follows: static string myString;
225
DENOTE: That again we require the static keyword have. Again, Im not going to say any more about this at this paint other than that in console applications of this form we must use either the static an const keyword for global variables of this form. It we want to modify the value of the global variable we need to use static, as const prohibits the value of the variable changing. In order to different between this variable and the local variables in main ( ) and write ( ) with the same name, we have to classify the variables name using a fully qualified name, as introduced in last 2 chart, Here we refer to the global version as Program. myString. Note that this is only necessary when we have global and local variables with the same name, if there was no local my string variable, we could simply use my string to refer to the global variable, rather than Program.myString. When we have a local variable is said to be hidden. The value of the global variable is set in Main ( ) with! Program.myString = "Global string";
And accessed in write ( ) with! Console.WriteLine("Local myString = {0}", myString); Console.WriteLine("Global myString = {0}", Program.myString);
Now you may be wondering why we shouldnt just uses this techniques to exchange data with functions rather than the parameter passing we saw earliest; there are indeed situations where this is the preferable way to exchange data, but there are just as many if not more where it isnt.
226
227
This code will also fail. The reason for this is that variables must be declared and be initialized before use, and text is only animalized in the for loop. The value assigned to text is lost when the loop block is exited. However we can also make the following change:int. i; String text = , For (i = o; i 10; i ++) { text = Line + convert, To string (i); Console write Line (Last text output in loop; {o}, text);
This time text initialized outside of the loop, and we have access to its value. The result of this simple code is shown in the following screen short:-
For the above program in the CD Refer the Following Path: \\EaglesVisualCSharp\Chapter 5 Function\Example Using Defining and using a basic Function\ EaglesGroupText Here the last value assigned to text in the loop is accessible from outside t he loop.
228
As you can see, this tonic require a bit of wore to get grins with. It is not immediately obvious why in the light of the earlier example, text, doesnt retain the empty string it is assigned before the loop in the code after the loop. The explanation for this behaviors concerns the memory allocation for the text variable, and indeed and variable. Simply declaring a simple variable type doesnt result in very much happening. It is only when values are assigned to the variable that values are allocated a place in memory to be stored. When this allocation takes place inside a loop, the value is essentially defined, as a local value, and goes out of scope outside of the loop. Even though the variable itself is not localized to the loop, the value it contains is. However, assigning a value outside of the loop ensures that the value is local to the main code, and is still in scope inside the loop. This means that the variable doesnt goose of scope before the main code block is existed. So we have access to its value outside of the loop. Luckily for us, the c compiles, will detect variable scope problems, and responding to the error messages it generator certainly helps us to understand the tonic of variable scope. As a final note, we should turn to best practice In general; it is worth declaring and initialing all variables before using them in any code blocks. An exaction to this is where we declare looping variables as part of a loop block example. For (int. i = o; 10; i++ ) { }
Here is localized to the looping code block, but this is fire as we will rarely require access to this counter from external code.
229
230
static void showDouble () { val *= 2; Console.WriteLine ("val doubled = {0}", val ); } static void Main(string[] args) { val = 5; Console.WriteLine("val = {0}", val); showDouble(); Console.WriteLine("val = {0}", val); } The result of the above both program showDouble () function is same and the screen shot as follows:
231
Now, there are no hard and fast rules for using one method rather than another, and both techniques are perfectly valid. However there are some guideline you might like to consider. To start with, as to mentioned when we first introduced this tonic, He show Double ( ) version that uses the global value will only use the global variable val, In order to use t his version, we must use this global variable. This limits the versatility of the function slightly, and means that we must continuously copy the global variable value into other variables if we intend on storing results, In addition, global data might be modified by code elsewhere in our application, which could cause unpredicted results (Values might change without us realizing until too late) Finally, it should be remembered that using global data isnt always possible. Later on in the boo,, we will see code writer in different files and / or belonging to difficult namespace communicating with each other via functions. In such case this. He code is often separated to such a degree that there is no obvious choice for a global storage location. So, to summarize, feel free to use either technique to exchange data. I would in general, urge, you to use parameters rather than global data, but there are certainly cases where global data might be more suitable, and it certainly isnt an error to use this technique.
232
DENOTE: That there are four possible signatures that we can use for the main ( ) Function, static void Main ( ) static void main (string [ ] orgs) static int main ( ) static int main (String [ ] orgs) We can, if we wish, omit the args argument discussed her. The reason weve used the version with this argument up till now, is that it is the version that is generated automatically for us when we create a console application in visual studio (VS) The may well have come across command line parameters already. When we execute an application from the command Line we are often able to specify information directly such as a file to load an application execution. As an example, consider the notepad application in windows. We can run this application simply by ***** Notepad in a command prompt window, on in the window that appears when we select the run option from the windows start menu. We can also type something like notepad my file.txt in there locations. The result of this is that notepad will load the file myfile.text when it runs, us or offer to create this file if it doesnt already exist. Here, myfile.txt is a command line argument. We can unite console application that worm in much the same way by making use of the args parameter. When a console application is executed any command line parameters that are specified are placed in this args array. We can then use these parameters in our application as required. Lets work it out Using Command Line Arguments
Example 5-5 Using Command Line Arguments Example Try it out Eagles CommandArguments
233
1. Create a new Console Application and name it as Eagles CommandArguments in the directory C:\EaglesVisualCSharp\Chapter 5 Function\Example Using Command Line Arguments 2. Add the following code in the Program.cs as follows:
namespace Eagles_CommandArguments { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { static void Main(string[] args) { Console.WriteLine("{0}command line arguments were specified;", args.Length); foreach (string arg in args) Console.WriteLine(arg); } } 3. When you run the Program it will have the output like this:
234
But this is not the output we are excepting 4. Now open the property page of the Eagles CommandArguments in the Solution Explorer window and select Properties. 5. Select the Configuration Properties | Debugging and add what ever command line argument you want to the Command Line Argument setting as shown in the below screen shot:
6. Run the application and you will get the output as shown in the above command prompt Now lets see how the above program works: The code used here is very simple Console.WriteLine("{0}command line arguments were specified;", args.Length); foreach (string arg in args) Console.WriteLine(arg);
235
We are just using the args parameter like we would any other string array. Were not doing anything ferry with the arguments. Were just writing whatever is specified to the screen. In this example, we supplied the arguments via the project properties dialog in VS. This is a handy way of using the same command line arguments when ever you run the application from VS rather than having to type them at a command Line prompt every time. The same result as above could be obtained by opening a command prompt every time. The same result as above could be obtained by opening a command prompt window in the same directory as the project output. Note that each argument is separated from the next by spaces, but we can also enclose arguments this is necessary if the argument includes spaces. So as not to be interpreted as multiple arguments.
236
customer Name my customer my customer, First Name = Siddhu my customer, last Name = Eagle console. write line ({ o } { 1 }, my customer, First Name, my customer, last Name); By adding function to structs, we can simplify this by centralizing the processing of common tasks such as this; we can add a suitable function to the struct type as follows: struct customer Name { Public string firstName, lastName { return first Name + + Last Name; } }
This looks much like any other function weve looked at in this chapter, expert that we havent used the static modifies. The reasons for this will become clear later in this book, for now it is enough to know that this keyword isnt required for struct functions. We can use this function as follows. Customer Name my customer my customer, first Name = Siddhu; my customer, Last Name = eagle Console Write Line (my customer, Name )
This syntax is much simples, and much easier to understand, than the earlier one.
237
An important paint to note here is that the name ( ) function has direct access to the first Name and last Name struct members. Within the customer Name struct they can be thought of as global.
238
class Program { static int MaxValue(int[] intArray) { int maxVal = intArray[0]; for (int i = 1; i < intArray.Length; i++) { if (intArray[i] > maxVal) maxVal = intArray[i]; } return maxVal; } static void Main(string[] args) { int[] myArray = { 1, 8, 3, 6, 2, 5, 9, 3, 0, 2 }; int maxVal = MaxValue(myArray); Console.WriteLine ("The maxium value in myArray is{0}", myVal); }
This function can only be used with arrays of int values. Now, we could provide different parameter types, perhaps renaming the above function such as Double Array Max value ( ) to work with other types. Alternatively, we could just add the
239
class Program { static double MaxValue(double[] doubleArray) { double maxVal = doubleArray[0]; for (int i = 1; i < doubleArray.Length; i++) { if (doubleArray[i] > maxVal) maxVal = doubleArray[i]; } return maxVal; }
The different here is that we are using double values. The function name. Max Value ( ), is the same, but (crucially) its signature is different. It would be an error to define two functions with the same name and signature, but since these two functions have different signatures, this is file. The beauty of this type of code is that we dont have to explicitly specify which of these two functions we wish to use. At this point, it is worth nothing another feature of the IntelliSence feature in Visual Studio .NET. If we have two function shown above in an application, and then proceed to type the name of the function in for example Main (), Visual Studio.NET will show us the available overloads for the function. If we type the following:
Visual Studio .NET gives us information about both version of MaxValue (), which we can scroll between using the up and down arrow keys:
240
All aspects of the function signature are included when overloading functions. We might, for example, have two different functions that take parameters by value and by reference respectively. static void showDoubwl (ref int val) { ... }
The choice as to which of these versions to use is based purely on whether the function call contains the ref keyword. The Following would call the reference versions: showDouble(ref val);
And the following would cal the value versions: showDouble( val);
241
5.10 Delegates
A Delegate is a type that enables us to store references to functions. Although this sounds quite involved, the mechanism is surprisingly simple. The most important purpose of delegates wont become clear until later in this book when we look of event and even handling, but we can get a fair amount of mileage by looking at delegates her. When we come to use them later on theyll look familiar, which will make some more complicated topics a lot easier to comprehend. Delegates are declared much like functions, but with no function body and using the delegate key word. The delegate declaration sacrifices a function signature consisting of a return type and the parameter list. After defining a delegate we can declare a variable with the type of the delegate. We can than initialize this variable tope a reference to any function that has the same signature as that delegate, once we have done this we can call that function by using the delegate variable as if is were a function. We have a variable that refers to a function we can also perform other operations that would be impossible by other means, for example, we can pass a delegate variable to a function as a parameter, then that function can use the delegate to call whatever function it refer, to without having knowledge, as to what function will be called until runtime. Lets have an example. Lets work it out Using a Delegate to Call a Function
Example 5-6 Using a Delegate to Call a Function Example Try it out Eagles DelegateFunction
242
namespace Eagles_DelegateFunction { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { delegate double processDelegate(double param1, double param2); static double Muiltiply(double param1, double param2) { return param1 * param2; } static double Divide(double param1, double param2) { return param1 / param2; } static void Main(string[] args) { processDelegate process; Console.WriteLine("Enter 2 number seperated with a comma:"); string input = Console.ReadLine(); int commaPos = input.IndexOf(','); double param1 = Convert.ToDouble(input.Substring(0, commaPos)); double param2 = Convert.ToDouble(input.Substring(commaPos + 1, input.Length - commaPos - 1)); Console.WriteLine("Enter M to mui;ltiply or D to divide:"); input = Console.ReadLine(); if (input == "M") process = new processDelegate(Muiltiply); else process = new processDelegate(Divide); Console.WriteLine("Result:{0}", process(param1, param2)); }
243
3. Now Execute the code and you will have the output like this:
Now lets see how the above code works: This code defines a delegate (Process Delegate) whose signature matches that of the two functions (multiply ( ) and Divide ( )). The delegate designation as follows:delegate double processDelegate(double param1, double param2);
The delegate keyword specifies that the definition is for a delegate, rather than a function the definition appears in the same place as a function definition might Next, we have a signature that specifies a double return value and, two double parameter. The actual names used are arbitrary, so we can call the delegate type and parameter name whatever we like, here, weve used a delegate name of process Delegate and double parameters called param1 and param 2. The code in main ( ) stars by declaring a variable using our new delegate type:static void Main(string[] args) { processDelegate process;
244
Next, we have some fairly standard C code that requests two numbers separated by a comma and places these numbers in two double variables:Console.WriteLine("Enter 2 number seperated with a comma:"); string input = Console.ReadLine(); int commaPos = input.IndexOf(','); double param1 = Convert.ToDouble(input.Substring(0, commaPos)); double param2 = Convert.ToDouble(input.Substring(commaPos + 1, input.Length - commaPos - 1)); Console.WriteLine("Enter M to mui;ltiply or D to divide:"); input = Console.ReadLine(); if (input == "M") process = new processDelegate(Muiltiply); else process = new processDelegate(Divide); Console.WriteLine("Result:{0}", process(param1, param2)); DENOTE: That far demonstration purposes, Ive included no user input validation here. If this were real code, wed spend much more time ensuring that we get valid in the local param 1 and Param 2 variables. Next we ask the user whether to multiply or divide these numbers:Console.WriteLine("Enter 2 number seperated with a comma:"); string input = Console.ReadLine(); Based on the user choice us initialize the process delegate variable:if (input == "M") process = new processDelegate(Muiltiply); else process = new processDelegate(Divide); Console.WriteLine("Result:{0}", process(param1, param2)); To assign a function reference to a delegate variable, we use slightly add looking syntax. Much like assigning array values, we must use the new keyword to create a new delegate.
245
After this keywords we specify the delegate type and supply a parameter referring to function we want to use, namely the multiply ( ) or Divide ( ) function. That this parameter doesnt match the parameters of the delegate type or the target function, it is syntax unique to delegate assignment. The parameter is simply the name of the function to use, without any parentheses. Finally, we call the chosen function using the delegate. The same syntax works here, regardless of which function the delegate refers to. Console.WriteLine("Result:{0}", process(param1, param2));
Here, we treat the delegate variable just as if it were a function name. Unlike function, however, we can also perform additional operations on this variable, Such as passing it to a function via a parameter. A simple example of such a function might be:Static void execute Function (process Delegate Process) { Process (2.2, 3.3); }
This means that we can control the behavior of functions by passing them function delegates, much like choosing a Snap-in to use. Fro example, we might have a function that sorts a string array alphabetically. There are several methods of sorting lists with varying performance depending on the characteristics of the list being sorted. By using delegates, we could specify the method to use by passing a sorting algorithm function delegate to a sorting function. There are many such uses for delegates, but as mentioned earlier, their most prolific use is in event handling. Well come to this subject late we will discuss.
246
Summary: In this character, weve seen a fairly complete overview of the use of functions in C code. Much of the additional features that function often (delegates in particular) are more abstract, and well only need to discuss them in the light of object oriented programming, which is a subject that well be discussing very soon. To summarize what has been covered in this chapter. Define and using functions in console applications Exchanging data with functions via return values and parameters Parameter arrays Passing Values by reference or by value Specifying out parameter for additional return values. The concept of variable scope Details of the main ( ) Function, including command line parameter usage Using functions in struct types Function overloading Delegates
247
Chapter 06
248
249
In this section, well take a look at these techniques and how we can use them to identify and fix those areas of code which do not work as expected, a process more commonly know as debugging. Well divide up the techniques into two sections by the way in which they are used. In general, debugging is performed either by interrupting program execution or by making notes for later analysis. In Visual Studio.NET terms, an application is either running or is in break mode, that is normal execution is halted. Well look at the non break mode runtime or normal technique first.
250
The above code snippet shows how we can give extra information concerning a function called Eagles (). Doing this is all very well, but can make console output a bit cluttered. Ad an alternative, we can output text to a separate location the Output window in Visual Studio.NET Back in the Chapter 1 we took a quick look at the Output window, which is by default located at the bottom of the Visual Studio environment, sharing space with the Task List window, we saw how this window displays information relating to the compilation and execution of code, including errors encountered during compilation and so forth... We can also use this window to display custom diagnostic information by writing to it directly. We can see this window in the screen shot below:
DENOTE: That the above window in the output has three modes that can be selected using the drop down it contains. We can toggle between Build, Debug, and Test Run mode. The Build and Debug mode show us compilation and run time information respectively.
251
Alternatively, we might want to create a logging file, which would have information appended to it when our application is executed. The technique for doing this are much the same as for writing text to output window, although it requires an understanding of how to access the file system from C# applications. For now, well leave this function on the back, as there is plenty we can do without getting bogged down by file access techniques.
252
Example Try it out Eagles TextOutput Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles TextOutput in the directory C:\EaglesVisualCSharp\Chapter 6\Example Writing Text to the OutPut Window\Eagles TextOutput 2. Enter the following code in the using directive: using System; using System.Collections.Generic; using System.Text; using System.Diagnostics;
3. Now enter the following code in the Program.cs : namespace Eagles_TextOutput { # region EaglesGroup Console Application /// <summary> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </summary> # endregion class Program {
All Rights Reserved To EaglesGroup
253
static void Main(string[] args) { int[] EaglesArray = { 0, 4, 2, 7, 2, 3, 1, 7, 3, 4, 3 }; int[] maxValIndices; int maxVal = Maxima(EaglesArray, out maxValIndices); Console.WriteLine("Maximum value {0} found at element indices:", maxVal); foreach (int index in maxValIndices) { Console.WriteLine(index); } }
static int Maxima(int[] integers, out int[] indices) { Debug.WriteLine("Maximum value search started."); indices = new int[1]; int maxVal = integers[0]; indices[0] = 0; int count = 1; Debug.WriteLine("Mximum value intilized to " + maxVal + " at element index 0."); for (int i = 1; i < integers.Length; i ++) { Debug.WriteLine ("Now looking at element at index "+ i + "."); if (integers [i] > maxVal )
254
{ maxVal = integers [i]; count = 1; indices = new int [1]; Debug.WriteLine ("New maximum found. new valiues is " + maxVal + ", at elemt index" + i +"."); } else { if (integers [i] == maxVal ) { count ++; int [] oldIndices = indices ; indices = new int [count ]; oldIndices.CopyTo (indices , 0); indices [count - 1] = i; Debug.WriteLine ("Duplicate maximum foud at elemt index" + i + "."); } } } Trace.WriteLine("Maximum value:" + maxVal + "found, with " + count + "occurrences."); Debug.WriteLine("Maximum value search completed."); return maxVal; }
4. Now run the program in the debug mode and you will see the output like this:
255
5. Now exit the application, and look at the contents in the output window while in debug mode which will created the following: 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorli b.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Uti lities\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities .dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c5 61934e089\System.Windows.Forms.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\Syste m.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3 a\System.Drawing.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Uti lities.Sync\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Ut ilities.Sync.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\EaglesVisualCSharp\Chapter 6\Example Writing Text to the OutPut All Rights Reserved To EaglesGroup 256 Window\Eagles TextOutput\Eagles TextOutput\bin\Debug\Eagles TextOutput.vshost.exe', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread 0x62c has exited with code 0 (0x0). The thread 0x5f0 has exited with code 0 (0x0). 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\EaglesVisualCSharp\Chapter 6\Example Writing Text to the OutPut Window\Eagles TextOutput\Eagles TextOutput\bin\Debug\Eagles TextOutput.exe', Symbols loaded. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3 a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. Maximum value search started. Mximum value intilized to 0 at element index 0. Now looking at element at index 1. New maximum found. new valiues is 4, at elemt index1. Now looking at element at index 2. Now looking at element at index 3. New maximum found. new valiues is 7, at elemt index3. Now looking at element at index 4. Now looking at element at index 5. Now looking at element at index 6. Now looking at element at index 7. Duplicate maximum foud at elemt index7. Now looking at element at index 8. Now looking at element at index 9. Now looking at element at index 10. Maximum value:7found, with 2occurrences. Maximum value search completed. The thread 0xd74 has exited with code 0 (0x0). The thread 0xd80 has exited with code 0 (0x0). The program '[1900] Eagles TextOutput.vshost.exe: Managed' has exited with code 0 (0x0).
257
6. Now Change to Release mode using the drop down menu on the Standard toolbar:
7. Now again run the program but this time you r running it in the Release mode, and take a another look at the output window when the program is executed: Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\msc orlib.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess. Utilities\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess. Utilities.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a 5c561934e089\System.Windows.Forms.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\Sy stem.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d5 0a3a\System.Drawing.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
258
'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities.Sy nc\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\EaglesVisualCSharp\Chapter 6\Example Writing Text to the OutPut Window\Eagles TextOutput\Eagles TextOutput\bin\Release\Eagles TextOutput.vshost.exe', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Dat a.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System.Xml\2.0.0.0__b77a5c561934e089\System. Xml.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. The thread 0xe04 has exited with code 0 (0x0). 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\EaglesVisualCSharp\Chapter 6\Example Writing Text to the OutPut Window\Eagles TextOutput\Eagles TextOutput\bin\Release\Eagles TextOutput.exe', Symbols loaded. 'Eagles TextOutput.vshost.exe' (Managed): Loaded 'D:\WINDOWS\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3a\ System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. Maximum value:7found, with 2occurrences. The thread 0x990 has exited with code 0 (0x0). The thread 0x9fc has exited with code 0 (0x0). The program '[1800] Eagles TextOutput.vshost.exe: Managed' has exited with code 0 (0x0).
259
Now lets see how the above code works and what happen out there lets see now:
This Program return an array of the indices where maximum values are found in an array, so that the calling code can be manipulated these elements The additional using directive appears at the start of the code it because it simplifies access to the functions discussed above this example, as they are contained in the Sys using System; using System.Collections.Generic; using System.Text; using System.Diagnostics;
Without the above highlighted using directive, we would not be able to code such as: Debug.WriteLine("Maximum value search started.");
Even we can rewrite the following code as follows: System.Diagnostics.Debug.WriteLine("Maximum vale search stated");
The using directive keeps our code simple and reduces verbosity. The code in the Main () simply initializes a test array of integers called EaglesArray; it also declares another integer array called maxValIndices to store the index output of Maxima () the function that performs the calculation, then calls this function. Once the function returns, the code simply outputs the result. Maxima () is slightly more complicates, but doesnt use much code that we havent already seen. The search through the array is performed in similar way to the MaxVal () function in the example.
260
Perhaps the key point to note in the code other than those lines that output debugging information is the function used to keep track of the indices. Rather then returning an array that would be large enough to store every index in the source array needing the same dimensions as the source array, Maxima () returns an array just large enough to hold the indices found. It foes this by continually recreating arrays of different sizes as the search progresses. This is necessary as array cant be resized once it has been created. To start with, the search is initialized by assuming that the first element in the source array called integers locally is the maximum value, and that there is only one maximum value in the array. Values can, therefore be set the for maxVal the return value of the function, and the maximum values found and indices, the out parameters array that stores the indices is assigned a single value, simply 0, which is the index of the first element in the array. We also store the number of maximum values found in a variable called count, which allows the program to keep track of the indices array. The main body of the function is a loop that cycle thought the values in the integer array, omitting the first one as this has already been processed. Each value is compared to the current value of maxVal, and ignored if maxVal is greater. If the currently inspected array value is greater then maxVal then maxVal and indices are changed to reflect this. If the value is equal to maxVal then count is incremented and a new array is substituted for indices. This new array is one element bigger than the old indices array, contain the new index found. f (integers [i] > maxVal ) { maxVal = integers [i]; count = 1; indices = new int [1]; Debug.WriteLine ("New maximum found. new valiues is " + maxVal + ", at elemt index" + i +"."); } Through out the code, various pieces of text are output using the Debug.WriteLine () and Trace.WiteLine () functions. The end result of this when running in the debug mode is a completer recode of the steps taken in the loop that give us our result. In release mode, we just see the end result of the calculation as no Debug.WriteLine () functions work. But the old indices array into oldIndices it is because of backing up the ole indices, an integer array local to this if code block, that the value is oldIndices are copied into the new indices array using the oldIndices.CopyTo (indices , 0); . this Function simply takes a target array and index to use for the first element to copy to, and pastes all the values into the target array.
261
As well as these WriteLine () functions there are few more we should be aware of it. To start with, these are equlavent to Console.Write (); Debug. Write(); Trace.Write(); Both these functions use the same syntax as the WriteLine () function one or two parameters, with a message and a optional category, but differ in that they dont add end of line characters. These are also the following commands: Debug. WriteLineIF() Trace. WriteLineIF() Debug. WriteIf() Trace. WriteIf()
262
The first four buttons on this toolbar allow manual control of the breaking. In the above screenshot, the three of these grayed out and disabled buttons as they wont work with a program that isnt currently being executed. The one that is enabled, Start is identical to the button that exists on the standard toolbar. In the following sections well look at the rest of the buttons when needed. When an application is running, the toolbar might change and look likes the following screenshot:
Now the three buttons that were grayed in the before picture are enabled in the above picture and let us do the following thing:
263
Pause the application and enter break mode Stop the application completely this doesnt enter break mode, it just quit Restart the application Pausing the application is perhaps the simplest way of entering break mode, but it doesnt give us fine granted control over exactly where to stop, we are likely to stop in a natural pause in the application, perhaps where we request user input. We might also be able to enter break mode during a lengthy operation, or a long loop, by the exact point we stop is likely be fairly random. But in general, it is far better to use the break points.
6.6 Breakpoints
A breakpoint is a marker to the source code that triggers automatic entry into break mode. They may be configured to: Enter break mode immediately when the breakpoint is reached Enter break mode when the breakpoint is reached if a Boolean expression evaluates to true Enter break mode once the breakpoint is reached a set number of times. Enter break mode once the breakpoint is reached and a variable value has changed since the last time the breakpoint was reached DENOTE: That the above points available in the debug builds. If you compile a release build then all breakpoints will be ignored. There are three ways to adding breakpoints. To add simple breakpoints that break when a line is reached we simply left click on the gray area to the left of the line code, or right click on the line, and select the Insert BreakPoint menu option:
264
The break point will appear as a red circle next to the line of code, and highlight on the line of the code as you can see in the following screenshot:
We can also see information about the breakpoints in a file using the BreakPoints window. We need to enable this window first, by selecting the Debug | Windows | BreakPoints menu option or you press the Ctrl + D, B. The following windows will then appear at the bottom of the screen, in the same place as the TaskList and the Output window.
265
Here, we can disable breakpoints by removing the tick to the left of a description a disabled breakpoint shows up as an unfilled red circle, delete breakpoints and edit the properties of breakpoints.
The properties shows in the window, Condition and Hit Count, are only two of the available ones, but they are most useful. We can edit these by right clicking on breakpoints in code or in this window, and selecting the Properties menu option. We can then use the three tabs, Function, File, and Address, to change the location of the breakpoint Address lets us specify an absolute memory address for a breakpoint, an involved subject that we are not seeing it now , and the Condition .. And the Hit Count.. buttons to change the two properties mentioned above. Selecting the Condition button pops up the following dialog as shown in the following screenshot:
266
Here, we can type any Boolean Expression, which may involve any variables that are in scope at the breakpoint. The following screenshot show as breakpoint that will trigger when it is reached and the value of maxVal is greater than 4. We can also check to see it this expression has changed, and only trigger the breakpoint then in the below case, we might trigger the maxVal had changed from 2 to 6 between breakpoint encounters
267
Selecting the hit Count Button pops up the following dialog as you can see in the following screenshot:
268
In the above screenshot by default the Breakpoint Hit Count will be say break always but we change it to the following:
Hence we can specify how times a breakpoint may need to be hit before it is triggered. The drop down list offers the following options:
The option chose, combined with the value entered in the text box to the list, determines the behavior of the breakpoint.
269
This hit the count is useful in long loops, when we might want to break after, say, the first 5000 cycles. It would be a pain to break and restart 5000 times it we couldnt do this!.
Debug.Assert(); Trace.Assert();
Again, the debug version will only be compiled into debug build. These functions take three parameters. The first is a Boolean value, where a value of false will cause the assertion to trigger. The second and third are two string parameters to write information both to pop up dialog and the Output window. The above example would need a function call such as: Debug.Assert(maxVal < 10, "MyVar is 10 or greater,", "Assertion occured in Main ().");
270
271
All these windows works in more or less the same way, with various additional features depending on their specification function. In general, each window will contain a list of variables, with information on variables name, value, and type. More complex variables, such as arrays, may be further intergraded using the and the tree expansion / constriction symbols to the left of their names, allowing a tree view of their content for example, this is display obtained by placing a break point in the code for the earlier example, just after the call to Maxima (); Here, Ive expanded the view for one of the array variables, maxValIndices. We can also edit the content of variables from this view. This effectively bypasses any other variable assignment that might have happened in earlier code. To do this, we simply type a new value into the Value column for the variable we want to edit. We might do this to try out some scenarios that might otherwise require code changes, for example: The Watch windows, of which there may be up to 4, allow us to monitor specific variables or expressions involving specific variables. To use this window, we simply type the name of a variable or expression into the Name column and observe the results. Note that not all variables in an application will be in scope all the time, and will be labeled as such in a Watch window. For example, the following screenshot shows a Watch window with a few sample variables and expressions in it. Again, the code from the last example is used here, paused in the execution of the Maxima () function.
272
The EaglesArray array is local to Main (), so we dont see a value here, instead, we get message information us that variable isnt in scope. We can also add variables to watch window by dragging them from the source code into the window. To add more windows, we can use the Debug | Windows | Watch | Watch N menu to toggle the four possible windows on or off. Each window may contain an individual set fo watches on variables and expressions, so we can group related variables together for easy access. As well as these watch windows, there is also a Quick Watch window that can give us detailed information about variables in the source code quickly. To use this, we simply right click on the variable we want to interrogated and select the QuickWatch menu option. In most cases, though, it is just as easy to use the standard windows. An important point to note about watches is that they are maintained between application executions. If we terminate an application then re- run it we dont have to add watches again - Visual Studio.NET will remember what we were looking at this time.
273
When break mode is entered, a cursor appears to the left of the code view which may initially appear inside the red circle of a breakpoint if a breakpoint has been used to enter mode, by the line of code that is about to be executed.
This shows us that what point execution has reached when break mode is entered. At this point, we can choose to have execution processed on a line by line basics. To do this, we use some more of the Debug toolbar buttons we saw earlier:
The sixth, seventh, and eight icons control program flow in break mode. In order, they are: Step into execute and move to the next statement to execute Step Over as above, but wont entered nested blocks of code Step Out run to end of code block, and resume break mode at the statement that follows:
274
If we want to look at every single operation carried out by the application then we can use Step into to follow the instructions sequentially. This includes moving inside functions, such as Maxima () in the above example. Clicking on this icon when the cursor reaches line 28, the call to Maxima (), will result in the cursor moving to the first line inside the Maxima () function. Alternatively, clicking on Step Over when we reach the line 28, will move the cursor straight to line 29, without having to go through the code in Maxima () although this code is still executed. If we do step into a function that we arent interested in we can hit Step Out to return to the code that called the function.
275
In most cases, we can get the effects we want more easily using the variable monitoring windows we saw earlier, but this technique can still be handy for tweaking values, and is good for testing expressions where we are unlikely to be interested in the results at a later data:
The above window is particular useful when errors are first detected, as they allow us to see what has happened immediately before the error. Where the error occurs in commonly used functions, this will help us to see the source of the error:
276
DENOTE: That sometimes this window will show very confusing information, for me a lot time it is, for example, errors occur outside of our application due to using external functions in the wrong way. At times like this, there could be a long list of entries in this window, but only one or two look similar.
6.13 Exceptions
An exception is an error generated either in our code or in a function called by out code that occurs at runtime. The definition of error here is vaguer that to has been up until now, as exception may be generated manually in functions and so on. For example. We might generated an exception in a function if one of its string parameters doesnt start with the letter a this isnt strictly specking an error outside of the context of this function, although it is treated as one by the code that calls the function. Weve come across the exceptions a few times already in this book. Perhaps the simplest example is attempting to address an array element that is out of range, for example: int [] EaglesArray = {1,2,3,4}; int EaglesElem = EaglesArray[4]; This is generated the following exception message, and then terminate the application:
277
System.IndexOutOfRangeException was unhandled Message: Index was outside the bounds of the array. Exceptions are defined in namespaces and most have names that make it clear what they are intended for. In this example, the exception generated is called System.IndexOutOfRangeException, which makes sense as we have supplied an index that is not in the range of the indices permissible in EaglesArray[]. This message only appears and the application only terminates when the exception is unhandled. So what exactly we can do to handle this exception lets look in more details this in trycatchfinally
6.13 TRY..CATCHFINALLY
The C# language includes syntax for Structured Exception handling which is known as (SHE). Keywords exist to mark code out as being able to handle exceptions, along with instructions as to what to do if an exception occurs. The three keywords we use for this are try, catch, and finally. Each of these has associated code block, and must be used in the consecutive lines of code. I by myself preferred to use this method in the lot of projects and programs which is easier to reduce the burden .The basic structure is follows:
278
It is also possible, however, to have a try block and a finally block with no catch block, or try block with multiple catch blocks, if one or more catch blocks exist then the finally block is optional, else, it is mandatory.
The usage of the blocks is as follows: try Contains code that might throw exception catch Contains code to execute when exceptions are thrown. Catch blocks may be set to using System.IndexOutOfRangeException siddhu, hence the ability to provide multiple catch blocks. It is also possible to omit this parameter entirely, to get a general catch block that will respond to all exceptions. Finally contains code that is always executed, either after the try block if no exception occurs, after a catch block if an exception is handled, or just before an unhandled exception terminates the application the fact that this block is proceed at this time is the reason for its own existence, otherwise we might just as well place code after the block. The sequence of event that occurs after an exception occurs in code in a try block is as follows:
279
The try block terminates at the point where the exception occurred If a catch block exists then a check is made to see if the block matches the type of exception that has been thrown. If no catch block exists, then the finally block which must be present if there are no catch blocks executes. If a catch block exists, but there is no match, then a check is made for other catch blocks. If a catch block matches the exception type, then the code it contains execution, and then the finally block executes if its present If no catch block match the exception the exception type the finally block of code execution if it is present. Lets work it out Writing Exception Text to the output windows
Example Try it out Eagles ExceptionText Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles ExceptionText in the directory C:\EaglesVisualCSharp\Chapter 6\Example Writing Exception Text to the output windows 2. Enter the following code in the using directive: using System; using System.Collections.Generic; using System.Text; using System.Diagnostics;
280
3. Add the following code to the Program.cs as follows: namespace Eagles_ExceptionText { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion class Program { static string[] eTypes = { "none", "simple", "index", "nested index" }; static void Main(string[] args) { foreach (string eType in eTypes ) { try { Console.WriteLine ("Main () try block reached."); Console.WriteLine ("ThrowException(\"{0}\") called." ,eType ); ThrowException (eType ); Console.WriteLine ("Main() try block Continues."); }
281
catch (System.IndexOutOfRangeException siddhu) { Console.WriteLine ("Main () System.IndexOutOfRangeException catch" + " block reached. Message:\n\"{0}\"", siddhu.Message ); } catch { Console.WriteLine ("Main () general catch block reached."); } finally { Console.WriteLine ("main () finally blcok reached."); } Console.WriteLine (); } } static void ThrowException(string exceptionType) { Console.WriteLine("ThrowException(\"{0}\") reached.", exceptionType); switch (exceptionType) { case "none": Console.WriteLine("Not throwing an exception."); break; case "Simple": Console.WriteLine("Thorew System.Exception."); throw (new System.Exception()); break; case "index": Console.WriteLine("Throwing System.IndexOutOfrangeExceptioon."); eTypes[4] = "error"; break; case "nested index": try { Console.WriteLine("ThrowingException(\"nested index\") " + "try block reached."); Console.WriteLine("ThrowException(\"index\") called.");
282
ThrowException("index"); } catch { Console.WriteLine("ThorwException(\"nested index \") general" + "catch block reached."); } finally { Console.WriteLine("ThrowExeption (\"nested index\") finally" + "block reached."); } break; } }
4. Now Run the application and you should see some thing like this:
Now lets see how the above program works: This application has a try block in the Main () that calls a function called Throw Exception (). This function may throw exception, depending on the parameter it is called with:
All Rights Reserved To EaglesGroup
283
Throw Exception (none) doesnt throe an exception Throw Exception (Simple) generates a general exception Throw Exception (index) generates a System.IndexOutOfRangeException exception Throw Exception (Index) to generate a System.IndexOutOfRangeException exception Each of these string parameters is held in the global named eTypes array, which is iterated through in the Main () function to call the Throw Exception () once with each possible parameters. During this loop various messages are written to the console to indictcate what is happening. This code gives us an excellent opportunity to use the code stepping techniques we say earlier in this chapter. By working our way through the code is a line at time you can see exactly how code execution progress; Add a new break point with the default properties to the line 27 of the code, which reads And the line 27 is in my computer. Line 27 // Console.WriteLine ("Main () try block reached.");
Now run the application in the debug mode Almost immediately, the program will enter break mode, with the cursor in line 27. if you select the Locals tab in the variables monitoring window, you should see that eType is currently none. Use the step into button to process lines 27 and 28, and how check that the first line of text has been written to the console.
Next, use the Step into button to the step into the Throw Exception () function on line 29.
Once in the Throw Exception () function on line 50, the Local window changes. eType and Args are no longer in scope they are local to Main(); instead, we see the local exception Type argument, which is of course none. Keep pressing Step into and youll reach the switch statement that checks the value of exception Type and execute the code that writes out the string not throwing an exception to be the screen.
284
When we execute the break statement 54 we exit the function and resume processing in Main () at line 29. as no exception was thrown the try block continues. Next, processing continues with the finally block, click step into a few more times to complete the finally block and the first cycle of the foreach loop. The next time we reach the 29, ThrowException () is called using a different parameters, simple. Continue using Step Into through Throw Exception () and youll eventually reach line 57: throw (new System.Exception()); Here we use the C# throw keyword to generate an exception. This keyword simply need to be provided with a new initialized exception as a parameter, and it will throw that exception. Here we are using another exception form the System namespace, which is System.Exception. When we process this statement with the Step into we find ourselves at the general catch block starting on line 36. There was no match with the earlier catch block starting on line 32, so this one is processed instead. Stepping through this code takes us through this block, through the finally block, and back into another loop cycle that calls ThrowException () with a new parameter on line 29. This time the parameter is index. This time, ThrowException () generates an exception on line 61; eTypes[4] = "error";
The eTypes array is global, so we have access to it here, however, here we are attempting to access the 5th element in the array remember counting start at 0, which generates a System.IndexOutOfRangeException exception. This time there is a matched catch block in main (), and stepping into the code us to this block, starting at line 34. As with the earlier exception handling, we now step now through this catch block, and the associated finally block, and reach the end of the function call. However, there is no crucial difference. Although an Exception has been thrown, it has also been handled by the code in ThrowException (). This means that there is no exception left to handle in the Main (), so we go straight to the finally block, and after that the application terminates.
All Rights Reserved To EaglesGroup
285
Exceptions are listed by category and .NET library namespace. We can see the exception in the System.Namespace by expanding the Common Language Runtime (CLR) Exception tab, and then the System tab. This list includes the System.IndexOutOfRangeException exception we used above. Each exception may be configured using the radio button at the button of the dialog. Most are set to Use parent setting by default, which means that they use the category level option which cares all as shown in the above screenshot. We can use the first option, when the exception is thrown, to cause a break into the debugger even for exception that is handled. The second option allows us to ignore unhandled exception and suffer the consequences Inmost cases the default setting here are fine for us.
286
Summary
This chapter has concentrated on techniques that you can use to debug you applications. There are a verity of techniques available here, moist of which are available for whatever, type of project you are creating, not just the console application. We just looked at: Using the Debug.WriteLine () Trace .WriteLine () Break mode and how to enter it, including the all-around breakpoints Debugging information windows in Visual Studio.NET Stepping through code Exception handling using the trycatch.finally
We have now concerned everything that we need to produce simple console application, along with the methods of debugging them. In the next section of this book, we will look the most powerful technique of the Object Oriented Programming.
287
Chapter 07
288
289
The type of the programming we have seen so far is know as functional or procedural programming, often resulting in so it called monolithic applications, meaning that all functionality is contained in a few modules of code often just one. With OOP techniques we often use many more modules of code, each offering specific functionality, and where each module may be isolated or even completely in depend to other. This modular method of programming gives us much more versatility, and provides more opportunity for code reuse. To illustrate this further, imagine that a high performance application on you computer is a top of the range racing car. If written with traditional programming technique this sports car is basically a single unit. If we want to improve this car we have to replace the whole unit, by sending it back to the manufacture and getting their expert mechanics to upgrade it, to by buying a new one. If OOP technique is used then we could simply buy a new engine from the manufacture and follow their instructions to replace it over selves In more Habitual application the flow of execution is often simple and liner. Application are loaded into memory, start executing at point A, end at point B, and are then unloaded from memory. Along the way various other entities might be used, such as files on storage media, or the capabilities of generally concerned with manipulating data through various mathematical and logical means. The methods of manipulating are usually quite simple, using basic types such as integers and Boolean Values to build up more complex representations of data. With OOP things are really so liner. Although the same result is achieved, the way of getting there is often very different. OOP techniques are firmly rooted in the structure and meaning of data, and the interaction between that data and other data. This is usually means putting more effort into the design stages of a project, but has the benefit of extensibility. Once an agreement is made as to the application, and even entirely new
290
applications. The fact that an agreement exists can reduce development time dramatically. This explain how the above racing car example works. The agreement substituted with ease, rather than requiring a trip back to the manufactures. As well as agreeing on data representations, OOP programming often simplifies things by agreeing on the structure and usage more abstract entities. For example, an agreement can be made not just on the format of data that should be used to send output to a device such as printer, but also on the methods of data exchange with that device, this would include what instructions it understands, and so on. As the name of the technology suggests, this is achieved using objects. So what is an object we will look it now.
291
The following diagram in this chapter have been create using the Microsoft Power point which is inbuilt with the Microsoft Office , but even the diagram can be created using the Microsoft Visio which is distribute with the Enterprise Architect edition of Visual Studio. The following is a UML (Universal Modeling Language) representation of out Speaker class, called Speaker:
The class name is shown in the top section of the box. The following is an UML (Universal Modeling Language) representation of an instance of this Speaker class called mySpeaker:
Here the instance name is shown first in the top section, followed by the name of its class. These two names are separated by a colon.
292
293
in the field, while the public shields external users form this data and prevents them from placing invalid content here. Public members are said to expose by the class. One way of visualizing this is to equate it with variable scope. Private Fields ad properties, for example, can be thought of as local to the object that posses them, whereas the scope of public filed and properties also encompasses code external to the object. In the UML (Universal Modeling Language) representation of a class we use the second section to display properties and fields, for example lets see
This is a representation of our CupOfCoffee class, with five members: Each of the entries contains the following information: Accessibility: A = Symbol is used for a public member, a symbol is used for a private member. In general, through, I wont show private members in the diagram in this chapter, as this information is internal to the class. No information is provided as to read or to write access. The member name They type of the member A colon is used to separate the member name and type in the diagram shown in the above. .
294
7.5 Methods
Methods are the term used to refer to functions exposed by object. These may be called in the same way as any other function, and may use return values and parameters in the same way we already looked at functions in details in the Chapter 5. Methods are use to give access to the functionality of objects. Like fields and properties they can be public or private, restricting access to external code as necessary. They will often make use of objects state to affect their operation, and have access to private members such as fields if required. For example, out CupOfCoffee class might define a method called AddSugar (), which would provide a more readable syntax for incrementing the sugar property than setting the corresponding Sugar property In the UML (Universal Modeling Language), class boxes shown methods in the third section:
The syntax here is similar to that for fields and properties, except that they type shown at the end so the return type and methods parameters are shown. Each parameter is displayed in UML, with one of the following identifiers: in, out, or in out. These are used to signify the direction of data flow, where out and in out roughly correspond to the use of the C# keywords out and ref already defines in the Chapter 5. In roughly corresponds to the C# behavior where neither of these keyword is used.
295
7.8 Constructors
Basic initialize of an object is automatic. For example, we dont have to worry about finding the memory to fit a new object into. However, there are times where we will want to perform additional tasks during an objects initialization stage. Lets say, we will often need to initialize the data stored by an object. A constructor function is what we use to do this. All objects have a default constructor, which is a parameter less method with the same name as the class itself. In addition, a class definition might include several constructor methods with parameters, know as non default constructors. These enable code that instances an object to do so in many ways, perhaps providing initial values for data stored in the object.
All Rights Reserved To EaglesGroup
296
In C#, constructors are called using the new Keyword. For example, we could instantiate a CupOfCoffee object using its default constructor in the following way: CupOfCofee myCup = new CupOfCofee();
Objects may also be instatined using non default constructors. For example, our CupOfCofee class might have a non default constructors that use a parameter to set the bean type at instantiation: CupOfCofee myCup = new CupOfCofee(Eagles Group);
Constructors, like fields, properties, and methods, may be public or private. Code external to a class cant instantiate an object using a private constructor; it might use a public constructor. In this way we can, for example, force the user of the class to use a non default, constructor. Some classes have no public constructors, meaning that is impossible for external code to instantiate them. However, this doesnt make them completely useless, as we will see soon
7.9 Destructors
Destructors are used by the .NET Framework to clean up after objects. In general, we dont want to have provide code foe a destructor method; instead the default operation works for us. However, we can provide specific instructions if anything important need to be done before the object instance is deleted. DENOTE: That the destructors method of an object doesnt get called as soon as we stop using that object. When a variable goes out of scope, for example, it may not accessible form our code, but it may still exist somewhere in your computers memory. It is only when the .NET
297
runtime perform its garbage collection clean up that the instance is completely destroyed. This means that we should rely on the destructors to free up resources that are used by an object instance, as this may be a long time after the object is of no further use to us. If the resources in use are critical this can cause problems. However, there is a solution to this we can see in more details in the Chapter 8 in the section 8.13 The C# Destructor.
298
7.10 Interfaces
An interface is a collection of implicitly public methods and properties that are grouped together to encapsulate specific functionality. Once an interface has been defined, we can implement it in a class. This means that the class will then support all of the properties and members specified by the interface. DENOTE: That interfaces cannot exist on their own. We cant instantiate an interface as we can a class. In addition, interfaces cannot contain any code that implements its members; it just defines the members themselves. The implementation must come form classes that implement the interface.
299
In our earlier coffee example, we might group together many of the more general purpose properties and methods into an interface, such as AddSugar (), Milk, Sugar, and Instant. We could call this interface something like IHotDrink (interface names are normally prefixed with a capital I. we could objects in a similar way, and they may still have their own individual properties BeanType for CupOfCoffee and LeafType for CupOfTea, for example. Interface implemented on objects in UML (universal modeling language), are shown using lollopop syntax. In the diagram below, I have split the members of IHotDrink into a separate box using class like syntax unfortunately the current version of Visio doesnt allow interfaces to posses fields or properties.
A class can support multiple interfaces, and multiple classes can support the same interface. The concept of an interface, therefore, makes life easier for user and other developers. For example, you might have some code that uses an object with certain interface. Provided you dont use other properties and methods of this object it is possible to replace one object with another code using the IHotDrink interface shown above in the picture the work with both CupOfCoffee and CupOfTea instances, for example, in addition, the developers of the object itself could supply you with an updated version of an object, and as long as it supports an interface that is already in use becomes to use this new version in you code.
300
Here the variable <VariableName> will be usable within this code block, and will be disposed of automatically at the end that is, Dispose () is called when the code block finishes executing.
7.12 Inheritance
Inheritance is one of the most important feature in the Object Oriented Programming. Any class may inherit from another, which means that it will have all the members that the class it inherits form has. In OOP terminology, the class being inherited also know as derived from is the parent class also know as the base class. DENOTE: That objects in C# may only descend from a single base class. Inheritance allows us to extend or create more specific class form a single, more generate base class, for example, consider a class that represents a farm of animals. This class might be called Animal, and process method such as EatFood () or Breed (). We could create a derived class called Dog, which would support all of the methods, but might also supply its own, such as Brake () and SupplyMilk (). We could also create another derived class, chicken, with Clunk () and LayEgg () methods. In UML (universal modeling language), we indicate inheritance using arrows, for example:
301
When inheriting from a base class the question of member accessibility becomes an important one. Private members of the base class will not be accessible from a derived class, but public members will, however, public members are accessible to both the derived class and external code. This means that if we could only use these two levels of accessibility we couldnt have a member that was accessible by the base class and the derived class not external code. To get round this, there is a third party type of accessibility, protected, where only derived class has access to a member. As far as external code is aware, this is identical to private member it doesnt have access in either case. As well as the protection level of the member, we can also define an inheritance behavior for it. Members of a base class may be virtual, which means that the member can be overridden by the class that inherits it. What this means is that the derived class may provide an alternative implementation for the member. This alternative doesnt delete the original code, which is still accessible from within the class, but it does shield it from external code. If no alternative is supplied the external code has access to the base class implementation of the member. DENOTE: That virtual members cannot be private, as this would cause a impossibility it is impossible to say that a member can be overridden by a derived class at the same time as saying that it is inaccessible from the derived class:
302
In our animal example, we could make EatFood () virtual, and provide a new implementation for it on any derived class, for example just on the Dog class:
Here I have displayed the EatFood () method on the Animal and Dog classes to signify that they have their own implementations. Base classes may also be defined as abstract classes. An abstract class cant be instantiated directly; to use it you need to inherit form it. Abstract classes may have abstract members, which have no implementation in the base class, so an implementation must be supplied in the derived class If Animal was an abstract class then the UML (universal modeling language), would be as follows:
303
Abstract class is shown with their name in italics in the above picture: In C# here is a common base class for all objects called object which is an alias for the System.Object class in the .NET Framework Interface, described earlier in this chapter, may also inherit from other interfaces, unlike classes; interface may inherit from multiple base interfaces.
7.13 Polymorphism
One consequence of inheritance is that class deriving from a base class has an overlap in the methods and properties that they expose. Because of this, it is often possible to treat objects instantiated from classes with a base type in common using identical syntax. For example, if a base class called Animal has a method called EatFood () then syntax for calling this method from the derived class Dog and Chicken will be similar: Dog myDog = new Dog (); Chicken myChicken = new Chicken (); myDog.EatFood(); myChicken.EatFood();
304
Polymorphism takes this step further. We can assign a variable that is of the base type to variable of the derived types, for example: Animal myAnimal = myDog; No casting is required for this. We can then call method of the base class through this variable: myAnimal.EatFood(); This will result in the implementing of EatFood() in the derived class being called. Note that we cant call methods define on the derived class in the same way. The following code wont work: myAnimal.Bite(); However, we can cast base type variable into a derived class variable and call the method of the derived class that way: Dog myNewDog = (Dog)Animal; myNewDog.Bite(); This casting will cause an exception to be raised if the type of the original variable was anything other than Dog or a class derived from Dog. There are ways of telling what type an object. Polymorphism is an extremely useful technique for performing tasks on different objects descending from a single class with the minimum code. DENOTE: That isnt just classes sharing the same parent class that can make use of polymorphism. It is also possible to treat, say, a child and a grandchild class in the same way, as long as there is common class in their inheritance hierarchy.
305
306
7.16 Containment
Containment is simple to achieve by using a member filed to hold an object instance. This member filed might be public, in which can users, of the container object will have access to its exposed methods and properties much like inheritance. However, we wont have the internals of the class via the derived class as we would with inheritance: Alternatively, we can make the contained member object a private member. If we do this, none of its member will be accessible directly by users, even if they are public. Instead, we can provide access to these members using members of containing class. This means we have complete control over what members of the contained class to expose, if any, and can also perform additional processing in the containing class members before accessing the contained class members. For example, a Dog class might an under class with the public method Brake (). The Dog object could call this method as required, perhaps as part of its DogBrake () method, but these details will not be apparent or important to users of the Dog object. Containment classes may be visualized in UML using an association line. For simple containment we label the ends of the lines with 1s, showing a one to one relationship one Dog instance will contains one Udder instance. We can also show the contained Udder class instance as private filed of the Dog class for clarity.
307
7.17 Collections
The variables types we have been using are really objects, so this is no real surprise. For example: Animal [] animals = new Animal [5]; A collection is basically an array with bells and whistles. Collections are implemented as classes in much the same way as other objects. They are often named in the plural form of the objects they store, for example a class called Animals might contain a collection of Animal objects. The main difference from arrays is that collections usually implement additional functionality, such as Add () and Remove () methods to ass and remove items from the collection. There is also usually an Item property that returns an object based on its index. More often than not this property is implemented in such a way to allow more sophisticated access. For example, it would be possible to design Animals such that a given Animal object could be accessed by its name. In UML we can visualize this as follows:
308
I have left off the members here, as its the relationship that is being illustrated. The numbers on the ends of the connecting lines here show that one Animals object will contain Zero, or more Animal objects.
309
Using operator overloading we could provide logic that used the Weight property implicitly in our code, such that we could write code such are: If (dogA > dogB> { // the do the following } Here the greater than operator > has been overloaded. An overloaded operator is one for which we have written the code to perform the operation involved this code is added to the class definition of one of the classes that it operates on. In the above example we are using the Dog objects, so the operator overloaded definition is contained in the Dog classes. We can also overload operator to work with different classes in the same way, where one or both of the classs definitions contains the code to achieve this. DENOTE: That we can only overload existing C# operators in this way; we cant create new ones. However, we can provide implementations for both unary and binary usages of operators such as +. Well see how to do in the C# Next Chapter.
7.19 Events
Object may raise and consume events as part of their processing. Events are important occurrence that we can act on in other pasts of code, similar to but more powerful than exceptions. We might for example, want some specific code to execute when an Animal object is added to an Animals collection, where that code isnt part of either the Animals class or the code that calls the Add() method. To do this we need to add an event handler to our code, which is a special kind of function that is called when the event occurs. We also need to configure this handler to listen for the event we are interested in. Using events, we create event driven applications, which are far more prolific than you might think at this point or stage. As an example, it is wroth bearing in mind that Windows based application are entirely depends on events. Every button click or scrollbar drag you perform is achieved through event handling. Were the event s are triggered by the mouse or by the keyboard. This event we will see later on the chapter 11 more depth and how this works in Windows application, but for the example we are going to use the console application which will be easier to understand but Window application also easier but we prefer to console application because we see more event s working in console application.
310
7.21 Structs
At this point there is an important point to note. The key difference between struct types and classes is that struct types are value types. The fact that struct types and classes are similar may have occurred to you, particularly as we saw in Chapter 5 how we can use functions in struct types. Well see more details about this in Chapter 9.
311
Example Try it out Eagles ObjectAction Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles ObjectAction in the directory C:\EaglesVisualCSharp\Chapter 7\Example Using Object in Action 2. Add a new Button control using the Toolbox bar, and position it in the center of the Form1.cs[Design] as shown in the following screenshot:
312
3. Now double click on the button and the add the code as follows: private void button1_Click(object sender, EventArgs e) { ((Button)sender).Text = "Clicked!"; Button newButton = new Button(); newButton.Text = "Eagles Button"; newButton.Click += new EventHandler(newButton_Click); Controls.Add(newButton); }
4. Now you have error because you need to add the following code in the Form1.cs as follows: private void newButton_Click(object sender, System.EventArgs siddhu) { ((Button)sender).Text = "Clicked!"; }
5. Now run the application and click the button and you should see the following outputs:
313
314
Now lets see how it workss: By adding just a few lines of code weve created a Windows application that does something, while at the same time illustring some OOP techniques in C#. The phrase we used before in this chapter Everythings an object is even truer when it comes to Windows application. From the form that runs, to the controls on the form, we need to make use of OOP technique all the time. Throughout this example description Ive highlighted some of the concepts that weve looked at earlier in this chapter to show everything fits together. The first thing we did in our application was to add a new button to the Form1.cs [Design]. This button is an object, called Button. Next, by double click the button we have added the event handler to listen out for the Click event that the Button object generates. This event handler is added into the code for the Form1.cs object that encapsulates our application, as a private method:
315
private void button1_Click(object sender, EventArgs e) { } This uses the C# keyword private as a qualifier. Dont worry too much about for now; in the next chapter well looking at the C# code required for the OOP techniques weve seen in this chapter. The first line of code we added change the text on the button that is clicked. This makes use of the polymorphism as seen earlier in this chapter. The button object representing the button that we click is sent to the event handler as an object parameter, which we cast into a Button type (this is possible as the Button object inherits from System.Object, which is the .NET class that object is an alias for. We then change the text property to change the text displayed: ((Button)sender).Text = "Clicked!"; Next, we create a new Button object with the new keyword note that namespace are set up in this project to enable this simple syntax, otherwise wed need to use the fully qualified name of this object, System.Windows.Forms.Button: Button newButton = new Button(); newButton.Text = "Eagles Button"; Elsewhere in the code a new event handler is added, which well use to respond to click evetn generated by out new button: private void newButton_Click(object sender, System.EventArgs siddhu) { ((Button)sender).Text = "Clicked!"; }
We then register this event handler as a listener for the Click evetn using some overloaded operator syntax. Along the way we create a new EvetnHandler object using a non default constructor, using the name of the new evetn handler function: newButton.Click += new EventHandler(newButton_Click);
316
Finally, we make use of the Controls property. This property is an object that is collection of all the controls on our form, and we use it Add () method to add our new button to the form: Controls.Add(newButton); The Controls property illustrates that properties need not necessarily be simple types such as string or integers, but can be any kind of object. This example has used almost all the techniques introduced in this chapter. As you can see. OOP programming neednt be complicated it just requires a different point of view to get right. As what we need to is Everyday there is a new thing for us, just open your mind for the Different View! The same thing for the OOP techniques also.
317
Summary
This chapter has presented us with a full description of object oriented techniques. We have gone through this in the context of C# programming, but this has mainly been illustrative. The vast majority of this chapter is relevant to OOP in any language. We started by covering the basics, such as what it meant by the term object, and how an object is an instance of class. Next we saw how object can have various members, such as fields, properties, and methods. These members can have restricted accessibility, and we looked at what we mean by public and private members. Later on, we saw the members can also be protected, as well as being able to be virtual and abstract where abstract methods are only permissible on abstract classes. We also looked at the difference between static shard and instance members. Next we tool a quick look at the lifecycle of an object, including how constructors are used in object creation, and destructors in object deletion. Later on, after examining groups of members in interfaces, we looked at more advanced object destruction with disposable objects supporting the IDisposable interface. Most of the reminder of this chapter looked at the feature of OOP, many of which well be seeing in more depth in the chapters that follow. We looked at inheritance, where classes inherit from base classes, two versions of polymorphism, through base classes and shared interface, and saw how objects can be used to contain one or more other objects through containment and collections. Finally, we say how operators overloading can be used to simplify the syntax of object usage, and how objects often raise events.
318
Chapter 08
319
320
This chapter explains the C# language features that are used to specify new classes. The elements of a classits behaviors and propertiesare known collectively as its class members. This chapter will show how methods are used to define the behaviors of the class, and how the state of the class is maintained in member variables (often called fields). In addition, this chapter introduces properties, which act like methods to the creator of the class but look like fields to clients of the class
So far, we've not instantiated any instances of that class; that is, we haven't created any Tester objects. What is the difference between a class and an instance of that class? To answer that question, start with the distinction between the type int and a variable of type int. Thus, while you would write:
321
You can't assign a value to a type; instead, you assign the value to an object of that type (in this case, a variable of type int). When you declare a new class, you define the properties of all objects of that class, as well as their behaviors. For example, if you are creating a windowing environment, you might want to create screen widgets more commonly known as controls in Windows programming to simplify user interaction with your application. One control of interest might be a list box, which is very useful for presenting a list of choices to the user and enabling the user to select from the list. List boxes have a variety of characteristicsfor example, height, width, location, and text color. Programmers have also come to expect certain behaviors of list boxes: they can be opened, closed, sorted, and so on. Object-oriented programming allows you to create a new type, ListBox, which encapsulates these characteristics and capabilities. Such a class might have member variables named height, width, location, and text color, and member methods named sort ( ), add ( ), remove ( ), etc. You can't assign data to the ListBox type. Instead you must first create an object of that type, as in the following code snippet: ListBox myListBox;
322
Once you create an instance of ListBox, you can assign data to its fields. Now consider a class to keep track of and display the time of day. The internal state of the class must be able to represent the current year, month, date, hour, minute, and second. You probably would also like the class to display the time in a variety of formats. You might implement such a class by defining a single method and six variables, as shown Lets work it out Using Simple Time Class
Example Try it out Eagles SimpleTime Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles SimpleTime in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using Simple Time Class 2. Add the following code in the Program.cs as follows: namespace Eagles_SimpleTime { # region EaglesGroup /// <EaglesGroup> ///Somu ///Siddhu ///Sri ///(C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { public class Time { // private variables
323
int Month; int Year; int Date; int Hour; int Minute; int Second; // public methods public void DisplayCurrentTime() { Console.WriteLine(DateTime.Now.ToString ()); } }
3. Now enter the following code into the static main () in the program.cs as follows: static void Main(string[] args) { Time t = new Time(); t.DisplayCurrentTime(); } 4. Now run the program and you will see the output like this:
324
The only method declared within the Time class definition is DisplayCurrentTime ( ). The body of the method is defined within the class definition itself. Unlike other languages (such as C++), C# does not require that methods be declared before they are defined, nor does the language support placing its declarations into one file and code into another. (C# has no header files.) All C# methods are defined inline as shown in Example with DisplayCurrentTime ( ). The DisplayCurrentTime ( ) method is defined to return void; that is, it will not return a value to a method that invokes it. For now, the body of this method has been "stubbed out." The Time class definition ends with the declaration of a number of member variables: Year, Month, Date, Hour, Minute, and Second. After the closing brace, a second class, Tester, is defined. Tester contains our now familiar Main ( ) method. In Main ( ), an instance of Time is created and its address is assigned to object t. Because t is an instance of Time, Main ( ) can make use of the DisplayCurrentTime ( ) method available with objects of that type and call it to display the time: t.DisplayCurrentTime ( );
325
The members in class A that are marked private are accessible only to methods of class A. The members in class A that are marked protected are accessible to methods of
class A and also to methods of classes derived from class A
The members in class A that are marked internal are accessible to methods of any class in A's assembly The members in class A that are marked protected internal are accessible to methods of class A, to methods of classes
derived from class A, and also to any class in A's assembly. This is effectively protected OR internal. There is no
326
It is generally desirable to designate the member variables of a class as private. This means that only member methods of that class can access their value. Because private is the default accessibility level, you do not need to make it explicit, but I recommend that you do so. Thus, in Example in the above example, the declarations of member variables should have been written as follows: // private variables private int Year; private int Month; private int Date; private int Hour; private int Minute; private int Second;
Class Program and method DisplayCurrentTime ( ) are both declared public so that any other class can make use of them.
DENOTE: It is good programming practice to explicitly set the accessibility of all methods and members of your class. Although you can rely on the fact that class members are declared private by default, making their access explicit indicates a conscious decision and is self-documenting
327
Within the body of the method, the parameters act as local variables, as if you had declared them in the body of the method and initialized them with the values passed in. The Following Example will show you how to pass the values into a methodin this case, values of type int and float. Lets work it out Using passing values into SomeMethod ()
Example Try it out Eagles passingvalues Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles passingvalues in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using passing values into SomeMethod () 2. Add the Following code into the Program.cs as follows namespace Eagles_passingvalues { # region EaglesGroup /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion public class SiddhuClass { public void SomeMethod(int firstParam, float secondParam) { Console.WriteLine("Here are the parameters received: {0}, {1}", firstParam, secondParam); }
328
class Program { static void Main(string[] args) { int howManyPeople = 5; float pi = 3.14f; SiddhuClass mc = new SiddhuClass (); mc.SomeMethod(howManyPeople, pi); }
3. Now run the program and you should see the out put like this:
The method SomeMethod ( ) takes an int and a float and displays them using Console.WriteLine ( ). The parameters, which are named firstParam and secondParam, are treated as local variables within SomeMethod ( ).
329
DENOTE: VB6 programmers take note: C# methods don't allow you to declare optional arguments. Instead, you have to use method overloading to create methods that declare different combinations of arguments. In the calling method (Main), two local variables (howManyPeople and pi) are created and initialized. These variables are passed as the parameters to SomeMethod ( ). The compiler maps howManyPeople to firstParam and pi to secondParam, based on their relative positions in the parameter list
It
does not actually contain the value for the Time object; it contains the address of that (unnamed) object that is created on the heap. t itself is just a reference to that object. DENOTE: VB6 programmers take note: While there is a performance penalty in using the VB6 keywords Dim and New on the same line, in C# this penalty has been removed. Thus in C# there is no drawback to using the new keyword when declaring an object variable
8.2.1 Constructors
In Example 8.2, notice that the statement that creates the Time object looks as though it is invoking a method:
330
In fact, a method is invoked whenever you instantiate an object. This method is called a constructor, and you must either define one as part of your class definition or let the Common Language Runtime (CLR) provide one on your behalf. The job of a constructor is to create the object specified by a class and to put it into a valid state. Before the constructor runs, the object is undifferentiated memory; after the constructor completes, the memory holds a valid instance of the class type. The Time class of Example 8.2 does not define a constructor. If a constructor is not declared, the compiler provides one for you. The default constructor creates the object but takes no other action. Member variables are initialized to innocuous values (integers to 0, strings to the empty string, etc.).
The Table 8.2.2.1 lists the default values assigned to primitive types. Table 8.2.2.1 Primitive types and their default values Type numeric (int, long, etc.) bool char enum Default Value
false
'\0' (null)
reference
null
Typically, you'll want to define your own constructor and provide it with arguments so that the constructor can set the initial state for your object. In Example 8.2, assume that you want to pass in the current year, month, date, and so forth, so that the object is created with meaningful data.
331
To define a constructor, declare a method whose name is the same as the class in which it is declared. Constructors have no return type and are typically declared public. If there are arguments to pass, define an argument list just as you would for any other method. The below Example will declares a constructor for the Time class that accepts a single argument, an object of type Date Time. Lets work it out Using Declaring a Constructor
Example Try it out Eagles DeclaringConstructor Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles declaringconstructor in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using Declaring a Constructor 2. Add the following code in the body of the Program.cs as follows:
namespace Eagles_declaringconstructor { # region EaglesGroup /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion class Program { public class Siddhu {
332
// private member variables int Year; int Month; int Date; int Hour; int Minute; int Second; // public accessor methods public void DisplayCurrentTime() { System.Console.WriteLine("{0}/{1}/{2} {3}:{4}:{5}", Month, Date, Year, Hour, Minute, Second); } // constructor public Siddhu (System.DateTime dt) { Year = dt.Year; Month = dt.Month; Date = dt.Day; Hour = dt.Hour; Minute = dt.Minute; Second = dt.Second; } }
3. Now add the following code in the static void main() as follows:
static void Main(string[] args) { System.DateTime currentTime = System.DateTime.Now; Siddhu t = new Siddhu (currentTime); t.DisplayCurrentTime(); }
333
4. Now Run the program and you will have the result similar to like this:
Now lets see how the above program works: In this example, the constructor takes a DateTime object and initializes all the member variables based on values in that object. When the constructor finishes, the Time object exists and the values have been initialized. When DisplayCurrentTime ( ) is called in Main ( ), the values are displayed. Try commenting out one of the assignments and running the program again. You'll find that the member variable is initialized by the compiler to 0. Integer member variables are set to 0 if you don't otherwise assign them. Remember, value types (e.g., integers) cannot be uninitialized; if you don't tell the constructor what to do, it will try for something innocuous In Example 8.3, the DateTime object is created in the Main ( ) method of Tester. This object, supplied by the System library, offers a number of public valuesYear, Month, Day, Hour, Minute, and Secondthat correspond directly to the private member variables of our Time object. In addition, the DateTime object offers a static member property, now, which is a reference to an instance of a DateTime object initialized with the current time. Examine the highlighted line in Main ( ), where the DateTime object is created by calling the static method now ( ). Now ( ) creates a DateTime object on the heap and returns a reference to it.
334
That reference is assigned to currentTime, which is declared to be a reference to a DateTime object. Then currentTime is passed as a parameter to the Time constructor. The Time constructor parameter, dt, is also a reference to a DateTime object; in fact dt now refers to the same DateTime object as currentTime does. Thus, the Time constructor has access to the public member variables of the DateTime object that was created in Tester.Main ( ). The reason that the DateTime object referred to in the Time constructor is the same object referred to in Main( ) is that objects are reference types. Thus, when you pass one as a parameter it is passed by referencethat is, the pointer is passed and no copy of the object is made.
8.3 Initializers
It is possible to initialize the values of member variables in an initializer, instead of having to do so in every constructor. Create an initializer by assigning an initial value to a class member: private int Second = 30; // initializer Assume that the semantics of our Time object are such that no matter what time is set, the seconds are always initialized to 30. We might rewrite our Time class to use an initializer so that no matter which constructor is called, the value of Second is always initialized, either explicitly by the constructor or implicitly by the initializer. See Example 8.4 The Following Example will uses an overloaded constructor, which means there are two versions of the constructor that differ by the number and type of variables. Lets work it out Using an Initializer
Example Try it out Eagles Initializer Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles Initializer in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using an Initializer
335
2. Add the following code in the Program.cs as follows: namespace Eagles_Initializer { #region EaglesGroup /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { public class EaglesTime { // private member variables private int Year; private int Month; private int Date; private int Hour; private int Minute; private int Second = 30; // initializer // public accessor methods public void DisplayCurrentTime() { System.DateTime now = System.DateTime.Now; System.Console.WriteLine("\nDebug\t: {0}/{1}/{2} {3}:{4}:{5}", now.Month, now.Day, now.Year, now.Hour, now.Minute, now.Second); System.Console.WriteLine("Time\t: {0}/{1}/{2} {3}:{4}:{5}", Month, Date, Year, Hour, Minute, Second); } // constructors public EaglesTime(System.DateTime dt) { Year = Month = Date = Hour = Minute = Second = } 336
All Rights Reserved To EaglesGroup
public EaglesTime(int Year, int Month, int Date, int Hour, int Minute) { this.Year = Year; this.Month = Month; this.Date = Date; this.Hour = Hour; this.Minute = Minute; } }
3. Add the Following Code in the Static Main () as follows: static void Main(string[] args) { System.DateTime currentTime = System.DateTime.Now; EaglesTime t = new EaglesTime(currentTime); t.DisplayCurrentTime(); EaglesTime t2 = new EaglesTime(2005, 11, 18, 11, 45); t2.DisplayCurrentTime(); }
337
4. Run the Program and you will have the output like this:
Now lets see how the above program works: If you do not provide a specific initializer, the constructor will initialize each integer member variable to zero (0). In the case shown, however, the Second member is initialized to 30: private int Second = 30; // initializer
If a value is not passed in for Second, its value will be set to 30 when t2 is created: EaglesTime t2 = new EaglesTime (2007, 11, 18, 11, 45); t2.DisplayCurrentTime ( );
However, if a value is assigned to Second, as is done in the constructor (which takes a DateTime object, shown in bold), that value overrides the initialized value.
338
The first time through the program, we call the constructor that takes a DateTime object, and the seconds are initialized to 54. The second time through, we explicitly set the time to 11:45 (not setting the seconds), and the initializer takes over. If the program did not have an initializer and did not otherwise assign a value to Second, the value would be initialized by the compiler to zero.
A copy constructor is invoked by instantiating an object of type Time and passing it the name of the Time object to be copied: EaglesTime t3 = new EaglesTime(t2);
Here an existingTimeObject (t2) is passed as a parameter to the copy constructor that will create a new Time object (t3).
339
DENOTE: C and C++ programmers take note: The C# compiler does not generate a copy constructor for you if you do not create your own; however, it doesn't need to. A copy constructor is simply another function in C#it is never called automatically
There are three ways in which the this reference is typically used. The first way is to qualify instance members otherwise hidden by parameters, as in the following: public void SomeMethod (int hour) { this.hour = hour; }
340
In this example, SomeMethod ( ) takes a parameter (hour) with the same name as a member variable of the class. The this reference is used to resolve the name ambiguity. While this.hour refers to the member variable, hour refers to the parameter. The argument in favor of this style is that you pick the right variable name and then use it both for the parameter and for the member variable. The counter argument is that using the same name for both the parameter and the member variable can be confusing. The second use of the this reference is to pass the current object as a parameter to another method. For instance, the following code: public void FirstMethod(OtherClass otherObject) { otherObject.SecondMethod(this); }
Establishes two classes, one with the method FirstMethod ( ) and the second (OtherClass) with the method SecondMethod ( ). Inside FirstMethod, we'd like to invoke SecondMethod, passing in the current object for further processing.
btnUpdate.SomeMethod( );
341
In C#, it is not legal to access a static method or member variable through an instance, and trying to do so will generate a compiler error (C++ programmers, take note). Some languages distinguish between class methods and other (global) methods that are available outside the context of any class. In C# there are no global methods, only class methods, but you can achieve an analogous result by defining static methods within your class. DENOTE: VB6 programmers take note: Don't confuse the static keyword in C# with the Static keyword in VB6 and VB.NET. In Visual Basic, the Static keyword declares a variable that is only available to the method it was declared in. In other words, the Static variable is not shared among different objects of its class (i.e., each Static variable instance has its own value). However, this variable exists for the life of the program, which allows its value to persist from one method call to another.
In C#, the static keyword indicates a class variable. In VB, the equivalent keyword is shared. Static methods act more or less like global methods, in that you can invoke them without actually having an instance of the object at hand. The advantage of static methods over global, however, is that the name is scoped to the class in which it occurs, and thus you do not clutter up the global namespace with myriad function names. This can help manage highly complex programs, and the name of the class acts very much like a namespace for the static methods within it.
DENOTE: Resist the temptation to create a single class in your program in which you stash all your miscellaneous methods. It is possible but not desirable and undermines the encapsulation of an object-oriented design.
342
SomeMethod( )
is a nonstatic method of SiddhuClass. For Main( ) to access this method, it must first instantiate an object of type SiddhuClass and then invoke the method through that object.
343
344
When all these changes are made, the output is: Name: Time 11/27/2005 7:52:54 Name: Time 11/18/2005 11:45:30
Although this code works, it is not necessary to create a static constructor to accomplish this goal. You could, instead, use an initializer: private static string Name = "Time";
Which accomplishes the same thing? Static constructors are useful, however, for set-up work that cannot be accomplished with an initializer and that needs to be done only once. DENOTE: Java programmers take note: In C#, a static constructor will serve where a static initializer would be used in Java. For example, assume you have an unmanaged bit of code in a legacy DLL. You want to provide a class wrapper for this code. You can call load library in your static constructor and initialize the jump table in the static constructor.
345
Example Try it out Eagles StaticFields Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles StaticFields in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using Static fields for instance counting 2. Add the following code in the Program.cs as follows: namespace Eagles_StaticFields { #region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGrroup /// </EaglesGroup> # endregion class Program
346
{ public class Eagles { private static int instances = 0; public Eagles( ) { instances++; } public static void HowManyEagles( ) { Console.WriteLine("{0} Eagles adopted",instances); } } static void Main(string[] args) { Eagles.HowManyEagles(); Eagles siddhu = new Eagles(); Eagles.HowManyEagles(); Eagles Shamu = new Eagles(); Eagles.HowManyEagles(); } }
3.
Now Run the program and the result will be like this:
347
Now lets see how the above program will work: The Eagles class has been stripped to its absolute essentials. A static member variable called instances is created and initialized to zero. Note that the static member is considered part of the class, not a member of an instance, and so it cannot be initialized by the compiler on creation of an instance. Thus, an explicit initializer is required for static member variables. When additional instances of Eagles are created in a constructor, the count is incremented. Static Methods to Access Static Fields It is undesirable to make member data public. This applies to static member variables as well. One solution is to make the static member private, as we've done here with instances. We have created a public accessor method, HowManyEagles ( ), to provide access to this private member.
DENOTE: C and C++ programmers take note: A destructor is not necessarily called when an object goes out of scope but when it is garbage-collected (which may happen much later). This is known as non-deterministic finalization
The destructor should only release resources that your object holds on to, and should not reference other objects. Note that if you have only managed references, you do not need to and should not implement a destructor; you want this only for handling unmanaged resources. Because there is some cost to having a destructor, you ought to implement this only on methods that require it (that is, methods that consume valuable unmanaged resources).
348
Never call an object's destructor directly. The garbage collector (GC) will call it for you. How Destructors Work? The garbage collector maintains a list of objects that have a destructor. This list is updated every time such an object is created or destroyed. When an object on this list is first collected, it is placed on a queue with other objects waiting to be destroyed. After the destructor executes, the garbage collector then collects the object and updates the queue, as well as its list of destructible objects.
C#'s destructor looks, syntactically, much like a C++ destructor, but it behaves quite differently. Declare a C# destructor with a tilde as follows: In C#, this syntax is simply a shortcut for declaring a Finalize ( ) method that chains up to its base class. Thus, when you write: The C# compiler translates it to: protected override void Finalize( ) { try { // do work here. } finally { base.Finalize( ); } }
349
The IDisposable interface requires its implementers to define one method, named Dispose ( ), to perform whatever cleanup you consider to be crucial. The availability of Dispose ( ) is a way for your clients to say, "Don't wait for the destructor to be called, do it right now." If you provide a Dispose ( ) method, you should stop the garbage collector from calling your object's destructor. To do so, call the static method GC.SuppressFinalize ( ), passing in the this pointer for your object. Your destructor can then call your Dispose ( ) method.
For some objects, you'd rather have your clients call the Close ( ) method. (For example, Close ( ) makes more sense than Dispose ( ) for file objects.) You can implement this by creating a private Dispose ( ) method and a public Close ( ) method and having your Close ( ) method invoke Dispose ( ).
350
Example Try it out Eagles UsingStatment Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles UsingStatment in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using the Using Statement 2. Add the following code in the Program.cs as follows: namespace Eagles_UsingStatment { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> #endregion class Program { static void Main(string[] args) { using (Font theFont = new Font("Arial", 10.0f)) { // use theFont } // compiler will call Dispose on theFont Font anotherFont = new Font("Courier", 12.0f); using (anotherFont) { // use anotherFont } // compiler calls Dispose on anotherFont }
351
Now lets see what exactly the above code does: In the first part of this example, the Font object is created within the using statement. When the using statement ends, Dispose ( ) is called on the Font object. In the second part of the example, a Font object is created outside of the using statement. When we decide to use that font, we put it inside the using statement; when that statement ends, Dispose ( ) is called once again. The using statement also protects you against unanticipated exceptions. No matter how control leaves the using statement, Dispose ( ) is called. It is as if there was an implicit try-catch-finally block
By default, value types are passed into methods by value, this means that when a value object is passed to a method, a temporary copy of the object is created within that method. Once the method completes, the copy is discarded. Although passing by value is the normal case, there are times when you will want to pass value objects by reference. C# provides the ref parameter modifier for passing value objects into a method by reference, and the out modifier for those cases in which you want to pass in a ref variable without first initializing it. C# also supports the params modifier, which allows a method to accept a variable number of parameters.
DENOTE: Java programmers take note: In C#, there is no need for wrapper classes for basic types like int (integer). Instead, use reference parameters Because we cannot return three values, perhaps we can pass in three parameters, let the method modify the parameters, and examine the result in the calling method
352
Example Try it out Eagles ReturningParameters Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles ReturningParameters in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using Returning values in parameters 2. Add the following code in the Program.cs as follows: namespace Eagles_ReturningParameters { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { public class EaglesTime { // private member variables private int Year; private int Month; private int Date; private int Hour; private int Minute; private int Second;
353
// public accessor methods public void DisplayCurrentTime( ) { System.Console.WriteLine("{0}/{1}/{2} {3}:{4}:{5}",Month, Date, Year, Hour, Minute, Second); } public int GetHour( ) { return Hour; } public void GetTime(int h, int m, int s) { h = Hour; m = Minute; s = Second; } // constructor public EaglesTime(System.DateTime dt) { Year = dt.Year; Month = dt.Month; Date = dt.Day; Hour = dt.Hour; Minute = dt.Minute; Second = dt.Second; } }
354
3. Add the following code in the Static Void Main() as follows: ystem.DateTime currentTime = System.DateTime.Now; EaglesTime t = new EaglesTime(currentTime); t.DisplayCurrentTime(); int theHour = 0; int theMinute = 0; int theSecond = 0; t.GetTime(theHour, theMinute, theSecond); System.Console.WriteLine("Current time: {0}:{1}:{2}", theHour, theMinute, theSecond);
4. Now run the program and you will have the output like this:
Notice that the "Current time" in the output is 0:0:0. Clearly, this first attempt did not work. The problem is with the parameters. We pass in three integer parameters to GetTime( ), and we modify the parameters in GetTime( ), but when the values are accessed back in Main( ), they are unchanged. This is because integers are value types, and so are passed by value; a copy is made in GetTime( ). What we need is to pass these values by reference. Two small changes are required. First, change the parameters of the GetTime( ) method to indicate that the parameters are ref (reference) parameters:
355
public void GetTime(ref int h, ref int m, ref int s) { h = Hour; m = Minute; s = Second; }
Second, modify the call to GetTime ( ) to pass the arguments as references as well: t.GetTime (ref theHour, ref theMinute, ref theSecond);
If you leave out the second step of marking the arguments with the keyword ref, the compiler will complain that the argument cannot be converted from an int to a ref int. The results now show the correct time. By declaring these parameters to be ref parameters, you instruct the compiler to pass them by reference. Instead of a copy being made, the parameter in GetTime ( ) is a reference to the same variable (theHour) that is created in Main( ). When you change these values in GetTime ( ), the change is reflected in Main( ). Keep in mind that ref parameters are references to the actual original valueit is as if you said, "Here, work on this one." Conversely, value parameters are copiesit is as if you said, "Here, work on one just like this."
C# imposes definite assignment, which requires that all variables be assigned a value before they are used, Example 8.7, if you don't initialize theHour, theMinute, and theSecond before you pass them as parameters to GetTime ( ), the compiler will complain. Yet the initialization that is done merely sets their values to 0 before they are passed to the method:
356
int theHour = 0; int theMinute = 0; int theSecond = 0; t.GetTime( ref theHour, ref theMinute, ref theSecond);
It seems silly to initialize these values because you immediately pass them by reference into GetTime where they'll be changed, but if you don't, the following compiler errors are reported: Use of unassigned local variable 'theHour' Use of unassigned local variable 'theMinute' Use of unassigned local variable 'theSecond'
C# provides the out parameter modifier for this situation. The out modifier removes the requirement that a reference parameter be initialized. The parameters to GetTime( ), for example, provide no information to the method; they are simply a mechanism for getting information out of it. Thus, by marking all three as out parameters, you eliminate the need to initialize them outside the method. Within the called method, the out parameters must be assigned a value before the method returns. Here are the altered parameter declarations for GetTime ( ): public void GetTime(out int h, out int m, out int s) { h = Hour; m = Minute; s = Second; } And here is the new invocation of the method in Main( ): t.GetTime( out theHour, out theMinute, out theSecond);
357
To summarize, value types are passed into methods by value. ref parameters are used to pass value types into a method by reference. This allows you to retrieve their modified value in the calling method. Out parameters are used only to return information from a method Lets work it out Using in, out, and ref parameters
Example Try it out Eagles Using3Parameters Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles Using3Parameters in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using in, out, and ref parameters 2. Add the following code in the program.cs as follows:
namespace Eagles_Using3Parameters { # region EaglesGroup Console Application /// <EaglesGruop> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program public class EaglesTime { // private member variables private int Year; private int Month; private int Date; private int Hour; private int Minute; private int Second;
358
// public accessor methods public void DisplayCurrentTime( ) { System.Console.WriteLine("{0}/{1}/{2} {3}:{4}:{5}", Month, Date, Year, Hour, Minute, Second); } public int GetHour( ) { return Hour; } public void SetTime(int hr, out int min, ref int sec) { // if the passed in time is >= 30 // increment the minute and set second to 0 // otherwise leave both alone if (sec >= 30) { Minute++; Second = 0; } Hour = hr; // set to value passed in // pass the minute and second back out min = Minute; sec = Second; } // constructor
359
public EaglesTime(System.DateTime dt) { Year = dt.Year; Month = dt.Month; Date = dt.Day; Hour = dt.Hour; Minute = dt.Minute; Second = dt.Second; } }
static void Main(string[] args) { System.DateTime currentTime = System.DateTime.Now; EaglesTime t = new EaglesTime(currentTime); t.DisplayCurrentTime( ); int theHour = 3; int theMinute; int theSecond = 20; t.SetTime(theHour, out theMinute, ref theSecond); System.Console.WriteLine( "the Minute is now: {0} and {1} seconds", theMinute, theSecond); theSecond = 40; t.SetTime(theHour, out theMinute, ref theSecond); System.Console.WriteLine("the Minute is now: " + "{0} and {1} seconds", theMinute, theSecond); }
360
is a bit contrived, but it illustrates the three types of parameters. theHour is passed in as a value parameter; its entire job is to set the member variable Hour, and no value is returned using this parameter. The ref parameter theSecond is used to set a value in the method. If theSecond is greater than or equal to 30, the member variable Second is reset to 0 and the member variable Minute is incremented. DENOTE: C and C++ programmers take note: In C#, you must specify ref on both the call and the destination when using reference parameters
Finally, theMinute is passed into the method only to return the value of the member variable Minute, and thus is marked as an out parameter. It makes perfect sense that theHour and theSecond must be initialized; their values are needed and used. It is not necessary to initialize theMinute, as it is an out parameter that exists only to return a value. What at first appeared to be arbitrary and capricious rules now make sense; values are only required to be initialized when their initial value is meaningful.
361
void myMethod(int p1); void myMethod(int p1, int p2); void myMethod(int p1, string s1);
A class can have any number of methods, as long as each one's signature differs from that of all the others Example 8.9 illustrates our Time class with two constructors: one that takes a DateTime object, and the other that takes six integers Lets work it out Using overloading the constructor
Example Try it out Eagles overloadingconstructor Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles overloadingconstructor in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using overloading the constructor 2. Add the following code in the Program.cs as follows: namespace Eagles_overloadingconstructor { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { public class EaglesTime { // private member variables
362
private int Year; private int Month; private int Date; private int Hour; private int Minute; private int Second; // public accessor methods public void DisplayCurrentTime( ) { System.Console.WriteLine("{0}/{1}/{2} {3}:{4}:{5}", Month, Date, Year, Hour, Minute, Second); } // constructors public EaglesTime(System.DateTime dt) { Year = dt.Year; Month = dt.Month; Date = dt.Day; Hour = dt.Hour; Minute = dt.Minute; Second = dt.Second; } public EaglesTime(int Year, int Month, int Date, int Hour, int Minute, int Second) { this.Year = Year; this.Month = Month; this.Date = Date; this.Hour = Hour; this.Minute = Minute; this.Second = Second; } } static void Main(string[] args) { System.DateTime currentTime = System.DateTime.Now; EaglesTime t = new EaglesTime(currentTime); t.DisplayCurrentTime(); EaglesTime t2 = new EaglesTime(2005, 11, 18, 11, 03, 30); t2.DisplayCurrentTime(); }
363
3. Now run the program and the you should have the output like this:
Now lets see how the above code works: As you can see, the Time class in Example 8-9 has two constructors. If a function's signature consisted only of the function name, the compiler would not know which constructors to call when constructing t1 and t2. However, because the signature includes the function argument types, the compiler is able to match the constructor call for t1 with the constructor whose signature requires a DateTime object. Likewise, the compiler is able to associate the t2 constructor call with the constructor method whose signature specifies six integer arguments. When you overload a method, you must change the signature i.e., the name, number, or type of the parameters. You are free, as well, to change the return type, but this is optional. Changing only the return type does not overload the method, and creating two methods with the same signature but differing return types will generate a compile error. This is illustrated in Example 8-10.
364
Lets work it out Using varying the return type on overload methods.
Example Try it out Eagles overloadmethods Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles overloadmethods in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using varying the return type on overload methods 2. Add the Following code into the Program.cs as follows:
amespace Eagles_overloadmethods { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { public class Eagles { private int Triple(int val) { return 3 * val; } private long Triple(long val) { return 3 * val; }
365
public void Test() { int x = 5; int y = Triple(x); System.Console.WriteLine("x: {0} y: {1}", x, y); long lx = 10; long ly = Triple(lx); System.Console.WriteLine("lx: {0} ly: {1}", lx, ly); } static void Main(string[] args) { Eagles E = new Eagles(); E.Test(); } } 3. Run the Application and you should have the output like this:
366
In this example, the Tester class overloads the Triple ( ) method, one to take an integer, the other to take a long. The return type for the two Triple ( ) methods varies. Although this is not required, it is very convenient in this case.
Example Try it out Eagles property Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles property in the directory C:\EaglesVisualCSharp\Chapter 8\Example Using a Property
367
2. Add the following code in the program.cs as follows: namespace Eagles_property { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { public class EaglesTime { // private member variables private int year; private int month; private int date; private int hour; private int minute; private int second; // public accessor methods public void DisplayCurrentTime() { System.Console.WriteLine( "Time\t: {0}/{1}/{2} {3}:{4}:{5}", month, date, year, hour, minute, second); } // constructors public EaglesTime(System.DateTime dt) { year = dt.Year; month = dt.Month; date = dt.Day; hour = dt.Hour; minute = dt.Minute; second = dt.Second; } // create a property 368
All Rights Reserved To EaglesGroup
public int Hour { get { return hour; } set { hour = value; } } } static void Main(string[] args) { System.DateTime currentTime = System.DateTime.Now; EaglesTime E = new EaglesTime(currentTime); E.DisplayCurrentTime(); int theHour = E.Hour; System.Console.WriteLine("\nRetrieved the hour: {0}\n", theHour); theHour++; E.Hour = theHour; System.Console.WriteLine("Updated the hour: {0}\n", theHour); }
369
3. Run the program and you will have the output like this:
Now lets see how the above program works: To declare a property, write the property type and name followed by a pair of braces. Within the braces you may declare get and set accessor. Neither of these has explicit parameters, though the set ( ) method has an implicit parameter value as shown next. In Example 8-11, Hour is a property. Its declaration creates two accessor: get and set. public int Hour { get { return hour; } set { hour = value; } }
370
Each accessor has an accessor-body that does the work of retrieving and setting the property value. The property value might be stored in a database (in which case the accessor-body would do whatever work is needed to interact with the database), or it might just be stored in a private member variable: private int hour;
In this example, the value of the Time object's Hour property is retrieved, invoking the get accessor to extract the property, which is then assigned to a local variable.
371
The set accessor sets the value of a property and is similar to a method that returns void. When you define a set accessor, you must use the value keyword to represent the argument whose value is passed to and stored by the property. set { hour = value; }
Here, again, a private member variable is used to store the value of the property, but the set accessor could write to a database or update other member variables as needed. When you assign a value to the property, the set accessor is automatically invoked, and the implicit parameter value is set to the value you assign: theHour++; t.Hour = theHour; The advantage of this approach is that the client can interact with the properties directly, without sacrificing the data-hiding and encapsulation sacrosanct in good object-oriented design
8. 20 Read-only Fields
You might want to create a version of the Time class that is responsible for providing public static values representing the current time and date. Example 8-12 illustrates a simple approach to this problem. Lets work it out Using Static public Constants
Example Try it out Eagles publicconstants Step by Step Example: Using Version 2005
372
1. Create a new Console Application name it as Eagles publicconstants in the directory 2:\EaglesVisualCSharp\Chapter 8\Example Using Static public Constants 2. Add the following Code in the Program.cs as follows: namespace Eagles_publicconstants { # region EaglesGroup Console Application /// <EaglesGroup> /// Somu /// Siddhu /// Sri /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { public class RightNow { // public member variables public static int Year; public static int Month; public static int Date; public static int Hour; public static int Minute; public static int Second; static RightNow() { System.DateTime dt = System.DateTime.Now; Year = dt.Year; Month = dt.Month; Date = dt.Day; Hour = dt.Hour; Minute = dt.Minute; Second = dt.Second; } } static void Main(string[] args) { System.Console.WriteLine("This year: {0}", RightNow.Year.ToString()); RightNow.Year = 2006; System.Console.WriteLine("This year: {0}", RightNow.Year.ToString()); }
373
3. Now Run the program and you should have something like this:
Now lets see hoe the above program works: This works well enough, until someone comes along and changes one of these values. As the example shows, the RightNow.Year value can be changed, for example, to 2006. This is clearly not what we'd like. We'd like to mark the static values as constant, but that is not possible, because we don't initialize them until the static constructor is executed. C# provides the keyword readonly for exactly this purpose. If you change the class member variable declarations as follows: public static readonly int Year; public static readonly int Month; public static readonly int Date; public static readonly int Hour; public static readonly int Minute; public static readonly int Second;
Then comment out the reassignment in Main ( ): // RightNow.Year = 2008; // error! The program will compile and run as intended.
374
Summary:
In this Chapter we had been looked the Classes and Objects and their uses in the C# as well and the sub topics and the topics so far covered are:
Introduction to Classes and Objects: 8.1.2 Access Modifiers: 8.1. 3 Method Arguments 8.2 Creating Objects 8.2.1 Constructors 8.2.2 Constructors 8.3 Initializers 8.3 Copy Constructors 8.4 The ICloneable Interface 8.6 The this Keyword 8.7 Using Static Members 8.8 Invoking Static Methods 8.9 Using Static Constructors 8.10 Using Private Constructors 8.11 Using Static Fields 8.12 Destroying Objects 8.13 The C# Destructor 8.14 Destructors Versus Dispose 8.15 Implementing the Close( ) Method 8.16 The using Statement 8.17 Passing Parameters 8.17.1 Passing by Reference 8.17.2 Passing Out Parameters with Definite Assignment 8.18 Overloading Methods and Constructors 8.19 Encapsulating Data with Properties 8.19.1 The get Accessor 8.19.2 The set Accessor 8. 20 Read-only Fields
375
Chapter 09
376
Structs
9.1 Introduction to Struts
A struct is a simple user-defined type, a lightweight alternative to classes. Structs are similar to classes in that they may contain constructors, properties, methods, fields, operators, nested types, and indexers There are also significant differences between classes and structs. For instance, structs don't support inheritance or destructors. More important, although a class is a reference type, a struct is a value type. Thus, structs are useful for representing objects that do not require reference semantics. The consensus view is that you ought to use structs only for types that are small, simple, and similar in their behavior and characteristics to built-in types DENOTE: C and C++ programmers take note: The meaning of C#'s struct construct is very different from C++'s. It permits C# to step outside the single-inheritance Object hierarchy and is particularly useful when interfacing with libraries written in C++. Structs are somewhat more efficient in their use of memory in arrays. However, they can be less efficient when used in collections. Collections expect references, and structs must be boxed. There is overhead in boxing and unboxing, and classes might be more efficient in large collections. In this chapter, you will learn how to define and work with structs, and how to use constructors to initialize their values.
377
Example 9.1 illustrates the definition of a struct. Location represents a point on a twodimensional surface. Notice that the struct Location is declared exactly as a class would be, except for the use of the keyword struct. Also notice that the Location constructor takes two integers and assigns their value to the instance members, x and y. The x and y coordinates of Location are declared as properties.
378
Example Try it out Eagles CreatingStruct Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles CreatingStruct in the directory C:\EaglesVisualCSharp\Chapter 9\Example CreatingStruct 2. Declare a variable as follows in the constructor of the program.cs public struct Location { private int xVal; private int yVal;
public Location(int xCoordinate, int yCoordinate) { xVal = xCoordinate; yVal = yCoordinate; } public int x { get { return xVal; } set { xVal = value; } }
379
public int y { get { return yVal; } set { yVal = value; } } public override string ToString( ) { return (String.Format("{0}, {1}", xVal,yVal)); } public void myFunc(Location loc) { loc.x = 50; loc.y = 100; Console.WriteLine("In MyFunc loc: {0}", loc); } static void Main(string[] args) { Location loc1 = new Location(200, 300); Console.WriteLine("Loc1 location: {0}", loc1); Tester t = new Tester(); t.myFunc(loc1); Console.WriteLine("Loc1 location: {0}", loc1); } }
380
4. Now run the program and you should have the output like this:
Unlike classes, structs do not support inheritance. They implicitly derive from object (as do all types in C#, including the built-in types) but cannot inherit from any other class or struct. Structs are also implicitly sealed (that is, no class or struct can derive from a struct). Like classes, however, structs can implement multiple interfaces. Additional differences include the following:
Though that would have been fine had this been a class.
381
Structs are designed to be simple and lightweight. While private member data promotes data hiding and encapsulation, some programmers feel it is overkill for structs. They make the member data public, thus simplifying the implementation of the struct. Other programmers feel that properties provide a clean and simple interface, and that good programming practice demands data-hiding even with simple lightweight objects. Whichever you choose is a matter of design philosophy; the language supports either approach.
Here the new instance is named loc1 and is passed two values, 200 and 300.
WriteLine ( )
is expecting an object, but, of course, Location is a struct (a value type). The compiler automatically boxes the struct (as it would any value type), and it is the boxed object that is passed to WriteLine ( ). ToString ( ) is called on the boxed object, and because the struct (implicitly) inherits from object, it is able to respond polymorphically, overriding the method just as any other object might: Loc1 location: 200, 300
382
Structs are value objects, however, and when passed to a function, they are passed by valueas seen in the next line of code, in which the loc1 object is passed to the myFunc( ) method: t.myFunc (loc1);
In myFunc ( ), new values are assigned to x and y, and these new values are printed out: Loc1 location: 50, 100
When you return to the calling function (Main ( )) and call WriteLine ( ) again, the values are unchanged: Loc1 location: 200, 300 The struct was passed as a value object, and a copy was made in myFunc( ). Try changing the declaration to class: public class Location
Loc1 location: 200, 300 In MyFunc loc: 50, 100 Loc1 location: 50, 100
This time the Location object has reference semantics. Thus, when the values are changed in myFunc ( ), they are changed on the actual object back in Main ( ).
383
Because there is now no constructor at all, the implicit default constructor is called. The output looks like this: Loc1 location: 0, 0 In MyFunc loc: 50, 100 Loc1 location: 0, 0
The default constructor has initialized the member variables to zero. DENOTE: C++ programmers take note: In C#, the new keyword does not always create objects on the heap. Classes are created on the heap, and structs are created on the stack. Also, when new is omitted (as you will see in the next section), a constructor is never called. Because C# requires definite assignment, you must explicitly initialize all the member variables before using the struct.
384
The resulting Location object is created on the stack. The new operator calls the Location constructor. However, unlike with a class, it is possible to create a struct without using new at all. This is consistent with how built-in type variables (such as int) are defined, and is illustrated in Example 9-2.
DENOTE: A caveat: I am demonstrating how to create a struct without using new because it differentiates C# from C++, and also differentiates how C# treats classes versus structs. That said, however, creating structs without the keyword new brings little advantage and can create programs that are harder to understand, more error prone, and more difficult to maintain. Proceed at your own risk.
385
Example Try it out Eagles CreatingStruct Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles Struct in the directory C:\EaglesVisualCSharp\Chapter 9\Example Creating a struct without using new 2. Enter the following code in the body of the program.cs as follows:
public struct Location { public int xVal; public int yVal; public Location(int xCoordinate, int yCoordinate) { xVal = xCoordinate; yVal = yCoordinate; } public int x { get { return xVal; } set { xVal = value; } }
386
public int y { get { return yVal; } set { yVal = value; } } public override string ToString() { return (String.Format("{0}, {1}", xVal, yVal)); } } public class Tester { static void Main(string[] args) { Location loc1; // no call to the constructor loc1.xVal = 75; // initialize the members loc1.yVal = 225; Console.WriteLine(loc1); } }
387
3. Now run the application and you should have the output like this:
In Example 9-2, you initialize the local variables directly, before calling a method of loc1 and before passing the object to WriteLine( ): loc1.xVal = 75; loc1.yVal = 225;
If you were to comment out one of the assignments and recompile: static void Main( ) { Location loc1; loc1.xVal = 75; // loc1.yVal = 225; Console.WriteLine(loc1); } You would get a compiler error: Use of unassigned local variable 'loc1' Once you assign all the values, you can access the values through the properties x and y:
388
static void Main( ) { Location loc1; loc1.xVal = 75; // assign member variable loc1.yVal = 225; // assign member variable loc1.x = 300; // use property loc1.y = 400; // use property Console.WriteLine(loc1); }
Be careful about using properties. Although these allow you to support encapsulation by making the actual values private, the properties themselves are actually member methods, and you cannot call a member method until you initialize all the member variables.
Summary:
In this chapter we see about struts and creating structs and many more things as the topics are covered are as follows: Introduction Defining Structs Creating Structs Structs as Value Types Calling the Default Constructor Creating Structs Without new
389
Chapter 10
390
Interfaces
10.1Introduction to Interfaces
An interface is a contract that guarantees to a client how a class or struct will behave. When a class implements an interface, it tells any potential client "I guarantee I'll support the methods, properties, events, and indexers of the named interface." An interface offers an alternative to an abstract class for creating contracts among classes and their clients. These contracts are made manifest using the interface keyword, which declares a reference type that encapsulates the contract. Syntactically, an interface is like a class that has only abstract methods. An abstract class serves as the base class for a family of derived classes, while interfaces are meant to be mixed in with other inheritance trees. When a class implements an interface, it must implement all the methods of that interface; in effect the class says "I agree to fulfill the contract defined by this interface." DENOTE: Java programmers take note: C# does not support the use of constant fields (member constants) in interfaces. Inheriting from an abstract class implements this-a relationship. Implementing an interface defines a different relationship that we've not seen until now: the implements relationship. These two relationships are subtly different. A car is-a vehicle, but it might implement the CanBeBoughtWithABigLoan capability (as can a house, for example). In this chapter, you will learn how to create, implement, and use interfaces. You'll learn how to implement multiple interfaces, and how to combine and extend interfaces, as well as how to test whether a class has implemented an interface.
391
The interface keyword is followed by the name of the interface. It is common but not required to begin the name of your interface with a capital I thus, IStorable, ICloneable, IClaudius, etc. The interface-body is the implementation of the interface, as described next. Suppose you wish to create an interface that describes the methods and properties a class needs to be stored to and retrieved from a database or other storage such as a file. You decide to call this interface IStorable. In this interface you might specify two methods: Read ( ) and Write ( ), which appear in the interface-body: interface IStorable { void Read( ); void Write(object); }
The purpose of an interface is to define the capabilities that you want to have available in a class. For example, you might create a class, Document. It turns out that Document types can be stored in a database, so you decide to have Document implement the IStorable interface. To do so, use the same syntax as if the new Document class were inheriting from IStorablea colon (:), followed by the interface name:
392
public class Document : IStorable { public void Read( ) {...} public void Write(object obj) {...} // ... } It is now your responsibility, as the author of the Document class, to provide a meaningful implementation of the IStorable methods. Having designated Document as implementing IStorable, you must implement all the IStorable methods, or you will generate an error when you compile. This is illustrated in Example 101, in which the Document class implements the IStorable interface.
Example Try it out Eagles SimpleInterface Step by Step Example: Using Version 2005
1. Create a new Console application name it as Eagles SimpleInterface in the directory C:\EaglesVisualCSharp\Chapter 10\Example Using SimpleInterface 2. Add the following code into the body of the Program.cs as follows: namespace Eagles_SimpleInterface { class Program { interface IStorable { // no access modifiers, methods are public // no implementation void Read(); void Write(object obj); int Status { get; set; } }
All Rights Reserved To EaglesGroup
393
// create a class which implements the IStorable interface public class Document : IStorable { // store the value for the property private int status = 0; public Document(string s) { Console.WriteLine("Creating document with: {0}", s); } // implement the Read method public void Read( ) { Console.WriteLine("Implementing the Read Method for IStorable"); } // implement the Write method public void Write(object o) { Console.WriteLine("Implementing the Write Method for IStorable"); }
// implement the property public int Status { get { return status; } set { status = value; } } } // Take our interface out for a spin
394
static void Main(string[] args) { // access the methods in the Document object Document doc = new Document("Test Document"); doc.Status = -1; doc.Read(); Console.WriteLine("Document Status: {0}", doc.Status); } Now lets see how the above code works: Example 10.1 defines a simple interface, IStorable, with two methods (Read ( ) and Write ( )) and a property (Status)
Of type integer. Notice that the property declaration does not provide an implementation for get ( ) and set ( ), but simply designates that there is a get ( ) and a set ( ): int Status { get; set; }
Notice also that the IStorable method declarations do not include access modifiers (e.g., public, protected, internal, private). In fact, providing an access modifier generates a compile error. Interface methods are implicitly public because an interface is a contract meant to be used by other classes. You cannot create an instance of an interface; instead you instantiate a class that implements the interface. The class implementing the interface must fulfill the contract exactly and completely. Document must provide both a Read ( ) and a Write ( ) method and the Status property. How it fulfills these requirements, however, is entirely up to the Document class. Although IStorable dictates that Document must have a Status property, it does not know or care whether Document stores the actual status as a member variable or looks it up in a database. The details are up to the implementing class.
395
public class Document : IStorable, ICompressible Having done this, the Document class must also implement the methods specified by the ICompressible interface (which is declared in Example 10-2): public void Compress( ) { Console.WriteLine ("Implementing the Compress Method"); } public void Decompress( ) { Console.WriteLine ("Implementing the Decompress Method"); }
396
ICompressible. ICompressible.
Example Try it out Eagles CombiningInterfaces Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles CombiningInterfaces in the Directory C:\EaglesVisualCSharp\Chapter 10\Example Extending and combining interfaces 2. Now add the following code in the body of the program.cs as follows: namespace Eagles_CombiningInterfaces { class Program { interface IStorable { void Read( ); void Write(object obj); int Status { get; set; } } // here's the new interface
397
interface ICompressible { void Compress( ); void Decompress( ); } // Extend the interface interface ILoggedCompressible : ICompressible { void LogSavedBytes( ); } // Combine Interfaces interface IStorableCompressible : IStorable, ILoggedCompressible { void LogOriginalSize( ); } // yet another interface interface IEncryptable { void Encrypt( ); void Decrypt( ); }
public class Document : IStorableCompressible, IEncryptable { // hold the data for IStorable's Status property private int status = 0; // the document constructor public Document(string s) { Console.WriteLine("Creating document with: {0}", s); } // implement IStorable
398
public void Read( ) { Console.WriteLine( "Implementing the Read Method for IStorable"); } public void Write(object o) { Console.WriteLine( "Implementing the Write Method for IStorable"); } public int Status { get { return status; } set { status = value; } } // implement ICompressible public void Compress( ) { Console.WriteLine("Implementing Compress"); } public void Decompress( ) { Console.WriteLine("Implementing Decompress"); } // implement ILoggedCompressible public void LogSavedBytes( ) { Console.WriteLine("Implementing LogSavedBytes"); }
399
// implement IStorableCompressible public void LogOriginalSize( ) { Console.WriteLine("Implementing LogOriginalSize"); } // implement IEncryptable public void Encrypt( ) { Console.WriteLine("Implementing Encrypt"); } public void Decrypt( ) { Console.WriteLine("Implementing Decrypt"); } }
static void Main(string[] args) { // create a document object Document doc = new Document("Test Document"); // cast the document to the various interfaces IStorable isDoc = doc as IStorable; if (isDoc != null) { isDoc.Read( ); } else Console.WriteLine("IStorable not supported"); ICompressible icDoc = doc as ICompressible;
400
if (icDoc != null) { icDoc.Compress( ); } else Console.WriteLine("Compressible not supported"); ILoggedCompressible ilcDoc = doc as ILoggedCompressible; if (ilcDoc != null) { ilcDoc.LogSavedBytes( ); ilcDoc.Compress( ); // ilcDoc.Read( ); } else Console.WriteLine("LoggedCompressible not supported"); IStorableCompressible isc = doc as IStorableCompressible; if (isc != null) { isc.LogOriginalSize( ); // IStorableCompressible isc.LogSavedBytes( ); // ILoggedCompressible isc.Compress( ); // ICompressible isc.Read( ); // IStorable } else { Console.WriteLine("StorableCompressible not supported"); } IEncryptable ie = doc as IEncryptable; if (ie != null) { ie.Encrypt( ); } else Console.WriteLine("Encryptable not supported"); } } }
401
4. Now run the application and you should have the output like this:
Lets see how the above code works: The Program starts by implementing the IStorable interface and the ICompressible interface. The latter is extended to ILoggedCompressible and then the two are combined into IStorableCompressible. Finally, the example adds a new interface, IEncryptable. The Eagles_CombiningInterfaces program creates a new Document object and then casts it to the various interfaces. When the object is cast to ILoggedCompressible, you can use the interface to call methods on Icompressible because ILoggedCompressible extends (and thus subsumes) the methods from the base interface: ILoggedCompressible ilcDoc = doc as ILoggedCompressible; if (ilcDoc != null) { ilcDoc.LogSavedBytes( ); ilcDoc.Compress( ); // ilcDoc.Read( ); }
402
You cannot call Read ( ), however, because that is a method of IStorable, an unrelated interface. And if you uncomment out the call to Read ( ), you will receive a compiler error. If you cast to IStorableCompressible which combines the extended interface with the Storable interface, you can then call methods of IStorableCompressible, Icompressible, and IStorable:
IStorableCompressible isc = doc as IStorableCompressible if (isc != null) { isc.LogOriginalSize( ); // IStorableCompressible isc.LogSavedBytes( ); // ILoggedCompressible isc.Compress( ); // ICompressible isc.Read( ); // IStorable }
You can also create an instance of the interface by casting the document to the interface type, and then use that interface to access the methods: IStorable isDoc = (IStorable) doc; isDoc.status = 0; isDoc.Read( );
403
In this case, in Main ( ) you know that Document is in fact an IStorable, so you can take advantage of that knowledge.
As stated earlier, you cannot instantiate an interface directly. That is, you cannot say: IStorable isDoc = new IStorable( );You can, however, create an instance of the implementing class, as in the following: Document doc = new Document("Test Document");You can then create an instance of the interface by casting the implementing object to the interface type, which in this case is IStorable: IStorable isDoc = (IStorable) doc; You can combine these steps by writing: IStorable isDoc = (IStorable) new Document ("Test Document");
In general, it is a better design decision to access the interface methods through an interface reference. Thus, it is better to use isDoc.Read ( ) than doc.Read ( ) in the previous example. Access through an interface allows you to treat the interface polymorphically. In other words, you can have two or more classes implement the interface, and then by accessing these classes only through the interface, you can ignore their real runtime type and treat them interchangeably.
404
If it turns out that Document implements only the IStorable interface: public class Document : IStorable
The cast to ICompressible would still compile because ICompressible is a valid interface. However, because of the illegal cast, when the program is run, an exception will be thrown: An exception of type System.InvalidCastException was thrown.
10.2.3The is Operator
You would like to be able to ask the object if it supports the interface, in order to then invoke the appropriate methods. In C# there are two ways to accomplish this. The first method is to use in the operator. The form of the is operator is: expression is type
The is operator evaluates true if the expression which must be a reference type can be safely cast to type without throwing an exception. The Following Example will illustrates the use of the is operator to test whether a Document implements the IStorable and ICompressible interfaces.
DENOTE: Java programmers take note: The C# is operator is the equivalent of Java's instance of.
405
Example Try it out Eagles ISOperator Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles ISOperator in the directory C:\EaglesVisualCSharp\Chapter 10\Example Using the Is Operator. 2. Add the following code in the body of the Program.cs as follows:
namespace Eagles_ISOperator { class Program { interface IStorable { void Read(); void Write(object obj); int Status { get; set; } } // here's the new interface interface ICompressible { void Compress(); void Decompress(); }
406
// Document implements IStorable public class Document : IStorable { private int status = 0; public Document(string s) { Console.WriteLine( "Creating document with: {0}", s); } // IStorable.Read public void Read() { Console.WriteLine("Implementing the Read Method for IStorable"); } // IStorable.Write public void Write(object o) { Console.WriteLine("Implementing the Write Method for IStorable"); } // IStorable.Status public int Status { get { return status; } set { status = value; } } }
407
3. Now add the following code in the Static Main method as follows:
Document doc = new Document("Eagles Test Document"); // only cast if it is safe if (doc is IStorable) { IStorable isDoc = (IStorable)doc; isDoc.Read(); } // this test will fail if (doc is ICompressible) { ICompressible icDoc = (ICompressible)doc; icDoc.Compress(); }
4. Now run the program and you should have the output like this:
408
Now lets see how the above code works: The above program differs from Example 10-2 in that Document no longer implements the ICompressible interface. Main ( ) now determines whether the cast is legal (sometimes referred to as safe) by evaluating the following if clause: if (doc is IStorable)
This is clean and nearly self-documenting. The if statement tells you that the cast will happen only if the object is of the right interface type. Unfortunately, this use of the is operator turns out to be inefficient. To understand why, you need to dip into the MSIL code that this generates. Here is a small excerpt note that the line numbers are in hexadecimal notation: IL_0023: IL_0028: IL_002a: IL_002b: IL_0030: IL_0031: IL_0032: isinst ICompressible brfalse.s IL_0039 ldloc.0 castclass ICompressible stloc.2 ldloc.2 callvirt instance void ICompressible::Compress( )
What is most important here is the test for ICompressible on line 17 in my computer. The keyword isinst is the MSIL code for the is operator. It tests to see if the object (doc) is in fact of the right type. Having passed this test we continue on to line 2b, in which cast class is called. Unfortunately, castclass also tests the type of the object. In effect, the test is done twice. A more efficient solution is to use the as operator.
409
Using the as operator eliminates the need to handle cast exceptions. At the same time you avoid the overhead of checking the cast twice. For these reasons, it is optimal to cast interfaces using as. The form of the as operator is: expression as type
The following code adapts the Eagles_ISOperator code from Example 10-3, using the as operator and testing for null: static void Main( ) { Document doc = new Document("Test Document"); IStorable isDoc = doc as IStorable; if (isDoc != null) isDoc.Read( ); else Console.WriteLine("IStorable not supported"); ICompressible icDoc = doc as ICompressible; if (icDoc != null) icDoc.Compress( );
else Console.WriteLine("Compressible not supported"); } A quick look at the comparable MSIL code shows that the following version is in fact more efficient: IL_0023: isinst ICompressible IL_0028: stloc.2 IL_0029: ldloc.2 IL_002a: brfalse.s IL_0034 IL_002c: ldloc.2 IL_002d: callvirt instance void ICompressible::Compress( )
410
Document
could now inherit from Storable, and there would not be much difference from using the interface. Suppose, however, that you purchase a List class from a third-party vendor whose capabilities you wish to combine with those specified by Storable? In C++, you could create a StorableList class and inherit from both List and Storable. But in C#, you're stuck; you can't inherit from both the Storable abstract class and also the List class because C# does not allow multiple inheritances with classes. However, C# does allow you to implement any number of interfaces and derive from one base class. Thus, by making Storable an interface, you can inherit from the List class and also from IStorable, as StorableList does in the following example: public class StorableList : List, IStorable { // List methods here ... public void Read( ) {...} public void Write(object obj) {...} // ... }
411
The Following Example Program will strips down the complexity of Example 10-3 and illustrates overriding an interface implementation. The Read ( ) method is marked as virtual and implemented by Document. Read ( ) is then overridden in a Note type that derives from Document.
Example Try it out Eagles overridinginterface Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles overridinginterface in the directory C:\EaglesVisualCSharp\Chapter 10\Example Using overriding an interface Implementation
412
amespace Eagles_overridinginterface { #region EaglesGroup /// <summary> /// EaglesSiddhu /// Siddhu /// Sri /// All Rights Reserved to EaglesGroup ///(C) EaglesGroup 1978 - 2010 /// </summary> #endregion class Program { // Declare the Interface here interface IStorable { void Read(); void Write(); } // Simplify Document to implement only IStorable public class Document : IStorable { // the document constructor public Document(string s)
413
{ Console.WriteLine( "Creating document with: {0}", s); } // Make read virtual public virtual void Read() { Console.WriteLine( "Document Read Method for IStorable"); } // NB: Not virtual! public void Write() { Console.WriteLine( "Document Write Method for IStorable"); } } // Derive from Document public class Note : Document { public Note(string s) : base(s) { Console.WriteLine( "Creating note with: {0}", s); } // override the Read method
414
public override void Read() { Console.WriteLine( "Overriding the Read method for Note!"); } // implement my own Write method public new void Write() { Console.WriteLine( "Implementing the Write method for Note!"); } }
3. Now add the following code in the Main () in the Program.cs as follows: static void Main(string[] args) { // create a document object Document theNote = new Note("Test Note"); IStorable isNote = theNote as IStorable; if (isNote != null) { isNote.Read( ); isNote.Write( ); } Console.WriteLine("\n"); // direct call to the methods theNote.Read( ); theNote.Write( ); Console.WriteLine("\n"); // create a note object Note note2 = new Note("Second Test"); IStorable isNote2 = note2 as IStorable; if (isNote2 != null) { isNote2.Read( ); isNote2.Write( ); } Console.WriteLine("\n"); // directly call the methods note2.Read( ); note2.Write( ); }
All Rights Reserved To EaglesGroup
415
4. Now run the application and you will have the output like this:
Now lets see hoe the above program works: In the above example, Document implements a simplified IStorable interface (simplified to make the example clearer): interface IStorable { void Read( ); void Write( ); } The designer of Document has opted to make the Read ( ) method virtual, but not to make the Write ( ) method virtual: public virtual void Read( )
416
In a real-world application, you would almost certainly mark both as virtual, but I've differentiated them to demonstrate that the developer is free to pick and choose which methods are made virtual. The new class Note derives from Document: public class Note : Document
It is not necessary for Note to override Read ( ), but it is free to do so and has in fact done so here: public override void Read( )
In Static, the Read and Write methods are called in four ways: Through the base class reference to a derived object Through an interface created from the base class reference to the derived object Through a derived object Through an interface created from the derived object To accomplish the first two calls, a Document (base class) reference is created, and the address of a new Note (derived) object created on the heap is assigned to the Document reference: Document theNote = new Note("Test Note"); An interface reference is created and the as operator is used to cast the Document to the IStorable reference: IStorable isNote = theNote as IStorable; You then invoke the Read ( ) and Write ( ) methods through that interface. The output reveals that the Read ( ) method is responded to polymorphically and the Write ( ) method is not, just as we would expect: Overriding the Read method for Note! Document Write Method for IStorable
417
The Read ( ) and Write ( ) methods are then called directly on the object itself: theNote.Read( ); theNote.Write( ); And once again you see the polymorphic implementation has worked: Overriding the Read method for Note! Document Write Method for IStorable In both cases, the Read ( ) method of Note is called and the Write ( ) method of Document is called. To prove to yourself that this is a result of the overriding method, next create a second Note object, this time assigning its address to a reference to a Note. This will be used to illustrate the final cases i.e., a call through a derived object and a call through an interface created from the derived object: Note note2 = new Note("Second Test");
Once again, when you cast to a reference, the overridden Read ( ) method is called. When, however, methods are called directly on the Note object: note2.Read( ); note2.Write( );
The output reflects that you've called a Note and not an overridden Document: Overriding the Read method for Note! Implementing the Write method for Note!
418
419
Explicit implementation is demonstrated in the following Example Lets work it out Using Explicit Implementation
Example Try it out Eagles ExplicitImplemention Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles ExplicitImplemention in the directory C:\EaglesVisualCSharp\Chapter 10\Example Using Explicit Implementation 2. Add the following code in the body of the Program.cs as follows:
namespace Eagles_ExplicitImplemention { # region EaglesGroup /// <summary> /// EaglesSiddhu /// Siddhu /// Sri /// All Rights Reserved To EaglesGroup /// (C) EaglesGroup 1978 - 2010 /// </summary> # endregion class Program { interface IStorable { void Read(); void Write(); }
420
interface ITalk { void Talk(); void Read(); } // Modify Document to implement IStorable and ITalk public class Document : IStorable, ITalk { // the document constructor public Document(string s) { Console.WriteLine("Creating document with: {0}", s); } // Make read virtual public virtual void Read() { Console.WriteLine("Implementing IStorable.Read"); } public void Write() { Console.WriteLine("Implementing IStorable.Write"); } void ITalk.Read() { Console.WriteLine("Implementing ITalk.Read"); } public void Talk() { Console.WriteLine("Implementing ITalk.Talk"); } }
421
3. Now add the following code in the Static void main() as follows:
static void Main(string[] args) { // create a document object Document theDoc = new Document("Test Document"); IStorable isDoc = theDoc as IStorable; if (isDoc != null) { isDoc.Read(); } ITalk itDoc = theDoc as ITalk; if (itDoc != null) { itDoc.Read(); } theDoc.Read(); theDoc.Talk(); } 4. Now Run the Program and you will have the output something like this:
422
Suppose you derive from that interface a new interface, IDerived, which hides the property P with a new method P ( ):
423
Setting aside whether this is a good idea, you have now hidden the property P in the base interface. An implementation of this derived interface will require at least one explicit interface member. You can use explicit implementation for either the base property or the derived method, or you can use explicit implementation for both.
Generally, it is preferable to access the methods of an interface through an interface cast. The exception is with value types (e.g., structs) or with sealed classes. In that case, it is preferable to invoke the interface method through the object. When you implement an interface in a struct, you are implementing it in a value type. When you cast to an interface reference, there is an implicit boxing of the object. Unfortunately, when you use that interface to modify the object, it is the boxed object, not the original value object, that is modified. Further, if you change the value type, the boxed type will remain unchanged. In the Below Example Program we will creates a struct that implements IStorable and illustrates the impact of implicit boxing when you cast the struct to an interface reference. Lets work it out Using References on value Types
Example Try it out Eagles valuetype Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles value type in the directory C:\EaglesVisualCSharp\Chapter 10\Example Using References on Value Types 2. Add the following code in the body of the Program.cs as follows:
424
amespace Eagles_valuetype { # region EaglesGroup /// <EaglesGroup> /// EaglesSiddhu /// Siddhu /// Sri /// Somu /// (C) EaglesGroup 1978 - 2010 /// All Rights Reserved to EaglesGroup /// </EaglesGroup> # endregion class Program { // declare a simple interface interface IStorable { void Read(); int Status { get;set;} } // Implement through a struct public struct myStruct : IStorable { public void Read() { Console.WriteLine( "Implementing IStorable.Read"); } public int Status { get { return status; } set { status = value; } }
425
private int status; } 3. Now add the following code in the Static Void Main() as follows in the Program.cs static void Main(string[] args) { // create a myStruct object myStruct theStruct = new myStruct( ); theStruct.Status = -1; // initialize Console.WriteLine( "theStruct.Status: {0}", theStruct.Status); // Change the value theStruct.Status = 2; Console.WriteLine("Changed object."); Console.WriteLine( "theStruct.Status: {0}", theStruct.Status); // cast to an IStorable // implicit box to a reference type IStorable isTemp = (IStorable) theStruct; // set the value through the interface reference isTemp.Status = 4; Console.WriteLine("Changed interface."); Console.WriteLine("theStruct.Status: {0}, isTemp: {1}", theStruct.Status, isTemp.Status); // Change the value again theStruct.Status = 6; Console.WriteLine("Changed object."); Console.WriteLine("theStruct.Status: {0}, isTemp: {1}", theStruct.Status, isTemp.Status); }
426
4. Now Run the Program.cs and you will have the output like this:
Now lets see how the above program works: In the above program, the IStorable interface has a method (Read) and a property (Status). This interface is implemented by the struct named myStruct: public struct myStruct : IStorable
The interesting code is in Eagles_valuetype. Start by creating an instance of the structure and initializing its property to -1. The status value is then printed: myStruct theStruct = new myStruct( ); theStruct.status = -1; // initialize Console.WriteLine( "theStruct.Status: {0}", theStruct.status);
427
The output from this shows that the status was set properly: theStruct.Status: -1
Next access the property to change the status, again through the value object itself: // Change the value theStruct.status = 2; Console.WriteLine("Changed object."); Console.WriteLine( "theStruct.Status: {0}", theStruct.status);
No surprises so far. At this point, create a reference to the IStorable interface. This causes an implicit boxing of the value object theStruct. Then use that interface to change the status value to 4: // cast to an IStorable // implicit box to a reference type IStorable isTemp = (IStorable) theStruct; // set the value through the interface reference isTemp.status = 4; Console.WriteLine("Changed interface."); Console.WriteLine("theStruct.Status: {0}, isTemp: {1}", theStruct.status, isTemp.status);
428
Aha! The object to which the interface reference points has been changed to a status value of 4, but the struct value object is unchanged. Even more interesting, when you access the method through the object itself: // Change the value again theStruct.status = 6; Console.WriteLine("Changed object."); Console.WriteLine("theStruct.Status: {0}, isTemp: {1}", theStruct.status, isTemp.status);
The output reveals that the value object has been changed, but the boxed reference value for the interface reference has not: Changed object. theStruct.Status: 6, isTemp: 4
429
Summary
In this chapter, we have looked at the important topic of interfaces. Although, initially difficult to get your head around, the code involved is quiet simple and youll certainly be using event handlers a lot in the rest of the book. The topics so far we covered are as follows: Introduction to Interfaces Implementing an Interface Implementing More Than One Interface Extending Interfaces Combining Interfaces Accessing Interface Methods Casting to an Interface The is Operator The as Operator The is Operator Versus the as Operator Interface Versus Abstract Class Overriding Interface Implementations Explicit Interface Implementation Selectively Exposing Interface Methods Member Hiding Accessing Sealed Classes and Value Types
430
Chapter 11
431
432
A delegate is created with the delegate keyword, followed by a return type and the signature of the methods that can be delegated to it, as in the following: public delegate int WhichIsFirst(object obj1, object obj2);
This declaration defines a delegate named WhichIsFirst, which will encapsulate any method that takes two objects as parameters and that returns an int. Once the delegate is defined, you can encapsulate a member method with that delegate by instantiating the delegate, passing in a method that matches the return type and signature. The delegate can then be used to invoke that encapsulated method.
433
In this definition, WhichIsFirst is defined to encapsulate a method that takes two objects as parameters, and that returns an object of type Comparison. Comparison turns out to be an enumeration you will define: public enum Comparison { theFirstComesFirst = 1, theSecondComesFirst = 2 }
To test the delegate, you will create two classes, a Dog class and a Student class. Dogs and Students have little in common, except that they both implement methods that can be encapsulated by WhichComesFirst, and thus both Dog objects and Student objects are eligible to be held within Pair objects. In the test program, you will create a couple of Students and a couple of Dogs, and store them each in a Pair. You will then create instances of WhichIsFirst to encapsulate their respective methods that will determine which Student or which Dog object should be first, and which second. Let's take this step by step. You begin by creating a Pair constructor that takes two objects and stashes them away in a private array: public class Pair { // hold both objects private object[]thePair = new object[2]; // two objects, added in order received public Pair(object firstObject, object secondObject) { thePair[0] = firstObject; thePair[1] = secondObject; }
434
Next, you override ToString ( ) to obtain the string value of the two objects: public override string ToString( ) { return thePair [0].ToString( ) + ", " + thePair[1].ToString( ); }
You now have two objects in your Pair and you can print out their values. You're ready to sort them and print the results of the sort. You can't know in advance what kind of objects you will have, so you delegate the responsibility of deciding which object comes first in the sorted Pair to the objects themselves. Both the Dog class and the Student class implement methods that can be encapsulated by WhichIsFirst. Any method that takes two objects and returns a comparison can be encapsulated by this delegate at runtime. You can now define the Sort ( ) method for the Pair class: public void Sort(WhichIsFirst theDelegatedFunc) { if (theDelegatedFunc(thePair[0],thePair[1]) == comparison.theSecondComesFirst) { object temp = thePair[0]; thePair[0] = thePair[1]; thePair[1] = temp; } }
This method takes a parameter: a delegate of type WhichIsFirst named theDelegatedFunc. The Sort ( ) method delegates responsibility for deciding which of the two objects in the Pair comes first to the method encapsulated by that delegate. In the body of the Sort ( ) method, it invokes the delegated method and examines the return value, which will be one of the two enumerated values of comparison. If the value returned is theSecondComesFirst, the objects within the pair are swapped; otherwise no action is taken.
435
This is analogous to how the other parameters work. If you had a method that took an int as a parameter: int SomeMethod (int myParam){//...}
The parameter name is myParam, but you can pass in any int value or variable. Similarly, the parameter name in the delegate example is theDelegatedFunc, but you can pass in any method that meets the return value and signature defined by the delegate WhichIsFirst. Imagine you are sorting Students by name. You write a method that returns theFirstComesFirst if the first student's name comes first and theSecondComesFirst if the second student's name does. If you pass in "siddhu, sambu" the method will return theFirstComesFirst, and if you pass in "sambu, siddhu" it will return theSecondComesFirst. If you get back theSecondComesFirst, the Sort ( ) method reverses the items in its array, setting Amy to the first position and Beth to the second. Now add one more method, ReverseSort ( ), which will force the items in the array into the reverse of their normal order: public void ReverseSort(WhichIsFirst theDelegatedFunc) { if (theDelegatedFunc(thePair[0], thePair[1]) == comparison.theFirstComesFirst) { object temp = thePair[0]; thePair[0] = thePair[1]; thePair[1] = temp; } } The logic here is identical to Sort ( ), except that this method performs the swap if the delegated method says that the first item comes first. Because the delegated function thinks the first item comes first, and this is a reverse sort, the result you want is for the second item to come first. This time if you pass in "siddhu, sambu," the delegated function returns theFirstComesFirst (i.e., Amy should come first), but because this is a reverse sort, it swaps the values, setting Beth first. This allows you to use the same delegated function as you used with Sort ( ), without forcing the object to support a function that returns the reverse sorted value.
436
Now all you need are some objects to sort. You'll create two absurdly simple classes: Student and Dog. Assign Student objects a name at creation: public class Student { public Student(string name) { this.name = name; }
The Student class requires two methods: one to override ToString ( ) and the other to be encapsulated as the delegated method. Student must override ToString ( ) so that the ToString ( ) method in Pair, which invokes ToString ( ) on the contained objects, will work properly; the implementation does nothing more than return the student's name (which is already a string object): public override string ToString( ) { return name ; }
It must also implement a method to which Pair.Sort ( ) can delegate the responsibility of determining which of two objects comes first: return (String.Compare (s1.name, s2.name) < 0? comparison.theFirstComesFirst: comparison.theSecondComesFirst); String.Compare( ) is a .NET Framework method on the String class that compares two strings and returns less than zero if the first is smaller, greater than zero if the second is smaller, and zero if they are the same. DENOTE: That the logic here returns theFirstComesFirst only if the first string is smaller; if they are the same or the second is larger, this method returns theSecondComesFirst. The WhichStudentComesFirst ( ) method takes two objects as parameters and returns a comparison. This qualifies it to be a Pair.WhichIsFirst delegated method, whose signature and return value it matches.
437
The second class is Dog. For our purposes, Dog objects will be sorted by weight, lighter dogs before heavier. Here's the complete declaration of Dog: public class Dog { public Dog(int weight) { this.weight=weight; } // dogs are ordered by weight public static comparison WhichDogComesFirst( Object o1, Object o2) { Dog d1 = (Dog) o1; Dog d2 = (Dog) o2; return d1.weight > d2.weight ? comparison.theSecondComesFirst : comparison.theFirstComesFirst; } public override string ToString( ) { return weight.ToString( ); } private int weight; }
The Dog class also overrides ToString and implements a static method with the correct signature for the delegate. Notice also that the Dog and Student delegate methods do not have the same name. They do not need to have the same name, as they will be assigned to the delegate dynamically at runtime.
438
Example Try it out Eagles Delegates Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles Delegates in the directory C:\EaglesVisualCSharp\Chapter 11 - Events\Example Using Delegates 2. Add the following code into the body of the Program.cs as follows: amespace Eagles_Delegates { class Program { public enum Comparison { theFirstComesFirst = 1, theSecondComesFirst = 2 } // a simple collection to hold 2 items public class Pair { // private array to hold the two objects private object[] thePair = new object[2]; // the delegate declaration public delegate Comparison WhichIsFirst(object obj1, object obj2); // passed in constructor take two objects, // added in order received public Pair( object firstObject, object secondObject) { thePair[0] = firstObject; thePair[1] = secondObject; } // public method which orders the two objects // by whatever criteria the object likes!
439
public void Sort( WhichIsFirst theDelegatedFunc) { if (theDelegatedFunc(thePair[0],thePair[1]) == Comparison.theSecondComesFirst) { object temp = thePair[0]; thePair[0] = thePair[1]; thePair[1] = temp; } } // public method which orders the two objects // by the reverse of whatever criteria the object likes! public void ReverseSort( WhichIsFirst theDelegatedFunc) { if (theDelegatedFunc(thePair[0],thePair[1]) == Comparison.theFirstComesFirst) { object temp = thePair[0]; thePair[0] = thePair[1]; thePair[1] = temp; } } // ask the two objects to give their string value
public override string ToString() { return thePair[0].ToString() + ", " + thePair[1].ToString(); } } // end class Pair public class Dog { private int weight; public Dog(int weight) { this.weight = weight; }
440
// dogs are ordered by weight public static Comparison WhichDogComesFirst( Object object1, Object object2) { Dog dog1 = (Dog)object1; Dog dog2 = (Dog)object2; return dog1.weight > dog2.weight ? Comparison.theSecondComesFirst : Comparison.theFirstComesFirst; } public override string ToString() { return weight.ToString(); } } // end class Dog public class Student { private string name; public Student(string name) { this.name = name; } // students are ordered alphabetically public static Comparison WhichStudentComesFirst(Object o1, Object o2) { Student student1 = (Student)o1; Student student2 = (Student)o2; return (String.Compare(student1.name, student2.name) < 0 ? Comparison.theFirstComesFirst : Comparison.theSecondComesFirst); } public override string ToString() { return name; } } // end class Student
441
3. Now add the following code into the Main () of the Program.cs as follows:
static void Main(string[] args) { // create two students and two dogs // and add them to Pair objects Student Siddhu = new Student("Siddhu"); Student Sambu = new Student("Sambu"); Dog Blacky = new Dog(65); Dog Jimmy = new Dog(12); Dog Puppy = new Dog(20); Pair studentPair = new Pair(Siddhu, Sambu); Pair dogPair = new Pair(Blacky, Jimmy); Console.WriteLine("studentPair\t\t\t: {0}", studentPair.ToString()); Console.WriteLine("dogPair\t\t\t\t: {0}", dogPair.ToString());
// Instantiate the delegates Pair.WhichIsFirst theStudentDelegate = new Pair.WhichIsFirst( Student.WhichStudentComesFirst); Pair.WhichIsFirst theDogDelegate = new Pair.WhichIsFirst( Dog.WhichDogComesFirst); // sort using the delegates studentPair.Sort(theStudentDelegate); Console.WriteLine("After Sort studentPair\t\t: {0}", studentPair.ToString()); studentPair.ReverseSort(theStudentDelegate); Console.WriteLine("After ReverseSort studentPair\t: {0}", studentPair.ToString());
442
dogPair.Sort(theDogDelegate); Console.WriteLine("After Sort dogPair\t\t: {0}", dogPair.ToString()); dogPair.ReverseSort(theDogDelegate); Console.WriteLine("After ReverseSort dogPair\t: {0}", dogPair.ToString()); } 4. Now Run the program and the you will get the output something like this:
Lets see how the above code works: The Eagles Delegates program creates two Student objects and two Dog objects and then adds them to Pair containers. The student constructor takes a string for the student's name and the dog constructor takes an int for the dog's weight.
443
Student Siddhu = new Student("Siddhu"); Student Sambu = new Student ("Sambu"); Dog Blacky = new Dog(65); Dog Jimmy = new Dog(12); Dog Puppy = new Dog (20); Pair studentPair = new Pair(Siddhu,Sambu); Pair dogPair = new Pair(Blacky, Jimmy); Console.WriteLine("studentPair\t\t\t: {0}", studentPair.ToString( )); Console.WriteLine("dogPair\t\t\t\t: {0}", dogPair.ToString( ));
It then prints the contents of the two Pair containers to see the order of the objects. The output looks like this: studentPair dogPair : Siddhu, Sambu : 65, 12
As expected, the objects are in the order in which they were added to the Pair containers. We next instantiate two delegate objects: Pair.WhichIsFirst theStudentDelegate = new Pair.WhichIsFirst( Student.WhichStudentComesFirst); Pair.WhichIsFirst theDogDelegate = new Pair.WhichIsFirst( Dog.WhichDogComesFirst);
The first delegate, theStudentDelegate, is created by passing in the appropriate static method from the Student class. The second delegate, theDogDelegate, is passed a static method from the Dog class.
444
The delegates are now objects that can be passed to methods. You pass the delegates first to the Sort ( ) method of the Pair object, and then to the ReverseSort ( ) method. The results are printed to the console
The delegate is then instantiated using the class rather than an instance: Pair.WhichIsFirst theStudentDelegate = new Pair.WhichIsFirst( Student.WhichStudentComesFirst);
You can just as easily encapsulate instance methods public Comparison WhichStudentComesFirst(Object o1, Object o2)
445
In which case you will instantiate the delegate by passing in the instance method as invoked through an instance of the class, rather than through the class itself: Pair.WhichIsFirst theStudentDelegate = new Pair.WhichIsFirst( Jesse.WhichStudentComesFirst);
This creates a static, read-only delegate named OrderStudents DENOTE: Marking OrderStudents read-only denotes that once this static field is created, it will not be modified. You can create a similar delegate within the Dog class
446
These are now static fields of their respective classes. Each is prewired to the appropriate method within the class. You can invoke delegates without declaring a local delegate instance. You just pass in the static delegate of the class: studentPair.Sort(Student.OrderStudents); Console.WriteLine("After Sort studentPair\t\t: {0}", studentPair.ToString( )); studentPair.ReverseSort(Student.OrderStudents); Console.WriteLine("After ReverseSort studentPair\t: {0}", studentPair.ToString( )); dogPair.Sort(Dog.OrderDogs); Console.WriteLine("After Sort dogPair\t\t: {0}", dogPair.ToString( )); dogPair.ReverseSort(Dog.OrderDogs); Console.WriteLine("After ReverseSort dogPair\t: {0}", dogPair.ToString( ));
447
When the OrderStudent property is accessed, the delegate is created: return new Pair.WhichIsFirst(WhichStudentComesFirst);
The key advantage is that the delegate is not created until it is requested. This allows the test class to determine when it needs a delegate, but still allows the details of the creation of the delegate to be the responsibility of the Student or Dog class.
448
You can create delegates for each operation and add them to an ordered collection, such as an array, in the order you'd like them to execute. Once all the delegates are created and added to the collection, you simply iterate over the array, invoking each delegated method in turn. You begin by creating a class, Image, to represent the image that will be processed by the Eagles_ImageProcessor: public class EaglsImage { public Image( ) { Console.WriteLine("An image created"); } }
DENOTE: You can imagine that this stands in for a .gif or .jpeg file or other image The Eagles_ImageProcessor then declares a delegate. You can of course define your delegate to return any type and take any parameters you like. For this example, you'll define the delegate to encapsulate any method that returns void and takes no arguments: public delegate void DoEffect( ); The Eagles_ImageProcessor then declares a number of methods, each of which processes an image and each of which matches the return type and signature of the delegate:
449
public static void Blur( ) { Console.WriteLine("Blurring image"); } public static void Filter( ) { Console.WriteLine("Filtering image"); } public static void Sharpen( ) { Console.WriteLine("Sharpening image"); } public static void Rotate( ) { Console.WriteLine("Rotating image"); }
DENOTE: In a production environment, these methods would be very complicated, and they'd actually do the work of blurring, filtering, sharpening, and rotating the image
The Eagles_ImageProcessor class needs an array to hold the delegates that the user picks, a variable to hold the running total of how many effects are in the array, and of course a variable for the image itself
450
The Eagles_ImageProcessor also needs a method to add delegates to the array public void AddToEffects(DoEffect theEffect) { if (numEffectsRegistered >= 10) { throw new Exception("Too many members in array"); } arrayOfEffects[numEffectsRegistered++] = theEffect; }
It needs another method to actually call each method in turn public void Eagles_ProcessImages( ) { for (int i = 0;i < numEffectsRegistered;i++) { arrayOfEffects[i]( ); } }
Finally, you need to declare the static delegates that the client can call, hooking them to the processing methods public DoEffect BlurEffect = new DoEffect(Blur); public DoEffect SharpenEffect = new DoEffect(Sharpen); public DoEffect FilterEffect = new DoEffect(Filter); public DoEffect RotateEffect = new DoEffect(Rotate);
DENOTE: In a production environment, in which you might have dozens of effects, you might choose to make these properties rather than static methods. That would save creating the effects unless they are needed, at the cost of making the program slightly more complicated.
451
The client code would normally have an interactive user-interface component, but we'll
simulate that by choosing the effects, adding them to the array, and then calling Eagles_ProcessImage, as shown in Example 11-2.
Example Try it out Eagles ProcessImage Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles ProcessImage in the directory C:\EaglesVisualCSharp\Chapter 11 - Events\Example Using array of delegates
452
2. Add the following code in the body of the Program.cs as follows: namespace Eagles_ProcessImage { // the image which we'll manipulate class Program { public class Image { public Image() { Console.WriteLine("An image created"); } } public class ImageProcessor { // declare the delegate public delegate void DoEffect( ); // create various static delegates tied to member methods public DoEffect BlurEffect = new DoEffect(Blur); public DoEffect SharpenEffect = new DoEffect(Sharpen); public DoEffect FilterEffect = new DoEffect(Filter); public DoEffect RotateEffect = new DoEffect(Rotate); // the constructor initializes the image and the array public ImageProcessor(Image image) { this.image = image; arrayOfEffects = new DoEffect[10]; } // in a production environment we'd use a more // flexible collection.
453
public void AddToEffects(DoEffect theEffect) { if (numEffectsRegistered >= 10) { throw new Exception( "Too many members in array"); } arrayOfEffects[numEffectsRegistered++] = theEffect; } // the image processing methods... public static void Blur() { Console.WriteLine("Blurring image"); } public static void Filter() { Console.WriteLine("Filtering image"); } public static void Sharpen() { Console.WriteLine("Sharpening image"); } public static void Rotate() { Console.WriteLine("Rotating image"); } public void ProcessImages() { for (int i = 0; i < numEffectsRegistered; i++) { arrayOfEffects[i](); } }
454
// private member variables... private DoEffect[] arrayOfEffects; private Image image; private int numEffectsRegistered = 0; } // test the Process
3. Now add the following code into the Static Main () as follows:
static void Main(string[] args) { Image theImage = new Image(); // no ui to keep things simple, just pick the // methods to invoke, add them in the required // order, and then call on the image processor to // run them in the order added. ImageProcessor theProc = new ImageProcessor(theImage); theProc.AddToEffects(theProc.BlurEffect); theProc.AddToEffects(theProc.FilterEffect); theProc.AddToEffects(theProc.RotateEffect); theProc.AddToEffects(theProc.SharpenEffect); theProc.ProcessImages(); }
455
4. Now run the program and you will have the output like this:
Now lets see how the above the code works: In the Test class of Example 11-2, the ImageProcessor is instantiated, and effects are added. If the user chooses to blur the image before filtering the image, it is a simple matter to add the delegates to the array in the appropriate order. Similarly, any given operation can be repeated as often as the user desires, just by adding more delegates to the collection. You can imagine displaying the order of operations in a listbox that might allow the user to reorder the methods, moving them up and down the list at will. As the operations are reordered, you need only change their sort order in the collection. You might even decide to capture the order of operations to a database and then load them dynamically, instantiating delegates as dictated by the records you've stored in the database. Delegates provide the flexibility to determine dynamically which methods will be called, in what order, and how often.
456
457
Subscribing to an event means supplying code that will be executed when an event is raised in the form of an event handler. An event can have many handles subscribed to it, which will all be called when the event is raised. This may include event handlers that are part of the class of the object that raises the event but event handles are just as like to be found in other classes. Event handlers themselves are simply functions. The only restriction on an event handler function is that must match the signature (return type and parameters) required by the event. This signature is part of the definition of an event, and is specified by a delegate. DENOTE: The fact that delegates are used in events in events is what makes delegates such useful thing. This is the reason we devoted sometime to the back in chapter 5, and you may wish to re-read that section to refresh your memory as to what delegates are and how we use them. The sequence of processing goes something like this: First, an application creates an object that can raise an event. As an example, lets say that the application is an instant messaging application, and that the object it creates represents a connection to a remote user. This connection object might raise an event, say, when a message arrives through the connection from the remote user.
Picture 11.1
Application
Creates
Connection
Next, the application subscribes to the event. Our instant messaging application would do this by defining a function that could be used with the delegate type specified by the event, and passing a reference to this function to the event. This event handler function might be a method on another object. Lets say an object representing a display device to display instant message on when they arrive.
458
Picture 11.2
Application
Connection
When the event is raised, the subscriber is notified. When an instant message arrives through the connection object, the event handler method on the display device object is called. As we are using a standard method, the object that raises the event may pass any relevant information via parameters, making events very versatile. In our example case, one parameter might be the text of the instant message, which the event handler could display on the display device object.
Picture 11.3
Application
459
460
461
without breaking any of the subscribing classes. The subscribing classes can change how they respond to time changes without breaking the Clock. The two classes spin independently of one another, and that makes for code that is easier to maintain.
A method that handles an event is called an event handler. You can declare your event handlers as you would any other delegate.
By convention, event handlers in the .NET Framework return void and take two parameters. The first parameter is the "source" of the event that is, the publishing object. The second parameter is an object derived from EventArgs. It is recommended that your event handlers follow this design pattern. DENOTE: VB6 programmers take note: C# doesn't put restrictions on the names of the methods that handle events. Also, the .NET implementation of the publish/subscribe model lets you have a single method that subscribes to multiple events.
EventArgs is the base class for all event data. Other than its constructor, the EventArgs class inherits all its methods from Object, though it does add a public static field named empty, which represents an event with no state (to allow for the efficient use of events with no state). The EventArgs derived class contains information about the event. Suppose you want to create a Clock class that uses delegates to notify potential subscribers whenever the local time changes value by one second. Call this delegate SecondChangeHandler The declaration for the SecondChangeHandler delegate is: public delegate void SecondChangeHandler( object clock, TimeInfoEventArgs timeInformation );
462
This delegate will encapsulate any method that returns void and that takes two parameters. The first parameter is an object that represents the clock the object raising the event, and the second parameter is an object of type TimeInfoEventArgs that will contain useful information for anyone interested in this event. TimeInfoEventArgs is defined as follows: public class TimeInfoEventArgs : EventArgs { public TimeInfoEventArgs(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } public readonly int hour; public readonly int minute; public readonly int second; }
The TimeInfoEventArgs object will have information about the current hour, minute, and second. It defines a constructor and three public, read-only integer variables.
In addition to its delegate, a Clock has three member variableshour, minute, and secondas well as a single method, Run( ): public void Run( ) { for(;;) { // sleep 10 milliseconds Thread.Sleep(10); // get the current time System.DateTime dt = System.DateTime.Now; // if the second has changed // notify the subscribers if (dt.Second != second) { // create the TimeInfoEventArgs object // to pass to the subscriber
All Rights Reserved To EaglesGroup
463
TimeInfoEventArgs timeInformation = new TimeInfoEventArgs( dt.Hour,dt.Minute,dt.Second); // if anyone has subscribed, notify them if (OnSecondChange != null) { OnSecondChange(this,timeInformation); } } // update the state this.second = dt.Second; this.minute = dt.Minute; this.hour = dt.Hour; } }
Run ( ) creates an infinite for loop that periodically checks the system time. If the time has changed from the Clock object's current time, it notifies all its subscribers and then updates its own state.
This makes use of a static method of the Thread class from the System.Threading namespace, the call to Sleep ( ) prevents the loop from running so tightly that little else on the computer gets done.
After sleeping for 10 milliseconds, the method checks the current time: System.DateTime dt = System.DateTime.Now;
464
About every 100 times it checks, the second will have incremented. The method notices that change and notifies its subscribers. To do so, it first creates a new TimeInfoEventArgs object: if (dt.Second != second) { // create the TimeInfoEventArgs object // to pass to the subscriber TimeInfoEventArgs timeInformation = new TimeInfoEventArgs(dt.Hour,dt.Minute,dt.Second);
It then notifies the subscribers by firing the OnSecondChange event: // if anyone has subscribed, notify them if (OnSecondChange != null) { OnSecondChange(this,timeInformation); } If an event has no subscribers registered, it will evaluate to null. The test above checks } that the value is not null, ensuring that there are subscribers before calling OnSecondChange. You will remember that OnSecondChange takes two arguments: the source of the event and the object derived from EventArgs. In the snippet, you see that the clocks this reference is passed because the clock is the source of the event. The second parameter is the TimeInfoEventArgs object, timeInformation, created on the line above. Raising the event will invoke whatever methods have been registered with the Clock class through the delegate. We'll examine this in a moment. Once the event is raised, you update the state of the Clock class:
465
All that is left is to create classes that can subscribe to this event. You'll create two. First will be the DisplayClock class. The job of DisplayClock is not to keep track of time, but rather to display the current time to the console. The example simplifies this class down to two methods. The first is a helper method named Subscribe ( ) that is used to subscribe to the clock's OnSecondChange delegate. The second method is the event handler TimeHasChanged ( ):
public class DisplayClock { public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(TimeHasChanged); } public void TimeHasChanged( object theClock, TimeInfoEventArgs ti) { Console.WriteLine("Current Time: {0}:{1}:{2}", ti.hour.ToString( ), ti.minute.ToString( ), ti.second.ToString( )); } }
When the first method, Subscribe ( ), is invoked, it creates a new SecondChangeHandler delegate, passing in its event handler method, TimeHasChanged ( ). It then registers that delegate with the OnSecondChange event of Clock.
You will create a second class that will also respond to this event, LogCurrentTime. This class would normally log the event to a file, but for our demonstration purposes, it will log to the standard console:
466
public class LogCurrentTime { public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(WriteLogEntry); } // this method should write to a file // we write to the console to see the effect // this object keeps no state public void WriteLogEntry( object theClock, TimeInfoEventArgs ti) { Console.WriteLine("Logging to file: {0}:{1}:{2}", ti.hour.ToString( ), ti.minute.ToString( ), ti.second.ToString( )); } } Although in this example these two classes are very similar, in a production program any number of disparate classes might subscribe to an event. All that remains is to create a Clock class, create the DisplayClock class, and tell it to subscribe to the event. You then will create a LogCurrentTime class and tell it to subscribe as well.
467
Example Try it out Eagles Events&delegates Step by Step Example: Using Version 2005
1. Create a new Console Application called it EaglesEventsDelegents in the directory C:\EaglesVisualCSharp\Chapter 11 - Events\ Example Using Eventsdelegates 2. Now add the following code in the System. Namespace as follows: using System; using System.Collections.Generic; using System.Text; using System.Threading;
468
3. Now add the following code into the body of the Program.cs as follows: namespace EaglesEventsDelegents { class Program { // a class to hold the information about the event // in this case it will hold only information // available in the clock class, but could hold // additional state information public class TimeInfoEventArgs : EventArgs { public TimeInfoEventArgs(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } public readonly int hour; public readonly int minute; public readonly int second; } // our subject -- it is this class that other classes // will observe. This class publishes one delegate: // OnSecondChange. public class Clock { // the delegate the subscribers must implement public delegate void SecondChangeHandler ( object clock, TimeInfoEventArgs timeInformation );
469
// an instance of the delegate public SecondChangeHandler OnSecondChange; // set the clock running // it will raise an event for each new second public void Run() { for (; ; ) { // sleep 10 milliseconds Thread.Sleep(10); // get the current time System.DateTime dt = System.DateTime.Now; // if the second has changed // notify the subscribers if (dt.Second != second) { // create the TimeInfoEventArgs object // to pass to the subscriber TimeInfoEventArgs timeInformation = new TimeInfoEventArgs( dt.Hour, dt.Minute, dt.Second); // if anyone has subscribed, notify them if (OnSecondChange != null) { OnSecondChange( this, timeInformation); } }
470
// update the state this.second = dt.Second; this.minute = dt.Minute; this.hour = dt.Hour; } } private int hour; private int minute; private int second; } // an observer. DisplayClock subscribes to the // clock's events. The job of DisplayClock is // to display the current time
public class DisplayClock { // given a clock, subscribe to // its SecondChangeHandler event public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(TimeHasChanged); } // the method that implements the // delegated functionality public void TimeHasChanged( object theClock, TimeInfoEventArgs ti) { Console.WriteLine("Current Time: {0}:{1}:{2}", ti.hour.ToString(), ti.minute.ToString(), ti.second.ToString()); } } // a second subscriber whose job is to write to a file
471
public class LogCurrentTime { public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(WriteLogEntry); } // this method should write to a file // we write to the console to see the effect // this object keeps no state public void WriteLogEntry( object theClock, TimeInfoEventArgs ti) { Console.WriteLine("Logging to file: {0}:{1}:{2}", ti.hour.ToString(), ti.minute.ToString(), ti.second.ToString()); } }
4. Now Add the following code into the Static Main () as follows: static void Main(string[] args) { // create a new clock Clock theClock = new Clock(); // create the display and tell it to // subscribe to the clock just created DisplayClock dc = new DisplayClock(); dc.Subscribe(theClock); // create a Log object and tell it // to subscribe to the clock LogCurrentTime lct = new LogCurrentTime(); lct.Subscribe(theClock); // Get the clock started theClock.Run(); }
472
5. Now run the application and you will have the output like this:
Now lets see how the above the code works: The net effect of this code is to create two classes, DisplayClock and LogCurrentTime, both of which subscribe to a third class' event (Clock.OnSecondChange). OnSecondChange is a multicast delegate. It starts out set to null. When the observer classes wish to be notified, they create an instance of the delegate and then add these delegates to OnSecondChange. For example, in DisplayClock's Subscribe ( ) method, you see this line of code: theClock.OnSecondChange += new Clock.SecondChangeHandler(TimeHasChanged);
It turns out that the LogCurrentTime class also wants to be notified. In its Subscribe ( ) method is very similar code:
473
If you make that one tiny change to the example, you'll find that the Logger ( ) method is called, but the DisplayClock method is not called. The assignment operator replaced the delegate held in the OnSecondChange multicast delegate. This is not good.
A second problem is that other methods can call SecondChangeHandler directly. For example, you might add the following code to the Main ( ) method of your Test class:
474
Console.WriteLine("Calling the method directly!"); System.DateTime dt = System.DateTime.Now.AddHours(2); TimeInfoEventArgs timeInformation = new TimeInfoEventArgs( dt.Hour,dt.Minute,dt.Second); theClock.OnSecondChange(theClock, timeInformation);
Here Main ( ) has created its own TimeInfoEventArgs object and invoked OnSecondChange directly. This runs fine, even though it is not what the designer of the Clock class intended. Here is the output
The problem is that the designer of the Clock class intended the methods encapsulated by the delegate to be invoked only when the event is fired. Here Main ( ) has gone around through the back door and invoked those methods itself. What is more, it has passed in bogus data passing in a time construct set to two hours into the future!
475
Example Try it out Eagles HandlingEvents Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles HandlingEvents in the directory C:\EaglesVisualCSharp\Chapter 11 Events\Example Using HandlingEvents 2. Now enter the following code in the System. Namespace as follows using System; using System.Collections.Generic; using System.Text; using System.Timers;
3. Now enter the following code in the body of the program.cs as follows: class Program { static int counter = 0; static string displayString = "Welcome to EaglesGroup ! "; static void Main(string[] args) { Timer siddhu = new Timer(100); siddhu.Elapsed += new ElapsedEventHandler(WriteChar); siddhu.Start(); Console.ReadLine(); } static void WriteChar(object source, ElapsedEventArgs sri) { Console.Write(displayString[counter++ % displayString.Length]); } }
476
4. Run the application and the program will continuously will run and if you want to exit the program hit enter the program will terminate the application.
Lets see how the above code works: The object we are using to raise events is an instance of the system.Timers.Timerclass. This object is initialized with a time period (in milliseconds). When the timer object is started using its start () method a stream of events will be raised, spaced out in time according to the specified time period. Main (). Initializes a timer object with a timer period of 100 milliseconds, so it will raise events 10 tines a second when started. static void main (string [] Args) { Timer siddhu = new Timer (100);
The timer object possesses an event called Elapsed, and the event handler signature required by this event is that of the system.Timers.Elapsed Event handler delegate type, which is one of the standard delegates defined in the .Net framework. This delegate is used for functions that match the following signature: void function name(object source, ElapsedEvent Args e);
477
The timer object sends a reference to itself in the first parameter and an instance of an ElapsedEvent Args object in its second parameter. It is safe to ignore these parameters for now, but will take a look at them a little later. In our code, we have a method that matches this signature ; static void writechar(objectsource.ElapsedEventArg s e) { console.write(displaystring[counter ++ %display string.length]); }
This method uses the two static fields of siddhu1, counter and displaystring, to display a single character. different. Every time the method is called the character displayed will be
myTimer.start ();
Since, we dont want the application terminating before we have handled any events, we then put the main () function on hold. The simplest way of doing this is to request user input, since this command wont finish processing until the user has entered a line of text and or / pressed the enter key. console.Readline ();
Although processing in main () effectively ceases here, processing in the timer object continues when it raises events it calls our write char () method, which runs concurrently with the console.Readline () statement.
478
Example Try it out Eagles DefiningEvents Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles DefiningEvents in the directory C:\EaglesVisualCSharp\Chapter 11 - Events\Example Using DefiningEvents 2. Now enter the following code in the System. Namespace as follows using System; using System.Collections.Generic; using System.Text; using System.Timers;
3. Now declare a variable which is shown below in the constructor of the program.cs public delegate void MessageHandler(string messageText);
479
4. Now enter the following code in into the body of the program.cs as follows:
public class Connection { public event MessageHandler MessageArrived; private Timer siddhuTimer; public Connection() { siddhuTimer = new Timer(100); siddhuTimer.Elapsed += new ElapsedEventHandler(CheckForMessage); }
public void Connect() { siddhuTimer.Start(); } public void Disconnect() { siddhuTimer.Stop(); } private void CheckForMessage(object source, ElapsedEventArgs sri) { Console.WriteLine ("Checking for new messages."); Random random = new Random (); if ((random.Next (10) ==0) && (MessageArrived != null )) { MessageArrived("Welcome to EaglesGroup!"); } }
480
5. Now add a new class name it as Display.cs in the same console application for that just right click the Solution Explorer and then add new item and then add the class and then rename it to Display.cs and enter the following code in the Display.cs body as follows: public void DisplayMessage(string message) { Console.WriteLine("Message arrived:{0}", message); }
6. Now again go to the Program.cs and then modify the code a little bit as follows add the following code in the program.cs static void Main(string[] args) { Connection myConnection = new Connection(); Display myDisplay = new Display(); myConnection.MessageArrived += new MessageHandler(myDisplay.DisplayMessage); myConnection.Connect(); Console.ReadLine();
} 7. Now run the application and you should see the following output
481
Lets see how the above code works: The class that does most for the work in this application is the Connection class. Instances of the this class make use of a Timer object much like the one we saw in the first example of this chapter, initializing it in the class constructor and giving access to its state either enable or disabled via Connect () and Disconnect ():
public class Connection { public event MessageHandler MessageArrived; private Timer siddhuTimer; public Connection() { siddhuTimer = new Timer(100); siddhuTimer.Elapsed += new ElapsedEventHandler(CheckForMessage); } public void Connect() { siddhuTimer.Start(); } public void Disconnect() { siddhuTimer.Stop(); }
Also in the constructor, we register an event handler for the Elapsed event in the same way as we did in the first chapter. This handler method, CheckForMessage (), will rise on average once every ten times it is called. Before we look at the code for this, thought, lets look at the event definition itself
Before we define an evetn we must define a delegate type to use with the event that is delegate type that specific the signature that an event handling method must confirm to.
482
We do this using standard delegate syntax, defining it as public inside the Eagles DefiningEvents namespace in order to make the type available to external code:
This delegate type, which weve called MessageHandler here, is a signature for a void function that has a single string parameter. We can use this parameter to pass an instant message received by the Connection object to the Display object. Once a delegate has been defined or a suitable existing delegate has been located we can define the event, itself, as a member of the Connection class: public class Connection {
We simply name the event here we have use the name MessageArrived, and declare it using the event keyword and the delegate type to use the MessageHandler delegate type defined earlier.
483
Once we have declared an evetn in this way we can raise it simply by calling it by its name as if it were a method with the signature specified by the delegate. For example, we could rise this event using: { MessageArrived("Welcome to EaglesGroup!"); }
If the delegate has been defined without any parameters we could use simply: MessageArrived();
Alternatively we could have defined more parameters, which would have required more code to raise the event. Our CheckForMessage () method looks like this:
private void CheckForMessage(object source, ElapsedEventArgs sri) { Console.WriteLine ("Checking for new messages."); Random random = new Random (); if ((random.Next (10) ==0) && (MessageArrived != null )) { MessageArrived("Welcome to EaglesGroup!"); } } We use an instance of random class that we have seen in earlier chapters to generate a random number between 0 and 9, and raise an evetn if the number generated is 0, which should happen 10% of the time. This simulates polling the connection to see if a message has arrived, which wont be the case every time we check. Note that we supply additional logic. We only raise an event if the expression MessageArrived! = null evaluate to true. This expression, which again uses the delegate syntax in a slightly unusual way, means: Does the event have any subscribers? if there are no subscriber, MessageArrived will evaluate to null, and there would be no point in raising the event.
484
The class that will subscribe to the event is called Display, and contains the single method DisplayMessage () defined as follows: class Display { public void DisplayMessage(string message) { Console.WriteLine("Message arrived:{0}", message); } }
This method matches the delegate type method signature and is public, which is a requirement of event handlers in classes other than the class that generates the event, so we can use it to respond to the MessageArrived event. All that is left now is for the code in Main () to initialize instance of the Connection and Display classes, hook them up, and start things going. The code requires here is similar to that form the first example:
static void Main(string[] args) { Connection myConnection = new Connection(); Display myDisplay = new Display(); myConnection.MessageArrived += new MessageHandler(myDisplay.DisplayMessage); myConnection.Connect(); Console.ReadLine(); } Again, we call Console.Readline () to pause the processing of Main (), once we have started things moving with the Connect () method of the Connection objects.
485
Adding the event keyword fixes both problems. Classes can no longer attempt to subscribe to the event using the assignment operator (=), as they could previously, nor can they invoke the event directly, as was done in Main( ) in the example above. Either of these attempts will now generate a compile error: The event 'Programming_CSharp.Clock.OnSecondChange' can only appear on the left hand side of += or -= (except when used from within the type 'Programming_CSharp.Clock')
There are two ways of looking at OnSecondChange now that you've modified it. In one sense, it is simply a delegate instance to which you've restricted access using the keyword event. In another, more important sense, OnSecondChange is an event, implemented by a delegate of type SecondChangeHandler. These two statements mean the same thing, but the latter is a more object-oriented way of looking at it, and better reflects the intent of this keyword: to create an event that your object can raise, and to which other objects can respond.
486
Example Try it out Eagles EventKeyword Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles Event in the directory C:\EaglesVisualCSharp\Chapter 11 - Events\Example Using Eventkeyword 2. Add the following code in the System. Namespace as follows: using System; using System.Collections.Generic; using System.Text; using System.Threading;
487
3. Add the following code into the Program.cs body as follows: namespace Eagles_EventKeyword { class Program { // a class to hold the information about the event // in this case it will hold only information // available in the clock class, but could hold // additional state information public class TimeInfoEventArgs : EventArgs { public TimeInfoEventArgs(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } public readonly int hour; public readonly int minute; public readonly int second; } // our subject -- it is this class that other classes // will observe. This class publishes one event: // OnSecondChange. The observers subscribe to that event public class Clock
{ // the delegate the subscribers must implement public delegate void SecondChangeHandler ( object clock, TimeInfoEventArgs timeInformation ); // the keyword event controls access to the delegate public event SecondChangeHandler OnSecondChange; // set the clock running // it will raise an event for each new second public void Run() {
All Rights Reserved To EaglesGroup
488
for (; ; ) { // sleep 10 milliseconds Thread.Sleep(10); // get the current time System.DateTime dt = System.DateTime.Now; // if the second has changed // notify the subscribers if (dt.Second != second) { // create the TimeInfoEventArgs object // to pass to the subscriber TimeInfoEventArgs timeInformation = new TimeInfoEventArgs( dt.Hour, dt.Minute, dt.Second); // if anyone has subscribed, notify them if (OnSecondChange != null) { OnSecondChange( this, timeInformation); } }
// update the state this.second = dt.Second; this.minute = dt.Minute; this.hour = dt.Hour; } } private int hour; private int minute; private int second; } // an observer. DisplayClock subscribes to the // clock's events. The job of DisplayClock is // to display the current time
489
public class DisplayClock { // given a clock, subscribe to // its SecondChangeHandler event public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(TimeHasChanged); } // the method that implements the // delegated functionality public void TimeHasChanged( object theClock, TimeInfoEventArgs ti) { Console.WriteLine("Current Time: {0}:{1}:{2}", ti.hour.ToString(), ti.minute.ToString(), ti.second.ToString()); }
// a second subscriber whose job is to write to a file public class LogCurrentTime { public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(WriteLogEntry); } // this method should write to a file // we write to the console to see the effect // this object keeps no state public void WriteLogEntry( object theClock, TimeInfoEventArgs ti) { Console.WriteLine("Logging to file: {0}:{1}:{2}", ti.hour.ToString(), ti.minute.ToString(), ti.second.ToString()); } 490 }
4. Now add the following code in the Main () the code as follows:
static void Main(string[] args) { // create a new clock Clock theClock = new Clock(); // create the display and tell it to // subscribe to the clock just created DisplayClock dc = new DisplayClock(); dc.Subscribe(theClock); // create a Log object and tell it // to subscribe to the clock LogCurrentTime lct = new LogCurrentTime(); lct.Subscribe(theClock); // Get the clock started theClock.Run(); }
5. Now run the program and the output you should have like this:
491
Summary
In this chapter, we have looked at the important topic of events and event handling. Although, initially difficult to get your head around, the code involved is quiet simple and youll certainly be using event handlers a lot in the rest of the book. With this chapter we have completed not only a complete description of OOP as applied to C# programming, but also a complete description of the C# language. From this point on we will be applying this knowledge to make complex scenarios, such as creating windows and web applications as well as making more use of the .Net framework. In this chapter we had look the Delegates and Events and their uses and the keywords with the proper example so far we have covered the sub topics also witch are as follows: Introduction to Delegates Using Delegates to Specify Methods at Runtime Delegates and Instance Methods Static Delegates Delegates as Properties Setting Order of Execution with Delegate Arrays Introduction to Events What is an event? Event Handlers Event Sources Using Events Handling Events Publishing and Subscribing Events and Delegates The Event Keyword Return Values and Event Handlers
All Rights Reserved To EaglesGroup
492
Chapter 12
493
Preprocessor Directives
12.1 Introduction to Preprocessor Directives
In the examples you've seen so far, you've compiled your entire program whenever you compiled any of it. At times, however, you might want to compile only parts of your programfor example, depending on whether you are debugging or building your production code. Before your code is compiled, another program called the preprocessor runs and prepares your program for the compiler. The preprocessor examines your code for special preprocessor directives, all of which begin with the pound sign (#). These directives allow you to define identifiers and then test for their existence.
defines a preprocessor identifier, DEBUG. Although other preprocessor directives can come anywhere in your code, identifiers must be defined before any other code, including using statements.
DENOTE: C and C++ programmer take note: The C# preprocessor implements only a subset of the C++ preprocessor.
You can test whether DEBUG has been defined with the #if statement. Thus, you can write: #define DEBUG //... some normal code - not affected by preprocessor #if DEBUG // code to include if debugging #else // code to include if not debugging #endif //... some normal code - not affected by preprocessor - #endif block.
494
When the preprocessor runs, it sees the #define statement and records the identifier DEBUG. The preprocessor skips over your normal C# code and then finds the #if - #else
The #if statement tests for the identifier DEBUG, which does exist, and so the code between #if and #else is compiled into your programbut the code between #else and #endif is not compiled. That code does not appear in your assembly at all; it is as if it were left out of your source code. Had the #if statement failedthat is, if you had tested for an identifier that did not existthe code between #if and #else would not be compiled, but the code between #else and #endif would be compiled.
DENOTE: Any code not surrounded by #if - #endif is not affected by the preprocessor and is compiled into your program.
The first #if will succeed (DEBUG is defined), but the second will fail (DEBUG has been undefined).
495
In this example, the preprocessor first tests to see if the identifier DEBUG is defined. If it is, the code between #if and #elif will be compiled, and the rest of the code until #endif will not be compiled. If (and only if) DEBUG is not defined, the preprocessor next checks to see if TEST is defined. Note that the preprocessor will not check for TEST unless DEBUG is not defined. If TEST is defined, the code between the #elif and the #else directives will be compiled. If it turns out that neither DEBUG nor TEST is defined, the code between the #else and the #endif statements will be compiled.
12.2 #region:
The #region preprocessor directive marks an area of text with a comment. The principal use of this preprocessor directive is to allow tools such as Visual Studio .NET to mark off areas of code and collapse them in the editor with only the region's comment showing. For example, when you create a Windows application Visual Studio .NET creates a region for code generated by the designer. When the region is expanded, it looks like Figure 12-1. (Note: I've added the rectangle and highlighting to make it easier to find the region.)
496
You can see the region marked by the #region and #endregion preprocessor directives. When the region is collapsed, however, all you see is the region comment (Windows Form Designer generated code), as shown in Figure 9-2.
Summary:
In this chapter we know about the preprocessor directives and how it works and we also see the sub topics which is useful to the preprocessor directives they are as follows: Introduction to Preprocessor Directives Defining Identifiers Undefining Identifiers #if, #elif, #else, and #endif #region
497
Chapter 13
498
Handling Exceptions
13.0 Introduction to Handling Exceptions:
Like many object-oriented languages, C# handles errors and abnormal conditions with exceptions. An exception is an object that encapsulates information about an unusual program occurrence. It is important to distinguish between bugs, errors, and exceptions. A bug is a programmer mistake that should be fixed before the code is shipped. Exceptions are not a protection against bugs. Although a bug might cause an exception to be thrown, you should not rely on exceptions to handle your bugs. Rather, you should fix the bugs. An error is caused by user action. For example, the user might enter a number where a letter is expected. Once again, an error might cause an exception, but you can prevent that by catching errors with validation code. Whenever possible, errors should be anticipated and prevented. Even if you remove all bugs and anticipate all user errors, you will still run into predictable but unpreventable problems, such as running out of memory or attempting to open a file that no longer exists. You cannot prevent exceptions, but you can handle them so that they do not bring down your program. When your program encounters an exceptional circumstance, such as running out of memory, it throws (or "raises") an exception. When an exception is thrown, execution of the current function halts and the stack is unwound until an appropriate exception handler is found. This means that if the currently running function does not handle the exception, the current function will terminate and the calling function will get a chance to handle the exception. If none of the calling functions handles it, the exception will ultimately be handled by the CLR, which will abruptly terminate your program. An exception handler is a block of code designed to handle the exception you've thrown. Exception handlers are implemented as catch statements. Ideally, if the exception is caught and handled, the program can fix the problem and continue. Even if your program can't continue, by catching the exception, you have an opportunity to print a meaningful error message and terminate gracefully. If there is code in your function that must run regardless of whether an exception is encountered (e.g., to release resources you've allocated), you can place that code in a finally block, where it is certain to run, even in the presence of exceptions.
All Rights Reserved To EaglesGroup
499
In C#, you can throw only objects of type System.Exception, or objects derived from that type. The CLR System namespace includes a number of exception types that your program can use. These exception types include ArgumentNullException, InvalidCastException, and OverflowException, as well as many others.
DENOTE: C++ programmers take note: In C#, not just any object can be thrownit must be derived from System.Exception.
500
Example Try it out Eagles throwing an exception Step by Step Example: Using Version 2005
1. Create a new Console Application named Eagles Throwing an exception in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Throwing an exception 2. Now Enter the following code in the program.cs body and the code as follows public class Test { static void Main(string[] args) { Console.WriteLine("Enter Main..."); Test t = new Test(); t.Func1(); Console.WriteLine("Exit Main..."); } public void Func1() { Console.WriteLine("Enter Func1..."); Func2(); Console.WriteLine("Exit Func1..."); } public void Func2() { Console.WriteLine("Enter Func2..."); throw new System.Exception(); Console.WriteLine("Exit Func2..."); } } } }
501
3. After Entering the code compile and run the application and you should have a output like this:
This simple example writes to the console as it enters and exits each method. Main ( ) creates an instance of type Test and call Func1 ( ). After printing out the Enter Func1 message, Func1 ( ) immediately calls Func2 ( ). Func2 ( ) prints out the first message and throws an object of type System.Exception. Execution immediately stops, and the CLR looks to see if there is a handler in Func2 ( ). There is not, and so the runtime unwinds the stack (never printing the exit statement) to Func1 ( ). Again, there is no handler, and the runtime unwinds the stack back to Main ( ). With no exception handler there, the default handler is called, which prints the error message.
502
In C#, an exception handler is called a catch block and is created with the catch keyword. In Example 13-2, the throw statement is executed within a try block, and a catch block is used to announce that the error has been handled.
Example Try it out Eagles Catching an exception Step by Step Example: Using Version 2005
1. Create a new Console application name it as Eagles Catching an exception in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Catching an exception 2. Now enter the following code in the Program.cs as follows:
503
public class Test { static void Main(string[] args) { Console.WriteLine("Enter Main..."); Test t = new Test( ); t.Func1( ); Console.WriteLine("Exit Main..."); } public void Func1() { Console.WriteLine("Enter Func1..."); Func2(); Console.WriteLine("Exit Func1..."); } public void Func2() { Console.WriteLine("Enter Func2..."); try { Console.WriteLine("Entering try block..."); throw new System.Exception(); Console.WriteLine("Exiting try block..."); } catch { Console.WriteLine( "Exception caught and handled."); } Console.WriteLine("Exit Func2..."); } } } }
504
3. Now Run the application and you should see something like this:
Example 13.2is identical to Example 13-1 except that now the program includes a try/catch block. You would typically put the try block around a potentially "dangerous" statement, such as accessing a file, allocating memory, and so forth. Following the try statement is a generic catch statement. The catch statement in Example 13-2 is generic because you haven't specified what kind of exceptions to catch. In this case, the statement will catch any exceptions that are thrown. Using catch statements to catch specific types of exceptions is discussed later in this chapter.
505
Examine the output of Example 13-2 carefully. You see the code enter Main( ), Func1( ), Func2( ), and the try block. You never see it exit the try block, though it does exit Func2( ), Func1( ), and Main( ). What happened? When the exception is thrown, execution halts immediately and is handed to the catch block. It never returns to the original code path. It never gets to the line that prints the exit statement for the try block. The catch block handles the error, and then execution falls through to the code following catch. Without catch the call stack unwinds, but with catch it does not unwind, as a result of the exception. The exception is now handled; there are no more problems, and the program continues. This becomes a bit clearer if you move the try/catch blocks up to Func1( ), as shown in Example 13-3.
Example Try it out Eagles Catch in a calling function Step by Step Example: Using Version 2005
1. Create a new Console Application named as Eagles CatchcallingFunction in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Catch in a calling function 2. Enter the following code in the Program.cs
506
public class Test { static void Main(string[] args) { Console.WriteLine("Enter Main..."); Test t = new Test(); t.Func1(); Console.WriteLine("Exit Main..."); } public void Func1() { Console.WriteLine("Enter Func1..."); try { Console.WriteLine("Entering try block..."); Func2(); Console.WriteLine("Exiting try block..."); } catch { Console.WriteLine( "Exception caught and handled."); } Console.WriteLine("Exit Func1..."); } public void Func2() { Console.WriteLine("Enter Func2..."); throw new System.Exception(); Console.WriteLine("Exit Func2..."); } }
507
3. Now run the application and you should have the output like this:
This time the exception is not handled in Func2( ), it is handled in Func1( ). When Func2( ) is called, it prints the Enter statement and then throws an exception. Execution halts and the runtime looks for a handler, but there isn't one. The stack unwinds, and the runtime finds a handler in Func1( ). The catch statement is called, and execution resumes immediately following the catch statement, printing the Exit statement for Func1( ) and then for Main( ). Make sure you are comfortable with why the Exiting Try Block statement and the Exit Func2 statement are not printed. This is a classic case where putting the code into a debugger and then stepping through it can make things very clear.
Example Try it out Eagles exception to catch Step by Step Example: Using Version 2005
508
1. Create a new Console Application name it as Eagles exception to catch in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Exception to catch 2. Enter the following code into the program.cs as follows:
public class eagles { static void Main(string[] args) { eagles siddhu = new eagles(); siddhu.SriFunc(); } // try to divide two numbers // handle possible exceptions public void SriFunc() { try { double a = 5; double b = 0; Console.WriteLine("{0} / {1} = {2}", a, b, DoDivide(a, b)); } // most derived exception type first catch (System.DivideByZeroException) { Console.WriteLine("DivideByZeroException caught!"); } catch (System.ArithmeticException) { Console.WriteLine("ArithmeticException caught!"); } // generic exception type last catch { Console.WriteLine("Unknown exception caught"); } } // do the division if legal public double DoDivide(double a, double b) { if (b == 0) throw new System.DivideByZeroException(); if (a == 0) throw new System.ArithmeticException(); return a / b; } }
509
3. Now run the application and you should have the output like this:
In this example, the DoDivide ( ) method will not let you divide zero by another number, nor will it let you divide a number by zero. It throws an instance of DivideByZeroException if you try to divide by zero. If you try to divide zero by another number, there is no appropriate exceptiondividing zero by another number is a legal mathematical operation and shouldn't throw an exception at all. For the sake of this example, assume you don't want to allow division by zero; you will throw an ArithmeticException. When the exception is thrown, the runtime examines each exception handler in order and matches the first one it can. When you run this with a=5 and b=7, the output is: 5 / 7 = 0.7142857142857143 As you'd expect, no exception is thrown. However, when you change the value of a to 0, the output is: ArithmeticException caught! The exception is thrown, and the runtime examines the first exception, DivideByZeroException. Because this does not match, it goes on to the next handler, ArithmeticException, which does match. In a final pass through, suppose you change a to 7 and b to 0. This throws the DivideByZeroException.
510
DENOTE: You have to be particularly careful with the order of the catch statements, because the DivideByZeroException is derived from ArithmeticException. If you reverse the catch statements, the DivideByZeroException will match the ArithmeticException handler, and the exception will never get to the DivideByZeroException handler. In fact, if their order is reversed, it will be impossible for any exception to reach the DivideByZeroException handler. The compiler will recognize that the DivideByZeroException handler cannot be reached and will report a compile error!
It is possible to distribute your try/catch statements, catching some specific exceptions in one function and more generic exceptions in higher, calling functions. Your design goals should dictate the exact design. Assume you have a method A that calls another method B, which in turn calls method C. Method C calls method D, which then calls method E. Method E is deep in your code; methods B and A are higher up. If you anticipate that method E might throw an exception, you should create a try/catch block deep in your code to catch that exception as close as possible to the place where the problem arises. You might also want to create more general exception handlers higher up in the code in case unanticipated exceptions slip by.
DENOTE: In C#, this is less of a problem than in other languages, such as C++, because the garbage collection prevents the exception from causing a memory leak.
In the event, however, that there is some action you must take regardless of whether an exception is thrown (such as closing a file) you have two strategies to choose from. One approach is to enclose the dangerous action in a try block and then to close the file in both the catch and try blocks. However, this is an ugly duplication of code, and it's error prone. C# provides a better alternative in the finally block.
511
The code in the finally block is guaranteed to be executed regardless of whether an exception is thrown. The TestFunc ( ) method in Example 13-5 simulates opening a file as its first action. The method undertakes some mathematical operations, and the file is closed. It is possible that some time between opening and closing the file an exception will be thrown. If this were to occur, it would be possible for the file to remain open. The developer knows that no matter what happens, at the end of this method the file should be closed, so the file close function call is moved to a finally block, where it will be executed regardless of whether an exception is thrown.
Example Try it out Eagles finally block Step by Step Example: Using Version 2005
1. Create a new Console application called it as Eagles Final bloc in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Final bloc
512
2. Now Enter the following code into the Program.cs public class Test { static void Main(string[] args) { Test t = new Test(); t.TestFunc(); // try to divide two numbers // handle possible exceptions } public void TestFunc() { try { Console.WriteLine("Open file here"); double a = 5; double b = 0; Console.WriteLine("{0} / {1} = {2}", a, b, DoDivide(a, b)); Console.WriteLine( "This line may or may not print"); } // most derived exception type first catch (System.DivideByZeroException) { Console.WriteLine( "DivideByZeroException caught!"); } catch { Console.WriteLine("Unknown exception caught"); } finally { Console.WriteLine("Close file here."); } } // do the division if legal public double DoDivide(double a, double b) { if (b == 0) throw new System.DivideByZeroException(); if (a == 0) throw new System.ArithmeticException(); return a / b; } }
513
3. Now run the console application and you should see the output like this:
4. Now assign a value for b as 12 and the code as follows: public void TestFunc() { try { Console.WriteLine("Open file here"); double a = 5; double b = 12; Console.WriteLine("{0} / {1} = {2}", a, b, DoDivide(a, b)); Console.WriteLine( "This line may or may not print"); }
514
5. Now run the application and you should have the output like this:
In this example, one of the catch blocks has been eliminated to save space, and a finally block has been added. Whether or not an exception is thrown, the finally block is executed, and so in both output examples you see the message: Close file here.
DENOTE: A finally block can be created with or without catch blocks, but a finally block requires a try block to execute. It is an error to exit a finally block with break, continue, return, or goto.
515
DENOTE: VB6 programmers take note: In C#, you need to be careful when declaring and instantiating object variables on the same line of code. If there is a possibility that an error could be thrown in the constructor method, then you might be temped to put the variable declaration and instantiation inside the try block. But if you do that, the variable will only be scoped within the try block and it can't be referenced within the catch or finally blocks. The best approach is to declare the object variable before the try block and instantiate it within the try block. The Stack Trace property is read-only and is set by the runtime. In Example 13-6, the Exception.HelpLink property is set and retrieved to provide information to the user about the DivideByZeroException. The Stack Trace property of the exception is used to provide a stack trace for the error statement. A stack trace displays the call stack: the series of method calls that lead to the method in which the exception was thrown.
Example Try it out Eagles Exception object Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles Exception object in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Eagles Exception object
516
517
3. Now run the console application and you should see some thing like this:
In the output, the stack trace lists the methods in the reverse order in which they were called; that is, it shows that the error occurred in DoDivide( ), which was called by TestFunc( ). When methods are deeply nested, the stack trace can help you understand the order of method calls. In this example, rather than simply throwing a DivideByZeroException, you create a new instance of the exception: DivideByZeroException e = new DivideByZeroException ( ); you do not pass in a custom message, and so the default message will be printed: DivideByZeroException! Msg: Attempted to divide by zero. You can modify this line of code to pass in a default message: new DivideByZeroException ("You tried to divide by zero which is not meaningful"); In this case, the output message will reflect the custom message: DivideByZeroException! Msg: You tried to divide by zero which is not meaningful Before throwing the exception, set the HelpLink property: e.HelpLink = http://www.eaglesgroup.com"; When this exception is caught, the program prints the message and the HelpLink: catch (System.DivideByZeroException e) { Console.WriteLine("\nDivideByZeroException! Msg: {0}", e.Message); Console.WriteLine("\nHelpLink: {0}", e.HelpLink);
518
This allows you to provide useful information to the user. In addition, it prints the StackTrace by getting the StackTrace property of the exception object: Console.WriteLine("\nHere's a stack trace: {0}\n", e.StackTrace);
Example Try it out Eagles Custom Exception Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles Custom exception in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Custom Exception 2. Now enter the following code in the program.cs as follows:
519
public class SiddhuEagles : System.ApplicationException { public SiddhuEagles(string message) : base(message) { } } public class Sri { public static void Main() { Sri t = new Sri(); t.TestFunc(); } // try to divide two numbers // handle possible exceptions public void TestFunc() { try { Console.WriteLine("Open file here"); double a = 0; double b = 5; Console.WriteLine("{0} / {1} = {2}", a, b, DoDivide(a, b)); Console.WriteLine( "This line may or may not print"); } // most derived exception type first catch (System.DivideByZeroException e) { Console.WriteLine( "\nDivideByZeroException! Msg: {0}", e.Message); Console.WriteLine( "\nHelpLink: {0}\n", e.HelpLink); } catch (SiddhuEagles e) { Console.WriteLine( "\nMyCustomException! Msg: {0}", e.Message); Console.WriteLine( "\nHelpLink: {0}\n", e.HelpLink); } catch
520
{ Console.WriteLine( "Unknown exception caught"); } finally { Console.WriteLine("Close file here."); } } // do the division if legal public double DoDivide(double a, double b) { if (b == 0) { DivideByZeroException e = new DivideByZeroException(); e.HelpLink = "http://www.eaglesgroup.com"; throw e; } if (a == 0) { SiddhuEagles e = new SiddhuEagles ( "Can't have zero divisor"); e.HelpLink = "http://www.eaglesgroup.com/ZeroDivider.aspx"; throw e; } return a / b; } }
521
3. Now run the application and you should have a output like this:
SiddhuEagles is derived from System.ApplicationException and consists of nothing more than a constructor that takes a string message that it passes to its base class. In this case, the advantage of creating this custom exception class is that it better reflects the particular design of the Test class, in which it is not legal to have a zero divisor. Using the ArithmeticException rather than a custom exception would work as well, but it might confuse other programmers because a zero divisor wouldn't normally be considered an arithmetic error.
522
Example Try it out Eagles Inner Exceptions Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles Inner Exceptions in the directory C:\EaglesVisualCSharp\Chapter 13 Handling Exceptions\Example Using Inner Exceptions 2. Now enter the following code into the Program.cs as follows: public class SiddhuEagles : System.ApplicationException { public SiddhuEagles( string message, Exception inner) : base(message, inner) { } } public class Test { public static void Main() { Test t = new Test(); t.TestFunc(); } public void TestFunc() { try { DangerousFunc1(); } // if you catch a custom exception // print the exception history catch (SiddhuEagles e) { Console.WriteLine("\n{0}", e.Message); Console.WriteLine( "Retrieving exception history..."); Exception inner = e.InnerException; while (inner != null) { Console.WriteLine( "{0}", inner.Message); inner = inner.InnerException; } } }
All Rights Reserved To EaglesGroup
523
public void DangerousFunc1() { try { DangerousFunc2(); } // if you catch any exception here // throw a custom exception catch (System.Exception e) { SiddhuEagles ex = new SiddhuEagles ( "E3 - Custom Exception Situation!", e); throw ex; } }
public void DangerousFunc2() { try { DangerousFunc3(); } // if you catch a DivideByZeroException take some // corrective action and then throw a general exception catch (System.DivideByZeroException e) { Exception ex = new Exception( "E2 - Func2 caught divide by zero", e); throw ex; } }
524
public void DangerousFunc3() { try { DangerousFunc4(); } catch (System.ArithmeticException) { throw; } catch (System.Exception) { Console.WriteLine( "Exception handled here."); } } public void DangerousFunc4() { throw new DivideByZeroException("E1 - DivideByZero Exception"); }
3. Now run the application and you should see the output like this
Because this code has been stripped to the essentials, the output might leave you scratching your head. The best way to see how this code works is to use the debugger to step through it.
525
DangerousFunc1 ( ) calls DangerousFunc2 ( ), which calls DangerousFunc3 ( ), which in turn calls DangerousFunc4 ( ). All these calls are in their own try blocks. At the end, DangerousFunc4 ( ) throws a DivideByZeroException. System.DivideByZeroException normally has its own error message, but you are free
to pass in a custom message. Here, to make it easier to identify the sequence of events, the custom message E1 - DivideByZeroException is passed in. The exception thrown in DangerousFunc4 ( ) is caught in the catch block in DangerousFunc3 ( ). The logic in DangerousFunc3 ( ) is that if any ArithmeticException is caught (such as DivideByZeroException), it takes no action; it just rethrows the exception: catch (System.ArithmeticException) { throw; }
The syntax to rethrow the exact same exception (without modifying it) is just the word throw. The exception is thus rethrown to DangerousFunc2 ( ), which catches it, takes some corrective action, and throws a new exception of type Exception. In the constructor to that new exception, DangerousFunc2 ( ) passes in a custom message (E2 - Func2 caught divide by zero) and the original exception. Thus, the original exception (E1) becomes the Inner Exception for the new exception (E2). DangerousFunc2 ( ) then throws this new E2 exception to DangerousFunc1 ( ).
DangerousFunc1 ( ) catches the exception, does some work, and creates a new exception of type SiddhuEagles. It passes a new string (E3 - Custom Exception Situation!) to the constructor as well as the exception it just caught (E2). Remember, the exception it just caught is the exception with a DivideByZeroException (E1) as its inner exception. At this point, you have an exception of type SiddhuEagles (E3), with an inner exception of type Exception (E2), which in turn has an inner exception of type DivideByZeroException (E1). All this is then thrown to the test function, where it is
caught.
526
When the catch function runs, it prints the message: E3 - Custom Exception Situation! and then drills down through the layers of inner exceptions, printing their messages: while (inner != null) { Console.WriteLine("{0}",inner.Message); inner = inner.InnerException; }
527
Summary
In this chapter we had known more knowledge of the Handling Exceptions and the sections we covered are as follows:
Introduction to Handling Exceptions Throwing and Catching Exceptions The throw Statement The catch Statement Taking corrective action Unwinding the call stack Creating dedicated catch statements The finally Statement Exception Objects Custom Exceptions Rethrowing Exceptions
528
Chapter 14
529
14.2 Strings
C# treats strings as first-class types that are flexible, powerful, and easy to use. Each string object is an immutable sequence of Unicode characters. In other words, methods that appear to change the string actually return a modified copy; the original string remains intact. When you declare a C# string using the string keyword, you are in fact declaring the object to be of the type System.String, one of the built-in types provided by the .NET Framework Class Library. A C# string type is a System.String type, and we will use the names interchangeably throughout the chapter.
530
The declaration of the System.String class is: public sealed class String: IComparable, ICloneable, IConvertible, IEnumerable This declaration reveals that the class is sealed, meaning that it is not possible to derive from the string class. The class also implements four system interfacesIComparable, ICloneable, IConvertible, and IEnumerablethat dictate functionality that System.String shares with other classes in the .NET Framework.
DENOTE: C and C++ programmers take note: C# strings are immutable; modifying a string does not modify it in place. This may have performance implications. If you plan to do significant string manipulation, use a StringBuilder.
The IComparable interface is implemented by types whose values can be ordered. Strings, for example, can be alphabetized; any given string can be compared with another string to determine which should come first in an ordered list. IComparable classes implement the CompareTo method. Lets you use the foreach construct to enumerate a string as a collection of chars.
ICloneable
objects can create new instances with the same value as the original instance. In this case, it is possible to clone a string to produce a new string with the same values (characters) as the original. ICloneable classes implement the Clone ( ) method.
IConvertible classes provide methods to facilitate as ToInt32 ( ), ToDouble ( ), ToDecimal ( ), etc.
531
Quoted strings can include escape characters, such as "\n" or "\t," which begin with a backslash character (\) and are used to indicate where line breaks or tabs are to appear. Because the backslash is itself used in some command-line syntax, such as URLs or directory paths, in a quoted string the backslash must be preceded by another backslash. Strings can also be created using verbatim string literals, which start with the (@) symbol. This tells the String constructor that the string should be used verbatim, even if it spans multiple lines or includes escape characters. In a verbatim string literal, backslashes and the characters that follow them are simply considered additional characters of the string. Thus, the following two definitions are equivalent: string literalOne = "\\\\MySystem\\MyDirectory\\ProgrammingC#.cs"; string verbatimLiteralOne = @"\\MySystem\MyDirectory\ProgrammingC#.cs"; In the first line, a nonverbatim string literal is used, and so the backslash characters (\) must be escaped. This means it must be preceded by a second backslash character. In the second line, a verbatim literal string is used, so the extra backslash is not needed. A second example illustrates multiline verbatim strings: string literalTwo = "Line One\nLine Two"; string verbatimLiteralTwo = @"Line One, Line Two";
Again, these declarations are interchangeable. Which one you use is a matter of convenience and personal style.
532
The call to myInteger.ToString ( ) returns a String object, which is then assigned to integerString. The .NET String class provides a wealth of overloaded constructors that support a variety of techniques for assigning string values to string types. Some of these constructors enable you to create a string by passing in a character array or character pointer. Passing in a character array as a parameter to the constructor of the String creates a CLR-compliant new instance of a string. Passing in a character pointer creates a noncompliant, "unsafe" instance.
533
Method or field
Empty
Purpose
Public static field that represents the empty string. Overloaded public static method that compares two strings. Overloaded public static method that compares two strings without regard to local or culture.
Compare( )
CompareOrdinal( )
Concat( )
Copy( ) Equals( )
Format( )
Intern( )
IsInterned( ) Join( )
Overloaded public static method that creates a new string from one or more strings. Public static method that creates a new string by copying another. Overloaded public static and instance method that determines if two strings have the same value. Overloaded public static method that formats a string using a format specification. Public static method that returns a reference to the specified instance of a string. Public static method that returns a reference for the string. Overloaded public static method that concatenates a specified string between each element of a string array. The string indexer. The number of characters in the instance. Returns the string. Compares this string with another. Copies the specified number of characters to an array of Unicode characters.
534
PadLeft( )
Indicates whether the specified string matches the end of this string. Determines if two strings have the same value. Returns a new string with the specified string inserted. Reports the index of the last occurrence of a specified character or string within the string. Right-aligns the characters in the string, padding to the left with spaces or a specified character.
PadRight( )
Left-aligns the characters in the string, padding to the right with spaces or a specified character. Deletes the specified number of characters. Returns the substrings delimited by the specified characters in a string array. Indicates if the string starts with the specified characters. Retrieves a substring. Copies the characters from the string to a character array. Returns a copy of the string in lowercase. Returns a copy of the string in uppercase. Removes all occurrences of a set of specified characters from beginning and end of the string.
Trim( )
TrimEnd( ) TrimStart( )
Behaves like Trim ( ), but only at the end. Behaves like Trim ( ), but only at the start.
535
Example 14.1 illustrates the use of some of these methods, including Compare ( ), Concat ( ) (and the overloaded + operator), Copy ( ) (and the = operator), Insert ( ), EndsWith ( ), and IndexOf ( ).
Example Try it out Eagles WorkingStrings Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles WorkingStrings in the directory C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Using Working with strings 2. And enter the following code in the program.cs body inside the main : static void Main(string[] args) { // create some strings to work with string eagles1 = "abcd"; string eagles2 = "ABCD"; string eagles3 = @"EaglesGroup Application Software's, Inc. provides custom .NET development,Training, Siddhu"; int result; // hold the results of comparisons // compare two strings, case sensitive result = string.Compare(eagles1, eagles2); Console.WriteLine("compare eagles1: {0}, eagles2: {1}, result: {2}\n", eagles1, eagles2, result); // overloaded compare, takes boolean "ignore case" //(true = ignore case) result = string.Compare(eagles1, eagles2, true); Console.WriteLine("compare insensitive\n"); Console.WriteLine("String4: {0}, eagles2: {1}, result: {2}\n", eagles1, eagles2, result); // concatenation method string string6 = string.Concat(eagles1, eagles2); Console.WriteLine( "String6 concatenated from eagles1 and eagles2: {0}", string6);
536
// use the overloaded operator string string7 = eagles1 + eagles2; Console.WriteLine( "String7 concatenated from eagles1 + eagles2: {0}", string7); // the string copy method string string8 = string.Copy(string7); Console.WriteLine( "String8 copied from string7: {0}", string8); // use the overloaded operator string string9 = string8; Console.WriteLine("string9 = string8: {0}", string9); // three ways to compare. Console.WriteLine( "\nDoes string9.Equals(string8)?: {0}", string9.Equals(string8)); Console.WriteLine( "Does Equals(string9,string8)?: {0}", string.Equals(string9,string8)); Console.WriteLine( "Does string9==string8?: {0}", string9 == string8); // Two useful properties: the index and the length Console.WriteLine( "\nString string9 is {0} characters long. ", string9.Length); Console.WriteLine( "The 5th character is {1}\n", string9.Length, string9[4]); // test whether a string ends with a set of characters
537
Console.WriteLine("eagles3:{0}\nEnds with Training?: {1}\n", eagles3, eagles3.EndsWith("Training")); Console.WriteLine( "Ends with Siddhu?: {0}", eagles3.EndsWith("Siddhu")); // return the index of the substring Console.WriteLine( "\nThe first occurrence of Training "); Console.WriteLine ("in eagles3 is {0}\n", eagles3.IndexOf("Training")); // insert the word excellent before "training" string string10 = eagles3.Insert(101, "excellent "); Console.WriteLine("string10: {0}\n",string10); // you can combine the two as follows: string string11 = eagles3.Insert(eagles3.IndexOf("Training"), "excellent "); Console.WriteLine("string11: {0}\n",string11); }
538
3. Now run the console application and you should have the result like this:
Now lets see how the above program works string eagles1 = "abcd"; string eagles2 = "ABCD"; string eagles3 = @"EaglesGroup Application Software's, Inc. provides custom .NET development,Training, Siddhu";
The first two are string literals, and the third is a verbatim string literal. We begin by comparing eagles1 to eagles2. The Compare ( ) method is a public static method of string, and it is overloaded. The first overloaded version takes two strings and compares them: // compare two strings, case sensitive result = string.Compare(eagles1, eagles2); Console.WriteLine("compare eagles1: {0}, eagles2: {1}, result: {2}\n", eagles1, eagles2, result);
539
This is a case-sensitive comparison and returns different values, depending on the results of the comparison: A negative integer, if the first string is less than the second string 0, if the strings are equal A positive integer, if the first string is greater than the second string In this case, the output properly indicates that eagles1 is "less than" eagles2. In Unicode (as in ASCII), a lowercase letter has a smaller value than an uppercase letter: compare eagles1: abcd, eagles2: ABCD, result: -1
The second comparison uses an overloaded version of Compare ( ) that takes a third, Boolean parameter, whose value determines whether case should be ignored in the comparison. If the value of this "ignore case" parameter is true, the comparison is made without regard to case, as in the following: result = string.Compare(eagles1,eagles2, true); Console.WriteLine("compare insensitive\n"); Console.WriteLine("eagles4: {0}, eagles2: {1}, result: {2}\n", eagles1, eagles2, result);
DENOTE: The result is written with two WriteLine ( ) statements to keep the lines short enough to print properly in this book. This time the case is ignored and the result is 0, indicating that the two strings are identical (without regard to case): compare insensitive string4: abcd, eagles2: ABCD, result: 0
Then concatenates some strings. There are a couple of ways to accomplish this. You can use the Concat ( ) method, which is a static public method of string:
540
string string6 = string.Concat(eagles1,eagles2);or you can simply use the overloaded concatenation (+) operator: string string7 = eagles1 + eagles2;
In both cases, the output reflects that the concatenation was successful: string6 concatenated from eagles1 and eagles2: abcdABCD string7 concatenated from eagles1 + eagles2: abcdABCD Similarly, creating a new copy of a string can be accomplished in two ways. First, you can use the static Copy( ) method string string8 = string.Copy(string7);
Otherwise, for convenience, you might instead use the overloaded assignment operator (=), which will implicitly make a copy: string string9 = string8;
Once again, the output reflects that each method has worked: string8 copied from string7: abcdABCD string9 = string8: abcdABCD The .NET String class provides three ways to test for the equality of two strings. First, you can use the overloaded Equals ( ) method and ask string9 directly whether string8 is of equal value: Console.WriteLine("\nDoes string9.Equals(string8)?: {0}", string9.Equals(string8));
541
A second technique is to pass both strings to String's static method Equals( ): Console.WriteLine("Does Equals(s9,s8)?: {0}", string.Equals(s9,s8));
A final method is to use the overloaded equality operator (==) of String: Console.WriteLine("Does string9==string8?: {0}", string9 == string8);
In each of these cases, the returned result is a Boolean value, as shown in the output: Does string9.Equals(string8)?: True Does Equals(string9,string8)?: True Does string9==string8?: True
The equality operator is the most natural when you have two string objects. However, some languages, such as VB.NET, do not support operator overloading, so be sure to override the Equals ( ) instance method as well. The next several lines in program use the index operator ([]) to find a particular character within a string, and use the Length property to return the length of the entire string: Console.WriteLine("\nString string9 is {0} characters long., string9.Length); Console.WriteLine("The 5th character is {1}\n", string9.Length, string9[4]); And you should have the output as follows: String s9 is 8 characters long. The 5th character is A
542
The EndsWith ( ) method asks a string whether a substring is found at the end of the string. Thus, you might first ask eagles3 if it ends with Training (which it does not) and then if it ends with Siddhu (which it does): // test whether a string ends with a set of characters Console.WriteLine("eagles3:{0}\nEnds with Training?: {1}\n", eagles3, eagles3.EndsWith("Training") ); Console.WriteLine("Ends with Siddhu?: {0}", eagles3.EndsWith("Siddhu"));
And you should have the output reflects that the first test fails and the second succeeds: eagles3: @"EaglesGroup Application Software's, Inc. provides custom .NET development,Training, Siddhu"; Ends with Training?: False Ends with Siddhu?: True
The IndexOf ( ) method locates a substring within our string, and the Insert ( ) method inserts a new substring into a copy of the original string. The following code locates the first occurrence of Training in eagles3: Console.WriteLine("\nThe first occurrence of Training "); Console.WriteLine ("in eagles3 is {0}\n", eagles3.IndexOf("Training"));
The output indicates that the offset is 101: The first occurrence of Training in string3 is 101
543
You can then use that value to insert the word excellent, followed by a space, into that string. Actually, the insertion is into a copy of the string returned by the Insert ( ) method and assigned to string10: string string10 = string3.Insert(101,"excellent"); Console.WriteLine("string10: {0}\n",string10); Here's the output: eagles3 = @"EaglesGroup Application Software's, Inc. provides custom .NET development,Training, Siddhu";
Finally, you can combine these operations to make a more efficient insertion statement: string string11 = string3.Insert(string3.IndexOf("Training"),"excellent "); Console.WriteLine("string11: {0}\n",string11); with the identical output: string11: EaglesGroup Application Softwares, Inc. provides custom .NET development, on-site excellent Training, Siddhu;
544
Example Try it out Eagles Substring Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles Substring in the directory C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Using Substring 2. And add the following code in the body of the program.cs and the code as follows: static void Main(string[] args) {// create some strings to work with string eagles1 = "One Two Three Four"; int ix; // get the index of the last space ix=eagles1.LastIndexOf(" "); // get the last word. string string2 = eagles1.Substring(ix + 1); // set eagles1 to the substring starting at 0 // and ending at ix (the start of the last word // thus eagles1 has one two three eagles1 = eagles1.Substring(0,ix); // find the last space in eagles1 (after two) ix = eagles1.LastIndexOf(" "); // set string3 to the substring starting at // ix, the space after "two" plus one more // thus string3 = "three" string string3 = eagles1.Substring(ix + 1);
545
// reset string1 to the substring starting at 0 // and ending at ix, thus the string "one two" eagles1 = eagles1.Substring(0,ix); // reset ix to the space between // "one" and "two" ix = eagles1.LastIndexOf(" "); // set string4 to the substring starting one // space after ix, thus the substring "two" string string4 = eagles1.Substring(ix + 1); // reset string1 to the substring starting at 0 // and ending at ix, thus "one" eagles1 = eagles1.Substring(0,ix); // set ix to the last space, but there is // none so ix now = -1 ix = eagles1.LastIndexOf(" "); // set string5 to the substring at one past // the last space. there was no last space // so this sets string5 to the substring starting // at zero string string5 = eagles1.Substring(ix + 1); Console.WriteLine("string2: {0}\nstring3: {1}", string2, string3); Console.WriteLine("string4: {0}\nstring5: {1}\n", string4, string5); Console.WriteLine ("eagles1: {0}\n",eagles1); } }
546
3. Now run the application and you should have the result like this:
Now lets see how the above code works: Example 14-2 is not an elegant solution to the problem of extracting words from a string, but it is a good first approximation, and it illustrates a useful technique. The example begins by creating a string, eagles1: string eagles1 = "One Two Three Four";
Then ix is assigned the value of the last space in the string: ix=eagles1.LastIndexOf(" ");
Then the substring that begins one space later is assigned to the new string, string2: string string2 = eagles1.Substring(ix+1);
This extracts from x1+1 to the end of the line, assigning to string2 the value Four.
547
The next step is to remove the word Four from eagles1. You can do this by assigning to eagles1 the substring of eagles1, which begins at 0 and ends at ix: eagles1 = eagles1.Substring(0,ix);
Reassign ix to the last (remaining) space, which points you to the beginning of the word Three, which we then extract into string string3. Continue like this until string4 and string5 are populated. Finally, print the results: string2: Four string3: Three string4: Two string5: One eagles1: One This isn't elegant, but it works and it illustrates the use of Substring. This is not unlike using pointer arithmetic in C++, but without the pointers and unsafe code.
Example Try it out Eagles UsingSplit Step by Step Example: Using Version 2005
548
1. Create a new console application named it as Eagles UsingSplit in the directory C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Using UsingSplit 2. Now add the following code to the program.cs
static void Main(string[] args) { // create some strings to work with string eagles1 = "One,Two,Three EaglesGroup Application Software's, Inc."; // constants for the space and comma characters const char Space = ' '; const char Comma = ','; // array of delimiters to split the sentence with char[] delimiters = new char[] { Space, Comma }; string output = ""; int ctr = 1; // split the string and then iterate over the // resulting array of strings foreach (string subString in eagles1.Split(delimiters)) { output += ctr++; output += ": "; output += subString; output += "\n"; } Console.WriteLine(output); } }
549
3. Now run the application and you should see the output like this:
Now lets see how the above program works: You start by creating a string to parse: string eagles1 = "One,Two,Three EaglesGroup Application Software's, Inc.";
The delimiters are set to the space and comma characters. You then call Split ( ) on this string, and pass the results to the foreach loop: foreach (string subString in eagles1.Split(delimiters))
Start by initializing output to an empty string and then build up the output string in four steps. Concatenate the value of ctr. Next add the colon, then the substring returned by split, then the newline. With each concatenation, a new copy of the string is made, and all four steps are repeated for each substring found by Split ( ). This repeated copying of string is terribly inefficient.
550
The problem is that the string type is not designed for this kind of operation. What you want is to create a new string by appending a formatted string each time through the loop. The class you need is StringBuilder.
Explanation
Chars
Retrieves or assigns the number of characters the StringBuilder is capable of holding. The indexer.
AppendFormat( )
Retrieves or assigns the length of the StringBuilder. Retrieves the maximum capacity of the StringBuilder. Overloaded public method that appends a typed object to the end of the current StringBuilder. Overloaded public method that replaces format specifiers with the formatted value of an object.
EnsureCapacity( )
Insert( )
Ensures the current StringBuilder has a capacity at least as large as the specified value. Overloaded public method that inserts an object at the specified position.
Remove( )
551
Replace( )
Overloaded public method that replaces all instances of specified characters with new characters.
Unlike String, StringBuilder is mutable; when you modify a StringBuilder, you modify the actual string, not a copy. Example 14-4 replaces the String object in Example 14-3 with a StringBuilder object.
Example Try it out Eagles StringBuilder Step by Step Example: Using Version 2005
1. Create a new console application and name it as Eagles StringBuilder in the directory C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Using StringBuilder
552
static void Main(string[] args) { // create some strings to work with string eagles1 = "One,Two,Three EaglesGroup Application Software's, Inc."; // constants for the space and comma characters const char Space = ' '; const char Comma = ','; // array of delimiters to split the sentence with char[] delimiters = new char[] { Space, Comma }; // use a StringBuilder class to build the // output string StringBuilder output = new StringBuilder( ); int ctr = 1; // split the string and then iterate over the // resulting array of strings foreach (string subString in eagles1.Split(delimiters)) { // AppendFormat appends a formatted string output.AppendFormat("{0}: {1}\n",ctr++,subString); } Console.WriteLine(output); } }
553
3. Now run the console application and you will have a output like this:
The above code works exactly. Only the last part of the program is modified. Rather than using the concatenation operator to modify the string, use the AppendFormat ( ) method of StringBuilder to append new, formatted strings as you create them. This is much easier and far more efficient. The output is identical:
DENOTE: Because you passed in delimiters of both comma and space, the space after the comma between "Associates" and "Inc." is returned as a word, numbered 6 as shown. That is not what you want. To eliminate this you need to tell split to match a comma (as between One, Two, and Three), or a space (as between Liberty and Associates), or a comma followed by a space. It is that last bit that is tricky and requires that you use a regular expression.
554
As, you can return any or all of its substrings (e.g., Liberty or One), or modified versions of its substrings (e.g., EAGleSgRouP or OnE). What the regular expression does is determined by the syntax of the regular expression itself. A regular expression consists of two types of characters: literals and metacharacters. A literal is a character you wish to match in the target string. A metacharacter is a special symbol that acts as a command to the regular expression parser. The parser is the engine responsible for understanding the regular expression. For example, if you create a regular expression: ^ (From|To|Subject|Date):
This will match any substring with the letters "From," "To," "Subject," or "Date," so long as those letters start a new line (^) and end with a colon (:). The caret (^) in this case indicates to the regular expression parser that the string you're searching for must begin a new line. The letters "From" and "To" are literals, and the metacharacters left and right parentheses ( (, ) ) and vertical bar (|) are all used to group sets of literals and indicate that any of the choices should match. (Note that ^ is a
metacharacter as well, used to indicate the start of the line.)
555
As follows: "Match any string that begins a new line followed by any of the four literal strings From, To, Subject, or Date followed by a colon."
Example Try it out Eagles RegexClass Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles RegexClass in the directory as follows C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Uisng RegexClass 2. Now enter the following code in the System. Namespace as follows: using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions;
556
3. Now enter the following code into the program.cs body and the code as follows: static void Main(string[] args) { string eagles1 = "One,Two,Three EaglesGroup Application Software's, Inc."; Regex theRegex = new Regex(" |, |,"); StringBuilder siddhuBuilder = new StringBuilder( ); int id = 1; foreach (string subString in theRegex.Split(eagles1)) { siddhuBuilder.AppendFormat( "{0}: {1}\n", id++, subString); } Console.WriteLine("{0}", siddhuBuilder); } }
4. Now run the application and you should have the output like this:
557
Now lets see how the above program works Example 14-5 begins by creating a string, eagles1, that is identical to the string used in Example 14-4. string eagles1 = "One,Two,Three EaglesGroup Application Software's, Inc.";
It also creates a regular expression, which will be used to search that string: Regex theRegex = new Regex(" |,|, ");
One of the overloaded constructors for Regex takes a regular expression string as its parameter. This is a bit confusing. In the context of a C# program, which is the regular expression? Is it the text passed in to the constructor, or the Regex object itself? It is true that the text string passed to the constructor is a regular expression in the traditional sense of the term. From an object-oriented C# point of view, however, the argument to the constructor is just a string of characters; it is theRegex that is the regular expression object. The rest of the program proceeds like the earlier Example 14-4, except that rather than calling Split ( ) on string eagles1, the Split ( ) method of Regex is called. Regex.Split ( ) acts in much the same way as String.Split ( ), returning an array of strings as a result of matching the regular expression pattern within theRegex.
Regex.Split ( )
is overloaded. The simplest version is called on an instance of Regex, as shown in Example 14-5. There is also a static version of this method, which takes a string to search and the pattern to search with, as illustrated in Example 14-6.
558
Example Try it out Eagles RegexSplit Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles RegexSplit in the Directory C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Exmaple Using RegexSplit 2. Now enter the following code in the System. Namespace as follows: using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; 3. After enter the code for the system namespace enter the following code in the body of the program.cs as follows: static void Main(string[] args) { string eagles1 = "One,Two,Three EaglesGroup Application Software's, Inc."; StringBuilder siddhuBuilder = new StringBuilder( ); int id = 1; foreach (string subStr in Regex.Split(eagles1," |, |,")) { siddhuBuilder.AppendFormat("{0}: {1}\n", id++, subStr); } Console.WriteLine("{0}", siddhuBuilder); }
559
4. Now run the program and you should have a output like this:
The way the above program works is Example 14.6 is identical to Example 14-5, except that the latter example does not instantiate an object of type Regex. Instead, Example 146 uses the static version of Split ( ), which takes two arguments: a string to search for and a regular expression string that represents the pattern to match. The instance method of Split ( ) is also overloaded with versions that limit the number of times the split will occur and also determine the position within the target string where the search will begin.
560
Example Try it out Eagles MatchCollection Step by Step Example: Using Version 2005
1. Create a new Console application and name it as Eagles MatchCollection in the directory C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Using MatchCollection 2. Enter the following code in the namespace as follows: using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; 3. Now enter the following code in the program .cs and the code as follows: static void Main(string[] args) { string string1 = Welcome Siddhu!"; // find any nonwhitespace followed by whitespace Regex theReg = new Regex(@"(\S+)\s"); // get the collection of matches MatchCollection theMatches = theReg.Matches(string1); // iterate through the collection foreach (Match theMatch in theMatches) { Console.WriteLine( "theMatch.Length: {0}", theMatch.Length); if (theMatch.Length != 0) { Console.WriteLine("theMatch: {0}", theMatch.ToString()); } }
561
4. Now run the program and you should have the output like this:
Now lets see how the above program works Example 14.7 creates a simple string to search: string string1 = "Welcome Siddhu!"; And a trivial regular expression to search it: Regex theReg = new Regex(@"(\S+)\s");
The string \S finds no white space, and the plus sign indicates one or more. The string \s (note lowercase) indicates white space. Thus, together, this string looks for any no white space characters followed by white space.
DENOTE: Remember that at (@) symbol before the string creates a verbatim string, which avoids the necessity of escaping the backslash (\) character.
The output shows that the first four words were found. The final word was not found because it is not followed by a space. If you insert a space after the word string and before the closing quotation marks, this program will find that word as well.
562
The length property is the length of the captured substring, and is discussed in Section 14.3.6, later in this chapter.
DENOTE: IP addresses are used to locate computers on a network, and typically have the form x.x.x.x, where x is generally any digit between 0 and 255 (such as 192.168.0.1). The Group class allows you to create groups of matches based on regular expression syntax, and represents the results from a single grouping expression. A grouping expression names a group and provides a regular expression; any substring matching the regular expression will be added to the group. For example, to create an ip group you might write: @"(? <Ip> (\d|\.)+)\s"
The Match class derives from Group, and has a collection called "Groups" that contains all the groups your Match finds. Creation and use of the Groups collection and Group classes is illustrated in Example 14-8.
563
Example Try it out Eagles Group Class Step by Step Example: Using Version 2005
1. Create a new Console Application name it as Eagles Group Class in the directory D:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Using Group Class 2. Now enter the following in the System. Namespace. using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions;
564
3. Enter the following code into the program.cs body as follows: static void Main(string[] args) { string string1 = "05:11:25 127.0.0.0 eaglesgroup.com"; // group time = one or more digits or colons followed by space Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" + // ip address = one or more digits or dots followed by space @"(?<ip>(\d|\.)+)\s" + // site = one or more characters @"(?<site>\S+)"); // get the collection of matches MatchCollection theMatches = theReg.Matches(string1); // iterate through the collection foreach (Match theMatch in theMatches) { if (theMatch.Length != 0) { Console.WriteLine("\ntheMatch: {0}", theMatch.ToString()); Console.WriteLine("time: {0}", theMatch.Groups["time"]); Console.WriteLine("ip: {0}", theMatch.Groups["ip"]); Console.WriteLine("site: {0}", theMatch.Groups["site"]); } }
565
4. Now run the application and you should have a output like this:
Now lets see how the above program works: Again, Example 14-8 begins by creating a string to search: string string1 = "05:11:25 127.0.0.0 eaglesgroup.com";
This string might be one of many recorded in a web server log file or produced as the result of a search of the database. In this simple example, there are three columns: one for the time of the log entry, one for an IP address, and one for the site, each separated by spaces. Of course, in an example solving a real-life problem, you might need to do more complex searches and choose to use other delimiters and more complex searches. In Example 14-8, we want to create a single Regex object to search strings of this type and break them into three groups: time, ip address, and site. The regular expression string is fairly simple, so the example is easy to understand. However, keep in mind that in a real search, you would probably only use a part of the source string rather than the entire source string, as shown here:
566
// group time = one or more digits or colons // followed by space Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" + // ip address = one or more digits or dots // followed by space @"(?<ip>(\d|\.)+)\s" + // site = one or more characters @"(?<site>\S+)"); Let's focus on the characters that create the group:
(@"(?<time>(\d|\:)+)
The parentheses create a group. Everything between the opening parenthesis (just before the question mark) and the closing parenthesis (in this case, after the + sign) is a single unnamed group. The string ?<time> names that group time, and the group is associated with the matching text, which is the regular expression (\d|\:)+)\s". This regular expression can be interpreted as "one or more digits or colons followed by a space." Similarly, the string ?<ip> names the ip group, and ?<site> names the site group. As Example 14-7 does, Example 14-8 asks for a collection of all the matches: MatchCollection theMatches = theReg.Matches(string1);
Example 14-8 iterates through the Matches collection, finding each Match object. If the Length of the Match is greater than 0, a Match was found; it prints the entire match: Console.WriteLine("\ntheMatch: {0}", theMatch.ToString( ));
567
It then gets the "time" group from theMatch.Groups collection and prints that value: Console.WriteLine("time: {0}", theMatch.Groups["time"]);
The code then obtains ip and site groups: Console.WriteLine("ip: {0}", theMatch.Groups["ip"]); Console.WriteLine("site: {0}", theMatch.Groups["site"]);
This produces the output: ip: 127.0.0.0 site: eaglesgroup.com In Example 14-8, the Matches collection has only one Match. It is possible, however, to match more than one expression within a string. To see this, modify string1 in Example 14-8 to provide several logFile entries instead of one, as follows: string string1 = "05:11:25 127.0.0.0 eaglesgroup.com " + "05:12:28 127.0.0.0 siddhu.com " + "05:12:29 127.0.0.0 sri.com " ;
568
In this example, theMatches contains three Match objects. Each time through the outer foreach loop we find the next Match in the collection and display its contents: foreach (Match theMatch in theMatches) For each of the Match items found, you can print out the entire match, various groups, or both.
Each time a Regex object matches a subexpression, a Capture instance is created and added to a CaptureCollection collection. Each capture object represents a single capture. Each group has its own capture collection of the matches for the subexpression associated with the group. A key property of the Capture object is its length, which is the length of the captured substring. When you ask Match for its length, it is Capture.Length that you retrieve, because Match derives from Group, which in turn derives from Capture.
DENOTE: The regular expression inheritance scheme in .NET allows Match to include in its interface the methods and properties of these parent classes. In a sense, a Group is-a capture: it is a capture that encapsulates the idea of grouping subexpressions. A Match, in turn, is-a Group: it is the encapsulation of all the groups of subexpressions making up the entire match for this regular expression.
569
Typically, you will find only a single Capture in a CaptureCollection, but that need not be so. Consider what would happen if you were parsing a string in which the company name might occur in either of two positions. To group these together in a single match, create the? <Company> group in two places in your regular expression pattern: Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" + @"(?<company>\S+)\s" + @"(?<ip>(\d|\.)+)\s" + @"(?<company>\S+)\s");
This regular expression group captures any matching string of characters that follows time, and also any matching string of characters that follows ip. Given this regular expression, you are ready to parse the following string: string string1 = "05:11:25 127.0.0.0 eaglesgroup.com ";
The string includes names in both the positions specified. Here is the result: theMatch: 05:11:25 127.0.0.0 eaglesgroup.com time: 05:11:25 ip: 0.0.0.127 Company: EaglesGroup What happened? Why is the Company group showing EaglesGroup? Where is the first term, which also matched? The answer is that the second term overwrote the first. The group, however, has captured both. Its Captures collection can demonstrate, as illustrated in Example 14-9.
570
Example Try it out Eagles CaptureCollection Step by Step Example: Using Version 2005
1. Create a new Console Application and name it as Eagles CaptureCollection in the directory C:\EaglesVisualCSharp\Chapter 14 Strings and Regular Expressions\Example Using CaptureCollection 2. Enter the following code in the System. Namespace using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; 3. Now enter the following code in the program.cs body as follows:
571
static void Main(string[] args) { // the string to parse // note that names appear in both // searchable positions string string1 = "05:11:25 Siddhu 0.0.0.127 EaglesGroup "; // regular expression which groups company twice Regex theReg = new Regex(@"(?<time>(\d|\:)+)\s" + @"(?<company>\S+)\s" + @"(?<ip>(\d|\.)+)\s" + @"(?<company>\S+)\s"); // get the collection of matches MatchCollection theMatches = theReg.Matches(string1); // iterate through the collection foreach (Match theMatch in theMatches) { if (theMatch.Length != 0) { Console.WriteLine("theMatch: {0}", theMatch.ToString( )); Console.WriteLine("time: {0}", theMatch.Groups["time"]); Console.WriteLine("ip: {0}", theMatch.Groups["ip"]); Console.WriteLine("Company: {0}", theMatch.Groups["company"]); // iterate over the captures collection // in the company group within the // groups collection in the match foreach (Capture cap in theMatch.Groups["company"].Captures) { Console.WriteLine("cap: {0}",cap.ToString( )); } } } }
572
4. Now run the program and you should have the following output like this:
The following code iterates through the Captures collection for the Company group: foreach (Capture cap in theMatch.Groups["company"].Captures)
Let's review how this line is parsed. The compiler begins by finding the collection that it will iterate over. theMatch is an object that has a collection named Groups. The Groups collection has an indexer that takes a string and returns a single Group object. Thus, the following line returns a single Group object: theMatch.Groups["company"]
The Group object has a collection named Captures. Thus, the following line returns a Captures collection for the Group stored at Groups["company"] within the theMatch object: theMatch.Groups["company"].Captures
The foreach loop iterates over the Captures collection, extracting each element in turn and assigning it to the local variable cap, which is of type Capture. You can see from the output that there are two capture elements: Siddhu and EaglesGroup. The second one overwrites the first in the group, and so the displayed value is just EaglesGroup. However, by examining the Captures collection, you can find both values that were captured.
573
Summary
In this chapter we had look the String and Regular expression which we used in the Visual C#.NET and the topics we covered so far are as follows: Introduction to Strings and Regular Expressions Strings Creating Strings The ToString( ) Method Manipulating Strings Finding Substrings Splitting Strings Manipulating Dynamic Strings Regular Expressions Using Regular Expressions Using Regex Match Collections Using Regex Groups Using CaptureCollection
574
Chapter 15
575
576
From the design view, we can drag and drop controls onto our form, adjust their size, position and a great many more properties that range from determining the text displayed on the control to specifying a data source from which to populate the control. Before we look at the controls available, lets take a look at the from itself right click on the form, select View Code from the menu that appears, and youll be taken to the code editor. Here; the top portion of the code that youll see:
577
As you can see, there is a number of using directives at the top of the code for importing a number of namespaces that are commonly using in writing Windows applications weve highlighted the System.Windows.Forms namespace. The functionality for creating Windows application such as interface display, and user interaction is provided by the classes in this namespace. The other line highlighted above is the class definition for the Form1 class the: System.Windows.Forms.Form syntax indicates that this class derives form the Form class of the System.Windows.Forms namespace. The form that is displayed to user with all its control making up carefully crafted user interface is in fact an instance of a class that derives from System.Windows.Forms.Form (in System.Windows.Forms.Form class. Well see in a moment where the instance of the class is actually created in the code. Click on the Fom1.cs [Design] tab to return to the design view, click on the form to select it, and then set its Name property to MyForm in the Properties window. Now if you return to the code view, you will find the class has been renamed: public MyForm() However, if you attempt to run the application at this point you will receive the error the type or namespace name Form1 could not be found it seems that not allowed not all reference to the Form1 have been changed to MyForm. The culprit is found in the Main () method:
578
} Application is a class of the System.Windows.Forms namespace, providing the functionally that takes cares of the behind the scene activities for the execution of Windows applications. Here a new instance of our Form1 class is passed to the Run () method, which starts our application and displays the form. This is code we dont have to worry about, except when we change the name of the form in the form designer in Visual Studio.NET, if you change the name of the form in the form designer, you have to manually change its name in the Run () parameter in the Main() method as well. Thus, our Main () method needs to become: static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
} Well keep reminding you of this point when we change then name of forms in our examples its easy to forget!
579
580
The Toolbox consists of the controls that ship with the .NET Framework you are not limited to use this selection, and if is possible to customizing the Toolbox by adding you own custom built or bought controls. Building custom controls is something well look at this in the later chapter, but for now well concentrate on a sunset of the controls that we will be looking below:Now that you Toolbox is open, double click on the Button control, and an instance will appear on you form. Drag the button to the middle of the form:
Well, weve not written Microsoft Word just yet, but its start! Double click on the Button and youll be taken back to the code editor with the following method signature provided for you: private void button1_Click(object sender, EventArgs e) { } The code is generated by Visual Studio.NET is the event handler for the Button controls click event, well take a closer look at the events look at the events available to control in a movement, but for now well just mention the Click event is the event raised when the Button is clicked with the left mouse button. Each control has a default event, and when you double click on the control in the design view of Visual Studio.NET, code will be added to your file that allows the control to subscribe to the event, and the
581
method signature for handling the event will also be added, and you will be taken to this code. Weve see the event handler, but were is the code subscribing to the event? If you look through the file you will find a form1.designer.cs when you expand this region,
You will see the following option and just click on the Form1.Designer.cs and you will see the following
Just expand it and you will see the following code: #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // button1 // this.button1.Location = new System.Drawing.Point(94, 111); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(107, 32); this.button1.TabIndex = 0; this.button1.Text = "button1"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click);
// // MyForm //
582
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add (this.button1); this.Name = "MyForm"; this.Text = "Fom1"; this.ResumeLayout(false); } #endregion The InitializeComponent () method contains the code automatically generated by Visual Studio.NET. DENOTE: Be careful if you modify the code in this method, (the comment before the method advise you against it!) since it is possible to introduce errors that prevent youre form from being displayed in the designer until you have corrected the error. The highlighted lines above show the Button Controls (button1) contribution to this method including the line that subscribes the Button to Click event: this.button1.Click += new System.EventHandler(this.button1_Click); You should take a minute to look over the statements in this section. You will see exactly why it is possible to create a Windows Application without using the Visual Studio.NET. Every thing in this section could simply be entered in Notepad or a similar text editor and compiled. You will also see why that is not advisable. Keeping track of everything in here is difficult at the best of times; it is easy to introduce errors and , because you cannot se the effects f what you are doing, arranging the controls on the form to look right is a cumbersome task. This does, however, open the door for third party software producers to write their own programming environments to rival Visual Studio.NET because the compilers used to create the actual applications are included with the .NET Framework rather than being dedicated to Visual Studio.NET. Now that we know where well be doing our work, and weve had a quick peek behind the scenes, lets look at controls in general.
583
15.4 Controls
Most controls in .NET derive form the System.Windows.Forms.Control class. This class defines the basic functionality of the control, which is why many properties and events in the controls well see are identical. Many of those classes are themselves base classes for other controls, as is the case with the Label and Textbox Base classes in the diagram below:
DENOTE: some, named custom or user controls, derive from another class: System.Windows.Forms.UserControl. This class is itself derived form the Control class and provided the functionality we need to create controls over selves. Incidentally, controls used for designing web user interface from yet another class, System.Web.UI.Control.
584
15.5 Properties
All controls have a number of properties that are used to manipulate the behavior of the control. The base class of the most controls, System.Windows.Forms.Control, has a number of properties that other controls either inherit directly or override to provide some kind of custom behavior. The table below shows some of the most common properties of the Control class, these properties will be present in most of the controls well visit in this chapter, and they will therefore not be explained in details again, unless the behavior of the properties is change d for the control in questions. DENOTE: That this table is not meant to exhaustive; if you want to see all the properties in the class, please refer to the .NET Framework SDK Documentation
585
Name Anchor Back Color Bottom Dock Enabled ForeColor Height Left Name Parent Right TabIndex TabStop Tag
Description Using this property, you can specify how the controls behave when its container is resized. See below for the detailed explanation of this property. The background color of a control By setting this property, you specify the distance from the top of the window to the bottom of the control. This is not the same as specifying the height of the control. Allows you to make a control dock to the edge of a window. See below for more detailed expatiation of this property Setting Enabled to true usually mean that the control that control can receive input from the user. Setting Enabled to false usually means that it cannot. The foreground color of the control The distance from the top to the bottom of the control. The name of the control. This name can be used to reference the control in code. The name of the control. This name can be used to reference the control in code. The parent of the control. The right edge of the control relative to the left edge of the window. The number the control has in the tab order of its container. Specifies whether the control can be accessed by the Tab key This value is usually not used by the control itself and is there for you to store information about the control on the control itself. When this property is assigned a vale through the Windows Form designer, you can only assign a string to it. Holds the text that is associated with this control The top edge of the control relative to the top of the window. Specifies whether or not the control is visible at runtime. The width of the control
586
DENOTE: if you have experienced with Visual Basic you may notice that in .NET the Text property is used to set the text that is displayed, rather than a Caption property. You will find that all intrinsic .NET controls use the name Text to describe the main text for a control. Before .NET, Caption and Text were used interchangeable between different controls.
587
15.7 Events
In the last section, we saw what events are, ands how we can use them. Here we will talk about a particular kind of events, specifically the events generated by Windows Forms controls. These events are usually associated with actions of the user. For example, when the user clicks or presses a button, that button generates an event in which it says what just happened to it. Handling the events is then means by which the programmer can provide some functionality for that button. The control class defines a number of events that are common to controls well use this chapter. The table below describes a number of those events. DENOTE: That this table is not meant to exhaustive; if you want to see all the properties in the class, please refer to the .NET Framework SDK Documentation Name Click DoubleClick Description Occurs when a control is click. In some cases, these events will also occur when a user presses Enter. Occurs when a control is double clicked. Handling the Click event on some controls, such as the Button control will mean that the DoubleClick event can be called. Occurs when a drag and drop operation in completed, in other words, when an object has been dragged over the control, and user release the mouse button Occurs when an object begging dragged enters then bounds of the control Occurs when an object being dragged leaves the bounds of the control Occurs when an object has been dragged over the control. Occurs when a key becomes pressed while the control has focus. This event always occurs before KeyPress and KeyUp. Occurs when a key becomes pressed while a control has focus. This event always occurs after KeyDown and before KeyUp. The difference between KeyDown and KeyPress is that KeyDown passes the keyboard code of the key that has been pressed, while KeyPress passes the corresponding Char value for the key
588
Validating
Occurs when a key is released while a control has focus. This event always occurs after KeyDown and KeyPress. Occurs when a control receives focus. Dont not use this event to perform validation of controls. Use validating instead Occurs when a control loses focus. Do not use this event to perform validation of controls. Use validating and validate instead. Occurs when the mouse pointer is over a control and a mouse button is pressed. This is not the same as a click event because MouseDown occurs as soon as then button is pressed and before it is released. Occurs continually as the mouse travels over the control. Occurs when then mouse pointers is over a control and mouse button is released. Occurs when then control is drawn This event is fired when a control with the CasueValidation property set to true is about to receive focus. It fires after the Validation event finishes and indicates that validation is complete. Fires when a control with the CauseValidation property set to true is about to recive focus. Note that the control which is to be validated is the control which is losing focus, not then one that is reciving it.
We will see many of these events in the examples in the rest of the chapter. All our example will follow the same format, where we first create the forms visual appearance, choosing and positioning controls, etc... Before we then move onto adding then event handlers this is where the main work of our examples takes places. To handle a particular event there are three basic ways of going about it. The first is to double click on the control in question, any you will be taken to the event handler for the controls default event this event different from then default one of the control, there are two possible ways of proceeding. One way is to use the Events list in the Properties windows:
589
The grayed event is that controls default event. To add handler for a particular event, double click on that event in the Events list, and the code to subscribe the control to the event will be generated, along with the method signature to handle the event. Alternatively, you can type a name for the method to handle then particular event next to that event in the Events lists, and when you press enter the event handler will be generated with your chosen name. Another option is to add the code to subscribe to the event yourself well do this often in this and then next chapter by adding the code to the forms constructor after the InitializeComponent () call. Of Course, we still have to add the method signature to handle the event ourselves as well, and this method has then drawback that you need to know the exact method signature for the event.
590
Note that each of these two options requires two steps subscription to the event and the correct signature for the method handler. If you double click on a control and true to handle another event by editing then method signature of the default event for the event for the event that you actually want handled, you will fail you also need to alter the event subscriptions code in InitializeComponent (), and so this cheating method is method is not really a quick way to handle particular events. We are now ready to start looking at the controls themselves, and well start with one that weve seen in then pervious chapter, the Button Control.
591
DENOTE: That this table is not meant to exhaustive; if you want to see all the properties in the class, please refer to the .NET Framework SDK Documentation
Name FlatStyle
Enabled
Image ImageAlign
Description The style of the button can be changed with this property. If you set the style to Popup, the button will appear flat until the user moves the mouse pointer over it. When that happen, the button pop up to its normal 3D look. Well mention this here even though it is derived from Control, because its a very important property for a button. Setting the Enabled property to false means that the button becomes grayed out and something happens when you click it. Allows you to specify an image (bitmap, icon, etc), which will be displayed on the button. With this property, you can set where the image on the button should appear.
592
3. Right Click a button and select Properties. Then change the name of each button as indicated in the picture above by selecting then (Name) edit filed in the Properties window and typing the relevant text 4. Change the Text property of each button the be the same as the name, but omit the btn prefix for the Text property value. 5. We want to display a flag in front of the text to make it clear what we are talking about. Select the English Button and find the Image property. Click () to the right it to bring up a dialog where you can select an image. The flag icons we want to display come with Visual Studio.NET. If you installed to the default location (on an English language installation) they should be located in C:\ Program Files \ Microsoft Visual Studio.NET \ Common7\ Graphics\icons\Flags. Select the icon flguk.ico. Repeat this process with the Danish button, selecting the flgden.ico file instead (If you want to use a different flag here, then this directory will have other flags to choose from.) 6. Youll notice at this point that the button text and icon are placed on top of each other, so we need to change the alignment of the icon. For both English and Danish buttons, change the Image Align property to Middle Left. 7. At this point you may want to adjust the width of the buttons so that the text doesnt start right where the images end. Do this by selecting each of the buttons and pulling the notch on the right handed edge of the button.
593
8. Finally, click on the form and change the Text property to Do You Speak English? Thats it for the user interface of our dialog. You should now have something that look like this:
Now we are ready to add the event handlers to the dialog. Double click the English button. This will take you directly to the event handlers for the controls default event the Click event is the default event for the buttons and so that is the handler created.
594
Return to the design view and Double click the Danish Button and you will be taken to the event handler for that button. Here is the code: private void btndanish_Click(object sender, EventArgs e) { this.Text = "Taler du dansk?"; } This method is identical to the btnEnglish_Click, except that the text is in Danish. Finally, we add the event handler for the OK button in the same way as weve done twice now. The code is little different though: private void btnok_Click(object sender, EventArgs e) { Application.Exit () } With this we exit the appliation and, with it, this first example.Compile it, run it and press a few of the buttons. You will get the output simiular to this:
595
And thats it for most user of the Label control. Usually you need to add no event handling code for a standard Label, although it does support events like all controls. In the case of the LinkLabel, however, some extra code is needed if you want to allow the user to click it and take him or her to the web page show in the text. The Label control has a surprising number of properties that can be set. Most of these are derived from control, but some are new. The following table lists the most common ones. Unless stated otherwise, the properties are common to both the Label and LinkLabel controls. DENOTE: That this table is not meant to exhaustive; if you want to see all the properties in the class, please refer to the .NET Framework SDK Documentation Name Description Allows you to specify the style of the border the label. Border Style The default is no border. (LinkLabel only) the color of the LinkLabel after the DisabledLinkColor user has clicked it. Controls how the control is displayed. Setting this Flat Style property to Popup will make the control appear flat the user moves the mouse pointer over the control. At that time, the control will appear raised. This property allows you to specify a single image Image (bitmap, icon, etc...), to be displayed in the Label. (Read/Read) Where in the Label the image is shown. ImageAlign (LinkLabel only) The range in the text that should Link Area displayed as link. (LinkLabel only) It is possible for LinkLabel to Link Color contain more than one link. This property allows you to find the link you want. The control keeps track of the links displayed in the text. Not available at design time. (Link Label only) Returns whether a link has been Link Visited visited or not. Where in the control the text is shown. Text Align
596
Character Casing
Max Length
597
only by available memory. Multiline Indicates if this is a multiline control, which means it is able to show multiple lines of text. When Multiline property is set to true, youll usually want to set Word-Wrap to true as well. Specifies if a password character should replace the actual characters entered into a single line TextBox. If the Multiline property is true then this has no effect. A Boolean indicating if the text is read only. Specifies if a multiline TextBox should display scrollbars. The Text that is selected in the TextBox. The Number of characters selected in the text. If this value is set to be larger than the total number of characters in the text, it is reset by the control to be the total number of characters minus the value of Selection Start. The start of the selected text in a TextBox. Specifies if a multiline TextBox should automatically wrap words if a line exceeds the width of the control.
Password Char
598
Name
Description These six events occur in the order they are listed here. They are known as Focus Events and are fired whenever a controls focus changes, with two exceptions. Validating and Validated are only fired if the control that receives focus has the Causes Validation property set to true. The reason why its the reciving control that fires the events is that there are times where you do not want to validate the control, even if focus changes. An example of this is if the user clicks a Help button. These three events are known as Key Events. They allow you to monitor and change what is entered into you controls. Key Down and Key Up recive the key code corresponding to the key that was pressed. This allows you to determine if special keys such as Shift or Control and F1 were pressed. Key Press, on the other hand, receives the character corresponding to a keyboard key. This means that the value for the letter a is not the same as the letter A. it is useful if you want to exclude a range of characters, for example, only allowing numeric value to be entered. Occurs when ever the text in the TextBox is changed, no matter what the change.
Text Changed
599
600
3. Name the controls as indicated in the picture above. 4. Set the Text property of each Text Box to an empty string, which means that they will contain noting when the application is first run. 5. Set the Text property of all the other controls to the same as the name of the control, except for the first three letters. Set the Text property to Eagles TextBoxText. 6. Set the Scrollbars property to the two controls txtOutput and txtAddress to Vertical. 7. Set the ReadOnly property to the txtOutput control to true. 8. Set the CasusesValidation property to the btnHelp Button to false.
9. When you have sized the from to fit snugly around the controls, it is time to anchor the controls so they behave properly when the from is resized. Lets set the Anchor property for each type of control in one go first of all, select all the Label controls by holding down the Ctrl key while you select each Label in turn. Once youve selected them all, set the anchor property to Top, Left from the Properties window, and the Anchor property for each of the selected Label controls will be set as well. Repeat this procedure to set the Anchor property for each TextBox to Top, Left, and Right and additionally set the Anchor property txtOutpt TextBox to Top, Bottom, Left, and Right. Now set the Anchor property for both Button controls to Top, Right. The reason why txtOutput is anchored rather than docked to the bottom of the form is that we want the output text area to be resized as we pull the form. If we had docked the control to the bottom of the form, it would be moved to stay at the bottom, but it would not be resized. 10. One final thing should be set. On the form, find the Size and MinimumSize properties. Our form has little meaning if it is sized to some thing smaller that it is now, therefore you should set the MinimumSize property to the same as the Size property. The job of setting up the visual part of the form is now complete. If you run it nothing will happen when you click the button s or enter text, but if you maximize or pull in the dialog, the control behave exactly as you want them to in a proper user interface, staying put and resizing to fill the whole of the dialog.
601
private void btnHelp_Click(object sender, EventArgs e) { // Write a short description of each TextBox in the OutPut TextBox //EaglesSiddhu //SriJai string output; output = "Name = Your Name \r\n"; output += "Address = Your address \r\n"; output += "Occupation = Only allowed value os 'Programmer'\r\n"; output += "Age = Your Age"; //Insert the new text this.txtOutput.Text = output; }
602
In both functions the Text property of each TextBox is used, either retervied, set in the btnOk_Click () function, or simply set as in the btnHelp_Clcik () function. We insert information the user has entered without bothering to check if it is correct. This means that we must do the checking elsewhere. In this example, there are a number of criteria that we wish to enforce in order to be correct: The name of user cannot be empty The age of the user must be number grater than or equal to zero The address of the user cannot be empty From this we can see that the check that must be done for two of the textboxes (txtName and txtAddress) is the same. We also see that we should prevent the user form entering anything invalid into the Age box, and finally, we must check if the user claims to be a programmer. To prevent the user form clicking OK before anything is entered we start by setting the OK buttons Enabled property to false this time well for it in the constructor of our form rather than from the Properties window. If you do set properties in the constructor, make sure not to set them until after the generated code in InitizliaeComponmnet () has been called. public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); this.btnOk.Enabled = false; } Now well create the handler for the two text boxes that must be checked to see if they are empty. We do this by subscribing to the Validating event of the text boxes. We inform the control that the event should be handled by a method named txtBoxEmpty_Validating (), so thats a single event handling method for two different controls. We also need a way to know the stat of our control. For this purpose, we use the Tag property of the TextBox control. If you recall the discussion of this property from earlier in this chapter, we said that only strings can be assigned to the Tag property from the Forms Designer. However, as we are setting the Tag value from code, we can of pretty much what we want with it, since the Tag property takes an object, and it is more appropriate to enter a Boolean value here.
All Rights Reserved To EaglesGroup
603
this.btnOk.Enabled = false; // Tag Values for texting if the data is valid this.txtAddress.Tag = false; this.txtAge.Tag = false; this.txtName.Tag = false; this.txtOccupation.Tag = false; // Subscription to events this.txtName.Validating += new System.ComponentModel.CancelEventHandler(this.txtBoxEmpty_Validating); this.txtAddress.Validating += new System.ComponentModel.CancelEventHandler(this.txtBoxEmpty_Validating); Unlike the button event handler weve seen previously, the event handler for the Validating event is a specialized version of the standard handler System.EventHandler. The Reason this event needs a special handler is that should the validation fail, there must be a way to prevent any further processing. If we were to cancel further processing, that would effectively mean that it would be impossible to leave a text box until the data entered is valid. The Validating and Validated events combined with the Causes Validation property fix a nasty problem that occurred when using the GotFouces and LostFocus events to perform validation of controls. The problem occurred when the GotFouces and LostFocus events were continually fired because validation code was attempting to shift the focus between controls, which created an infinite loop. We add the following event handler as follows:
604
private void txtBoxEmpty_Validating(object sender, System.ComponentModel.CancelEventArgs e ) { // We know the sender is a TextBox, so we cast the sender object to that TextBox tb = (TextBox) sender; TextBox tb = (TextBox)sender; // if the text is empty we set the back ground color of the // TextBox to read to indicate a problem, we use the tag value // of the control to indicate if the control contains valid // information. if (tb.TextLength == 0) { tb.BackColor = Color.Red; tb.Tag = false; // In this case we do not want to cancel further processing, // but if we had wanted to do this, we would have added this lione; // e.Cancel = true; } else { tb.BackColor = System.Drawing.SystemColors.Window; tb.Tag = true; } //Finally, we call ValidateAll which will set the value of // the OK button. ValidateAll } Because more than one text box is using this method to handle the event, we cannot be sure which is calling the function. We do know, that the effect of calling the method should be the same no matter who is calling, so we can simply cast the sender parameter to TextBox and work on that: TextBox tb = (TextBox) sender; If the length of the text in the text box is zero, we set the background color to red and the Tag to false. If it is not, we set the background color to the standard Windows color for a window.
605
DENOTE: Should always use the color found in the System.Drawing.SystemColors enumerations when you want to set a standard color in a control. If you simply set the color to white, you application will look strange if the user has changed the default color setting. Well postpone our description of the ValidateAll () function until the end of this example. Keeping with the validating event, the next handler well add is for the Occupation text box. The procedure is exactly the same as for the two previous handlers, but the validation code is different because occupation must be Programmer or an empty string to be valid. We therefore add a new line to the constructor. This.txtOccupation.Validating += new System.ComponentModel.CancelEventHandler(this.txtOccupation_Validating); And then the handler itself:
private void txtOccupation_TextChanged(object sender, EventArgs e) { // Case the sender object to a textbox TextBox tb = (TextBox)sender; // Check if the values are correct if (tb.Text.CompareTo("Programmer") == 0 || tb.Text.Length == 0) { tb.Tag = true; tb.BackColor = System.Drawing.SystemColors.Window; } else { tb.Tag = false; tb.BackColor = Color.Red; } // Set the state of the OK button ValidateAll(); } Our second to last challenge is the age text box. We dont want the user to type anything but positive numbers (including 0 to make the test simpler). To achieve this well use the KeyPress event to remove any unwanted characters before they are shown in the text box.
606
First, we subscribe to the KeyPress event. Select the txtAge text box and double click on the KeyPress event in the Events list of the Properties window. The KeyPress event handler is specialized as well. The System.Windows.Forms.KeyPressEventHandler is supplied because the event needs information about the key that was pressed.
Add the following code to the event handler itself: private void txtAge_keyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { if ((e.KeyChar < 48 || e.KeyChar > 57) && e.KeyChar != 8) e.Handled = true; // remove the character } The ASCII values for the character between 0 and 9 lie between 48 and 57, so we make sure that the characters within this range. We make one exception though. The ASCII value 8 is the Backspace key, and for editing reasons, we allow this to slip through. Setting the Handled property of KeyPressEventArgs to true tell the control that it shouldnt do anything else with the character, and so if the Key pressed isnt a digit or a backspace, it is not shown. As it is now, the control is not marked as invalid or valid. This is because we need another check to see if anything was entered at all. This is a simple thing as weve already written the method to perform this check and we simply subscribe to the Validating event for this Age control as well by adding this line to the constructor: This.txtAge.Validating += new System.ComponentModel.CancelEventsHandler(this.txtBoxEmpty_Validating); One last case must be handled for all the controls. If the user has entered valid text in all the textboxes and then changes something, making the text invalid, the OK button remains enabled. So we have to handle one last event handler for all of the text boxes: the Change which will disable the OK button should any text filed contain invalid data. The TextChanged event is fired whenever the text in the control changes. We subscribing to the event by adding the following lines to the constructor:
607
//TextChangd event this.txtName.TextChanged += new System.EventHandler(this.txtBox_TextChanged); this.txtAddress.TextChanged += new System.EventHandler(this.txtBox_TextChanged); this.txtAge.TextChanged += new System.EventHandler(this.txtBox_TextChanged); this.txtOccupation.TextChanged += new System.EventHandler(this.txtBox_TextChanged); The TextChanged event uses the standard event handler we know form the Click event. Finally, we add the event itself. private void txtBox_TextChanged(object sender, System.EventArgs e) { // Case the sender object to a TextBox TextBox tb = (TextBox)sender; // Test if the data is valid and set the tag and background //color accordingly if (tb.Text.Length == 0 && tb != txtOccupation) { tb.Tag = false; tb.BackColor = Color.Red; } else if (tb == txtOccupation && (tb.Text.Length != 0 && tb.Text.CompareTo("Programmer") != 0)) { // Don't set the color here, as it will color changes while the user is typing tb.Tag = false; } else { tb.Tag = false; tb.BackColor = SystemColors.Window; } //Call ValidateAll to Set the OK Button ValidateAll(); } This time we must find out exactly which control is calling the event handler, because we dont have want the background color of the Occupation text box to change to red when the user starts typing. We do this by checking the Name property of the text box that was passed to us in the sender parameter. Only one this remains: the ValidateAll method that enables or disables the OK button.
608
private void ValidateAll() { // Set the OK Butotn to enabled if all the Tag are True this.btnOk.Enabled = ((bool)(this.txtAddress.Tag) && (bool)(this.txtAge.Tag) && (bool)(this.txtName.Tag) && (bool)(this.txtOccupation.Tag)); } The method simply sets the value of the Enabled property of the OK button to true if all of the Tag properties are true. We need to case the value of the Tag properties to a Boolean because it is stored as an object type. If you test the program now, you should see something like this:
Notice that you can click the Help button while you are in the text box with invalid data without the background color changing to red. The example weve just completed is quit long compared to the others you will see in this chapter this is because well build on this example rather than starting form scratch with example:
All Rights Reserved To EaglesGroup
609
DENOTE: Remember that you can have the example source code form the CD which is a in-built function in this Book make use of the CD to run the example thank you Enjoy Programming.
610
AutoCheck
CheckAlign
Checked
middle or right of it, or as a standard button. When it is displayed as button, the control will appear pressed when selected and not pressed otherwise. When his property is true, a check mark is displayed when the user clicks the radio button. When it is false the radio button must be manually checked in code from the Click event handler. By using this property, you can change the alignment of the check box portion of radio button. Then default is ContentAlignemnt.MiddleLeft. Indicates the status of the control. It is true if the control has a check mark, and false otherwise.
You will commonly use one event when working with RadioButton controls, but as always there are many others that can be subscribe to. Well only cover two in this chapter, and the only reason the second event is mentioned is that there is subtle difference between the two that should be noted. Name CheckedChanged Click Description This event is sent when the check of the RadioButton changes. This event is sent every time the RadioButton is clicked. This is not the same as the CheckedChanged event, because clicking a RadioButton two or more times in succession only changes the Checked property once and only if it wasnt checked already. Moreover, if the AutoCheck property of the button being clicked is false, the button will not get checked at all, and again only the Click event will be sent.
611
CheckState
Unlike the RadioButton, a CheckBox can have three states: Checked Indeterminate Unchecked When the state of the check box is Indeterminate, the control check next to the label is usually grayed, indicating that the current value of the check is not valid or has no meaning or has meaning under the current circumstances. When this property if false, the user will not be able to change the CheckState state to Indeterminate. You can, however, still change the CheckState property to Indeterminate from code.
ThreeState
CheckedStateChanged
This concludes the events and properties of the RadioButton and CheckBox controls. But before we look at an example using these, lets take a look at the GroupBox control which we mentioned earlier.
612
613
1. Remove the label named lblOccupation and the text box named txtOccupation. 2. Add a CheckBox, a GroupBox and two RadioButton controls, and name the new controls as shown in the picture below.
3. The Text Property of the RadioButton and CheckBox control should be the same as the named of the controls without the first three letters, and for the GroupBox the Text Property should be Sex. 4. Set the Checked property of the chkProgrammer check box to true.
5. Set the Checked property of either rdoMale or rdoFemale to true. Note that you cannot set both to true. If you try to, the value of the other RadioButton is automatically changed to
false. No more needs to be done on the visual part of the example, but there are number of changed in the code. First, we need to remove all the references to the text box that weve removed. Go to the code and complete the following steps.
All Rights Reserved To EaglesGroup
614
6. In the constructor to the form, remove the three lines which refer to txtOccupation. This includes subscription to the Validating and TextChanged events and the lines which sets the Tag property to false. 7. Remove the txtOccupation_Validating () method entirely.
615
} Since we are using a check box rather than a text box we know that the user cannot enter any invalid information, as he or she will always be either a programmer or not. We also know that the user is either male or female, and become we set the property of one of the radiobutton to true. The user is prevented from choosing an invalid value. Therefore, the only thing left to do is change the help text and the output. We do this in the button event handlers: private void btnHelp_Click(object sender, EventArgs e) { // Write a short description of each TextBox in the OutPut TextBox //EaglesSiddhu //SriJai string output; output = "Name = Your Name \r\n"; output += "Address = Your address \r\n"; output += "Programmer = Check 'Programmer' if you are a programmer \r\n"; output += "Sex = Choose your sex\r\n"; output += "Age = Your Age"; //Insert the new text this.txtOutput.Text = output; } Only the help text is changed, so nothing surprising in the help method. It gets slightly more interesting in the OK method: private void btnOk_Click(object sender, EventArgs e) { // No Testing for invlid vlaues are made, as that should not be necessayr // EaglesSiddhu //SriJai string output; //Concatenate the text values of the four TextBoxes output = "Name:" + this.txtName.Text + "\r\n"; output += "Address:" + this.txtAddress.Text + "\r\n"; output += "Occupation:" + (string)(this.chkProgrammer.Checked ? " Programmer" : "Not a Programmer") + "\r\n"; output += "Sex:" + (string)(this.rdoFemale.Checked ? "Female" : "Male") + "\r\rn"; output+= "Age" + this.txtAge.Text + "r\n"; // Insert the new text this.txtOutput.Text = output;
616
} The first of the highlighted lines is the line in which the occupation of the user is printed. We investigate the Checked property of the CheckBox, and if it is true, we write the string Programmer. If it is false, we write Not a programmer. The second line examines only the radio button rdoFemale. If the Checked property is true on that control. We know that the user claims to be female. If it is false we know that the user claims to be male. It is possioble to have radio buttons without any of them being checked when we start the program but become we checked one of the radio button at the design time, we know for sure that one of the two radio buttons will always be checked. When you run the example now, you should get a result similar to this:
617
618
SelectedText
Description This property is true when the last undone operation can be reapplied using Redo. This property is true if it is possiable to undo the last action on the RichTextBox. Note that CanUndo is defined in TextBoxeBase, so it is availabel to TextBox controls as well. This property holds the name of an action that would be preformed by Redo method. Set this property to true to make the control detect URLs and format them (underline as in a browser) This corresponding to the Text property, except that this holds the text in RTF. Use this property to get or set the selected text in the control, in RTF. If you copy this text to another applications, for example, Word, it will retain all formating. Like SelectedRtf you can use this property to get or set the selected text. However, unlike the RTF version of the property, all formating is lost. This represents the alignment of the selected text. It can be Center, Left, or Right. Use this property to find out if the selection is formatted with a bullet in front of it, or use it to insert or remove bullets. Use this property to specify the number of pixels a bullet should be indented. Allows you to change the color of the text in the selection. Allow you to change the font of the text in the selection.
619
SelectionLength SelectionType
ShowSelectionMargin
UndoActiveName SelectionProtected
Using this property, you either set or retervie the length of a selection. This property holds information about the selection. It will tell you if one or more OLE objects are selected or if only text is selected. If you set this property to trye, a margin will be shown at the left of the RichTextBox. This will make it easier for the user to select text. Gets the name of action that will be used if user chooses to undo something. You can specify that certain parts of the text should not be changed by setting this property to true.
As you can see from the listing above, most of the new properties have to do with s selection. This is because, any formating you will applying when a user is working on his or her text will propably be done on a selection made by that user. In case no selection made by user. In case no selection is made, the formating will start from the point in the text where the cursor is located, called the insertion point.
Description This event is sent when a user clcik on a link within the text. This event is sent when a user attempts to modify text that has been marked as protected. This event is sent when the selection changes. If for some reason you dont want the user to change the selection, you can prevent the change here.
620
3. Name the controls as indicated in the picture above and clear the Text Property of both rtfText and rtfSize. 4. Apart from the text boxes, set the Text of all controls to the same as the names except for the first three letters. 5. Change the Text propertyt of the txtSize text box to 10. 6. Anchor the controls as in the following table.
621
7. Set the MinimumSize property of the form to the same as the size property.
622
The event handlers for btnItalic and btnUnderline are the same as the one above, except we are checking the appropriate styles. Double click the two buttons Italic and Underline and add this code:
private void btnBold_Click(object sender, EventArgs e) { Font oldFont; Font newFont; //Get the font that is being used in the selected text oldFont = this.rtfText.SelectionFont; // If the font is using bold style now, we should remove the Formatting if (oldFont.Bold) newFont = new Font(oldFont, oldFont.Style & ~FontStyle. Italic); else newFont = new Font(oldFont, oldFont.Style | FontStyle. Italic); // Insert the new font and return focus to the RichTexBox this.rtfText.SelectionFont = newFont; this.rtfText.Focus(); } private void btnBold_Click(object sender, EventArgs e) { Font oldFont; Font newFont; //Get the font that is being used in the selected text oldFont = this.rtfText.SelectionFont; // If the font is using bold style now, we should remove the Formatting if (oldFont.Bold) newFont = new Font(oldFont, oldFont.Style & ~FontStyle. Underline); else newFont = new Font(oldFont, oldFont.Style | FontStyle. Underline); // Insert the new font and return focus to the RichTexBox this.rtfText.SelectionFont = newFont; this.rtfText.Focus(); } Double Clcik the last of the formatting buttons, Center, and add the following code:
623
private void btnCenter_Click(object sender, EventArgs e) { if (this.rtfText.SelectionAlignment == HorizontalAlignment.Center) this.rtfText.SelectionAlignment = HorizontalAlignment.Left; else this.rtfText.SelectionAlignment = HorizontalAlignment.Center; this.rtfText.Focus(); } Here we must check another property, SelectionAlignment, to see if the text in the selection is already centered. HorizontalAlignment is an enumeration with values Left, Right, Center, Justify, and NotSet. In this case we simply check if Center is set, and if it is, we set the alignment to left. If isnt we set it to Center. The final formatting our little text editor will be able to perform is setting the size of text. Well add two event handlers for the text box Size, one for controlling the input, and one to detect when the user has finished entering a value. Add the following lines to the constructor of the form: public Form1() { InitializeComponent(); // Event Subscription this.txtSize.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.txtSize_KeyPress); this.txtSize.Validating += new System.ComponentModel.CancelEventHandler(this.txtSize_Validating); }
We saw these two event handlers in the previous examples. Both of the events use a helper method called AppllyTextSize that takes a string with the size of the text.
624
private void txtSize_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { // Remove all characters that are not numbers, backspace and enter if ((e.KeyChar < 48 || e.KeyChar > 57) && e.KeyChar != 8 && e.KeyChar != 13) { e.Handled = true; } else if (e.KeyChar == 13) { // Apply size if the user hits enter TextBox txt = (TextBox)sender; if (txt.Text.Length > 0) ApplyTextSize(txt.Text); e.Handled = true; this.rtfText.Focus(); } } private void txtSize_Validating(object sender, System.ComponentModel.CancelEventArgs e) { TextBox txt = (TextBox)sender; ApplyTextSize(txt.Text); this.rtfText.Focus(); } private void ApplyTextSize (string textSize) { //Convert the text to a float because we'll be needing a flot shortly float newSize = Convert.ToSingle(txtSize); FontFamily currentFontFamily; Font newFont; //Create a new font of the same family but with the new size currentFontFamily = this.rtfText.SelectionFont.FontFamily; newFont = new Font (currentFontFamily, newSize ); // Set the font of the selected text to the new font this.rtfText.SelectionFont = newFont; }
625
The work we are interested in takes place in the helper method ApplyTextSize (). It starts by converting the size from a string to a float. Weve prevented the user entering anything but when we create the new font, we need a float, so convert it to the correct type. After that, we get the family to which the font belongs and we create a new font from that family with the new size. Finally, we set the font the selection to the new font. Thats all the formatting we can do, but some is handled by the RichTextBox itself. If you try to run the example now, you will be able to set the txt to Bold, Italic, and Underline, and you can center the text. That is what you except, but there is something else that is interesting try to type a web address, for example www.eaglesgroup.com in the text. The text recognized by the control as an Internet address, is underlined, and the mouse pointer changes to a hand when you move it over the text. If that leads you to believe that you can click it and brought to the page, you are almost correct. We need to handle the event that is sent when the user clicks a link: LinkClciked. We do this by subscribing to the event in the constructor: this.rtfText.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.rtfText_LinkedClick);
We havent seen this event handler before it is used to provide the text of the link that was clicked. The handler is surprisingly simple and looks like this: private void rtfText_LinkedClick(object sender, System.Windows.Forms.LinkClickedEventArgs e) { System.Diagnostics.Process.Start(e.LinkText); } This code opens the default browser if isnt open already and navigates to the site to which the link that was clicked is pointing. This editing part of the application is now done. All that remains is to load and save the contents of the control. Well use a fixed file to do this.
626
Double click the Load button, and add the following code:
private void btnLoad_Click(object sender, EventArgs e) { // Load the file into the RichTextBox try { rtfText.LoadFile("../..Text.rtf"); } catch (System.IO.FileNotFoundException) { MessageBox.Show("NoFiles To Load Yet", "EaglesGroup", MessageBoxButtons.OK, MessageBoxIcon.Error); } } Thats it! Nothing else had to be done. Because we are dealing with files, there is always a change that we might encounter exception, and we have to handle these. In the Load method we handle the exception that is thrown if the doesnt exit. It is equally simple to save the file. Double click the Save button and add this: private void btnSave_Click(object sender, EventArgs e) { //Save the Text try { rtfText.SaveFile("../../Text.rtf"); } catch (System.Exception eagles) { MessageBox.Show("EaglesGroup", eagles.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
627
Run the example now, format some text and click Save. Clear the text box and click Load and the text you just saved should reappear. This concludes the RichTextBox example. When you run it, you should be able to produce something like this:
628
Another kind of list box available is called CheckedListBox and is derived from the ListBox class. It provides a list just the ListBox, but in addition to the text strings it provides a check for each item in the list. Another kind of list box available is called CheckedListBox and is derived form the ListBox class. It provides just like the ListBox, but in addition to the text strings it provides a check for each item in the list.
ColownWidth
629
SelectedItem SelectionMode
This property is a collection, which contains all of the items currently selected. You can choose between four different modes of selection from the ListSelectionMode enumeration in a list box: None: No items can be selected One: Only one item can be selected at any time MultiSimple: Multiple items can be selected MultiExtended: Multiple items can be selected and the user can use the Ctrl, Shift, and arrows keys to make selections.
Sorted Text
CheckedIndices
Setting this property to true will cause the ListBox to sort the items it contains alphabetically. Weve seen Text properties on a number of controls, but this one works differently from any weve seen so far. If you set the Text property of the list box control, it searches for an item that matches the text, and selects it. If you get the Text property the value returned is the first selected item in the list. This property cannot be used if the SelectionMode is None. (CheckedListBox only) This property is a collection which contains indexes of all the items in the CheckedListBox that have a checked or indeterminate state. (CheckedListBox only) This is a collection of all the items in a CheckedListBox that are in a checked or indeterminate state. (CheckedListBox only) If this property is true, an item will change its state whenever the user clicks it. (CheckedListBox only) You can choose between CheckBoxes that are flat or normal by setting this property.
630
631
Normally the events you will want to be aware of when working with a ListBox or CheckedListBox are those that have to do with the selections that are being made by the user:
Description (CheckedListBox only) Occurs when the check state of the list items changes. Occurs when the index of the selected item changes.
Example Try it Out ListBox and CheckedListBox Test Step by Step Example:
Well create a small example with both a ListBox and a CheckedListBox. The user can check items in the CheckedListBox and then click a button which will move the checked items to the normal ListBox. We create the dialog as follows: 1. Create a new Windows application called Eagles Lists in directory C:\EaglesVisualCShap\Chapter 15 2. Add a List Box, a CheckedListBox and a button to the form and change the names as shown in the picture below:
632
633
3. Change the Text property of the button to Move. 4. Change the CheckOnClick property of the CheckedListBox to true.
We start by checking the Count property of the CheckedItems collection. This will be grater than zero if any items in the collection are checked. We then clear all items in the lstSelected list box, and loop though the CheckedItems collection, adding each item to the lstSelected list box. Finally, we remove all the checks in the CheckedListBox. Now we just need something in the CheckedListBox to move. We can add the items while in design mode, by selecting the Items property in the Properties window and adding the items there:
634
Also we can add item in code, for example in the constructor of our form:
public Form1() { InitializeComponent(); // EaglesSiddhu //Sri Jai //Add a eleventh element to the CheckedListBox this.chkListPossibleValue.Items.Add("Eleven"); } Here we add the eleventh element to the CheckedListBox, since we already have entered ten from the designer: This concludes the list box example, and if you run it now, you will get something like this:
635
636
The list view is usually used to present data where the user is allowed some control over the detail and style of the presentation. It is possible to display the data contained in the columns and rows much like in a grid, as a single column or with varying icon representations. The most commonly used list view is like the one seen above which is used to navigate the folders on a computer. The ListView control is easily the most complex control were going to encounter in this chapter, and covering all of it is beyond the scope of this book. What well do is provide a solid base for you to work on by writing an example that utilizes many of the most important features of the ListView control, and by a through description of the numerous proprieties, events, and methods that can be used. Well also take a look at the ImageList control, which is used to store the images used in a ListView control.
637
Alignment
TwoClick: Double clicking an item activates it. This property allows you to control how the items in the list view are aligned. The four possible values are: Default: If the user drags and drops an item it remains where he or she dropped it. Left: Items are aligned to the left edge of the ListView control Top: Items are aligned to the top edge of the ListView control SnapToGrid: The ListView control contains an invisible grid to which the items will snap.
AllowColumnReorder
AutoArrange
CheckBoxes
CheckedIndices CheckedItems
If you set this property to true, you allow the user to change the order of the columns in a list view. If you do so, you should be sure that the routines that fill the list view are able to insert the items properly; event the order of the columns is changed. If you set this property to true, items will automatically arrange them according to the alignment property. If the user drags an item to the center of the list view, and Alignment is Left, then the item will automatically jump to the left of the list view. This property is only meaningful if the View property is LargeIcon or Small Icon. If you set this property to true, every time in the list view will have a CheckBox displayed to the left of it. This property is only meaningful if the view property is Details or Left. These two properties give you access to a collection of indices and items respectively, containing the checked item
638
Columns
FocusedItem FullRowSelect
GridLines
HeaderStyle
in the list. A list view can contain columns. This property gives you access to the collection of columns through which you can add or remove columns. This property holds the item that has focus in the list view. If nothing is selected, it is null. When this property is true, and an item is clicked, the entire row in which the item resides will be highlighted. If it is false, only the item itself will be highlighted. Setting this property to true will cause the list view to draw grid lines between rows and columns. This property is only meaningful when the View property is Details. You can control how the column headers are displayed. There are three styles: Default: if the user drags and drops an item it remains where he or she dropped it. Left: Items are aligned to the left edge of the ListView control. Top: Items are aligned to the top edge of the ListView Control SnapToGrid: The ListView control contains an invisible grid to which the items will snap. When this property is true, the user can select an item in the list view by hovering the mouse pointer over it. The collection of items in the list view. When this property is true, the user can edit the content of the first column in a Details view. If this property is true, labels will wrap over as many lines is needed to display all the text This property holds the ImageList, which holds large images. These images can be
639
used when the View property is LargeIcon. Set this property to true to allow the user to select multiple items. Set this property to true to display scrollbars. These two properties contain the collections that hold the indices and items that are selected, respectively. When the View property is SmallICon this property holds the ImageList that contain the images used. You can allow the list view to sort the items it contains. There are three possible modes: Ascending Descending None The ImageList contains masks for images that are used as overlays on the LargeList and SmallImageList images to represent custom states. Returns the item at the top of the list view. A list view can display its items in four different modes: LargeIcon: All items are displayed with a large icon (32x32) and a label. SmallICon: All the items are displayed with a small icon (16x16) and a label List: Only one column is displayed. That column can contain an icon and label. Details: Any number of columns can be displayed. Only the first column can contains an icon.
StateImageList
TopItem View
640
Name BeginUpdate ()
Clear () EndUpdate ()
Description By calling this method you tell the list view to stop drawing updates until EndUpdate () is called. This is useful when you are interesting many items at once, because it stops the view from flickering and dramatically. Clear the list view completely. All items and columns are removed. Call this method, after calling BegingUpdate. When you call this method, the list view will draw all of its items. When you call this method, the list view will scroll itself to make the item with the index you specified visible. Returns the ListViewItem at position x, y in the list view.
EnsureVisible() GetItemAt()
641
activated.
15.31 ListViewItem
An item in a list view is always an instance of the ListViewItem class. The ListViewItem holds information such as text and the index of the icon to display. ListViewItem objects have s SubItems property that holds instances of another class, ListViewSubItem. These sub items are displayed if the ListView control is in Details mode. Each of the sub items represents a column in the list view. The main difference of sub items and the main items is that a sub item cannot display an icon. You add ListViewItem to the ListView thorough the Items Collection and ListViewSubItems to a ListViewItem through the SubItems collection on the ListViewItem.
15.32 CoumnHeader
To make a list view display column headers you add instances of class called ColumnHeader to the Columns collection of the ListView. ColumnHeaders provide a caption for the columns that can be displayed when the ListView is in Details mode.
642
3. Name the controls as shown in the picture above. The ListView will not display its name as in the picture above; Ive added an extra item just to show the name here you dont need to add this item.
643
4. Change the Text property of the radiobutton and button to the same as the name, except the for the first three letters, and the Text Property of the form to ListView. 5. Clear the Text property of the label. 6. Add two ImageList control to the form by double clicking the controls icon in the Toolbox. Rename the control ilSmall, and ilLarge. 7. Change the size property of the ImageList named ilLarge to 32, 32 8. Click the button to the right of the Images property of the ilLarge image list to bring up the dialog on which you can browse to the images you want to insert. 9. Click Add and browse to the folder under Visual Studio.NET that contains the images. The files are: <Drive>: \Program Files\Microsoft Visual studio .NET\Common7\Graphics\Icons\clsdfold.icon and <Drive>:\Program Files\Microsoft Visual studio .NET\Common\Graphics\Computer\msgbox04.ico 10. Make sure the folder icon is at the top of the list 11. Repeat steps 8 and 9 with the other ImagesList, ilSmall. 12. Set the Checked property of the radio button rdoDetails to true. 13. Set the following properties on the list view:
644
We didnt create any column headers in the forms designer, so well have to do that now. We create them in a method called CreateHeadersAndFileListView (): private void CreateHeadersAndFileListView() { ColumnHeader colHead; //First header colHead = new ColumnHeader(); colHead.Text = "Filename"; this.lwFilesAndFolders.Columns.Add(colHead); // Insert the header //Second Header colHead = new ColumnHeader(); colHead.Text = "Size"; this.lwFilesAndFolders.Columns.Add(colHead); //This will insert the header // Third header colHead = new ColumnHeader(); colHead.Text = "last Accesses"; this.lwFilesAndFolders.Columns.Add(colHead); // This will Insert eh header }
We start by declaring a single variable, colHead, which we will use to create the three column headers. For each of the three headers we declare the variable as new, and assign the Text to it before adding it to the Columns collection of the ListView. The final initialization of the form as it is displayed the first time is to fill the list view files and folders form your hard disk. This is done in another method:
645
private void PaintListView(string root) { try { // EaglesGroup //Siddhu //Sri Jai // Two local varibales that is used to create the items to insert ListViewItem lvi; ListViewItem.ListViewSubItem lvsi; // If there's no root folder, we can't insert anything if (root.CompareTo("") == 0) return; // Get information about the root folder. System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(root); // Reterive the files and folders form the root folder. DirectoryInfo[] dirs = dir.GetDirectories(); // This is for Folders/ FileInfo[] files = dir.GetFiles(); // This is for to get the Files // Clear the ListView. Note that we are not calling the Clear mehod on the // Items collection rather than on the ListView itself. //The clear method method of the ListView remove everthing, including column //headers, and we only want to remove the items from the view. this.lwFilesAndFolders.Items.Clear(); //Now we set the label with the current path this.lblCurrentPath.Text = root; // Now we better Lock the ListView for updates this.lwFilesAndFolders.BeginUpdate(); // Now let us Loop through all folders in the root and insert them foreach (System.IO.DirectoryInfo di in dirs) { // Create the main ListViewItem lvi = new ListViewItem(); lvi.Text = di.Name; // FolderName lvi.ImageIndex = 0; // The folder icon had index 0 lvi.Tag = di.FullName; // Set the tag to the qualified path of the folder
646
// Create the two ListViewSubItems. lvsi = new ListViewItem.ListViewSubItem(); lvsi.Text = ""; //Size - a folder has no size so this column is empty lvi.SubItems.Add(lvsi); // Adding the sub item to the LsitViewItem lvsi = new ListViewItem.ListViewSubItem(); lvsi.Text = di.LastAccessTime.ToString(); // Last accessed Column lvi.SubItems.Add(lvsi); //Add the sub item to the ListView this.lwFilesAndFolders.Items.Add(lvi); } // Now we Loop through all files in the root folder foreach (System.IO.FileInfo fi in files) { // Create the main ListViewItem lvi = new ListViewItem(); lvi.Text = fi.Name; // Filename lvi.ImageIndex = 1; // The icon we use to represent a folder has index 1 lvi.Tag = fi.FullName; // Set the tag to the qualified path of the file //Create the two sub items lvsi = new ListViewItem.ListViewSubItem(); lvsi.Text = fi.Length.ToString(); // length of the file lvi.SubItems.Add(lvsi); //Add to the SubItems Collection // Add the item to the Items collection of the ListView this.lwFilesAndFolders.Items.Add(lvi); } //Unlock the ListView. The item that have been inserted will now be displayed this.lwFilesAndFolders.EndUpdate(); } catch (System.Exception err) { MessageBox.Show("Error:", "EaglesGroup" + err.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
647
Before the first of the two foreach blocks we call BeginUpdate () on the ListView Control. Remember that the BeginUpdate () method on the ListView signals that ListView Control to stop updating its visible area until EndUpdate () is called. If we did not call this method, filling the list view would be slower and the list may flicker as the items are added. Just after the second foreach block we call EndUpdate (), which makes the ListView control draw the items weve filled it with. The two foreach blocks contains the code we are interested in. we start by creating a new instance of a ListViewItem and then setting the Text property to the name of the file or folder we are going to insert. The ImageIndex of the ListViewItem refers to the index of an item in one of the ImageLists. We use the Tag property to save the fully qualified path to both folders and files, for use when the user double clicks the item. Then, we create the two sub items. These are simply assigned the text to display and then added to the SubItems collection of the ListViewItem. Finally, the ListViewItem is added to the Items collection to the ListView. The ListView is smart enough to simply ignore the sub items, if the view mode is anything but Details, so we add the sub items no matter what the view mode is now. Note that there are some aspects of the code we havent discussed here - namely the lines that actually obtain information about the files: // Get information about the root folder. System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(root); // Reterive the files and folders form the root folder. DirectoryInfo[] dirs = dir.GetDirectories(); // This is for Folders/ FileInfo[] files = dir.GetFiles(); // This is for to get the Files
These lines use classes from the System.IO namespace for accessing files, so we need to add the following using directive to the top of our code: Which you need to do the following:using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; 648
All Rights Reserved To EaglesGroup
Well talk more about file access and System.IO later, but to give you an idea of whats going on, the GetDirectories () method of the DirectoryInfo object returns a collection of object that represent the folders in the directory were looking in , and the GetFiles () method return a collection of objects that represent the files in the current directory. We can loop through these collections, as we do in the code above, using the objects Name property to return the name of the relevant directory or file, and create a ListViewItem to hold this string. All that remains to be done for the list view to display the root folder is to call the functions in the constructor of the form. At the same time we instantiate the folderCol StringCollection with the root folder: public Form1() { InitializeComponent(); // init ListView and folder collection folderCol = new System.Collections.Specialized.StringCollection(); CreateHeadersAndFileListView(); PaintListView(@"C:\"); folderCol.Add(@"C:\"); } In order to allow the user to double click an item in the ListView to browse the folders, we need to subscribe to the ItemActivate event. We add the subscription to the constructor:
649
The corresponding event handler looks like this: private void lwFilesAndFolders_ItemActive(object sender, System.EventArgs e) { // Cast the sendere to a ListView and get the tag of the first selected item System.Windows.Forms.ListView lw = (System.Windows.Forms.ListView)sender; string filename = lw.SelectedItems[0].Tag.ToString(); if (lw.SelectedItems[0].ImageIndex != 0) { try { //Attempt to run the file System.Diagnostics.Process.Start(filename); } catch { // If the attempt fails we simply exit the method return; } } else { // Insert the items PaintListView(filename); folderCol.Add(filename); } } The tag of the selected item contains the fully qualified path to the file or folder that was double clicked. We know that the image with index 0 is a folder, so we can determine whether the item is a file or a folder by looking at the index. If it is a file we attempt to load the file. If it is a folder, we call PaintListView () with the new folder and then the new folder to the folderCol collection. Before we move on to the radio buttons well complete the browsing ability by adding the click event to the Back button. Double click the button and fill the event handle with this code:
650
private void btnBack_Click(object sender, EventArgs e) { if (folderCol.Count > 1) { PaintListView(folderCol[folderCol.Count - 2].ToString()); folderCol.RemoveAt(folderCol.Count - 1); } else { . PaintListView(folderCol[0].ToString()); } If there is more than one item in the folderCol collection them we are not at the root of the browser, and we call PaintListView () with the path to the previous folder. The last item in the folderCol collection is the current folder, which is why we need to take the second to last item. We them remove the last item in the collection, and make the new last item the current colder. If there is only one item ion the collection we simple call PaintListView () with that item. All that remains is to able to change the view type of the list view. Double clicks each of the radio buttons and add the following code: private void rdoLargeIcon_CheckedChanged(object sender, EventArgs e) { RadioButton rdb = (RadioButton ) sender ; if (rdb.Checked ) this.lwFilesAndFolders.View = View.LargeIcon ; }
private void rdoSmallIcon_CheckedChanged(object sender, EventArgs e) { RadioButton siddhu = (RadioButton)sender; if (siddhu.Checked) this.lwFilesAndFolders.View = View.List; }
651
private void rdoList_CheckedChanged(object sender, EventArgs e) { RadioButton rdb = (RadioButton)sender; if (rdb.Checked) this.lwFilesAndFolders.View = View.List; }
private void rdoDetails_CheckedChanged(object sender, EventArgs e) { RadioButton rdb = (RadioButton ) sender ; if (rdb.Checked ) this.lwFilesAndFolders.View = View.Details ; } We check the radio button to see if it has been changes to Checked if it has we set the View property of the ListView accordingly. That concludes the ListView example. When you run it, you should see something like this:
652
The above picture shows the status bar as it looks in Word. The panels in the status bar can be identified as the section that appears sunken. DENOTE: Now we will be seeing the Adding item to Toolbox For some reasons. In 2005.NET version the Status bar control is not there so we follow the steps below Enjoy Programming.
653
Second Step:-
After the dialog appears select the StatusBar and the click ok to exit the dialog and see in the toolbox. Third Step:
654
Description It is possible to assign an image to the status bar that will be drawn in the background. This is the collection of panels in the status bar. Use this collection to add and remove panels. If you want to display, this property must be set to true. When you are not using panels this property holds the text that is displayed in the status bar. Obtains a Status bars docking behavior Obtains the font for the Status bar.
655
There are not a whole lot of nee events for the status bar, but if you are drawing a panel manually, the DrawItem event is of crucial importance. Name DrawItem Description Occurs when a panel that has the OwnerDraw style set needs to be redrawn. You must subscribe to this event if you want to draw the contents of a panel yourself. Occurs when the panel is clicked. It occurs when the value of the ImeMode property has been edited.
PanelClick ImeModeChanged
656
5. Click Add to add a panel to the collection. Set the AutoSize property to Spring. This means that the panel will share the space in the StatusBar with other panels. 6. Click Add again, and change the AutoSize property to Contents. This means that the panel will resize itself to the size of the text it contains. Set the MiniSize property to 0. 7. Click OK to close the dialog. 8. Set the ShowPanles property on the StatusBar to true.
private void rdoSmallIcon_CheckedChanged(object sender, EventArgs e) { RadioButton siddhu = (RadioButton)sender; if (siddhu.Checked) { this.lwFilesAndFolders.View = View.SmallIcon; this.sbInfo.Panels[1].Text = "Small Icon"; } }
657
private void rdoList_CheckedChanged(object sender, EventArgs e) { RadioButton rdb = (RadioButton)sender; if (rdb.Checked) { this.lwFilesAndFolders.View = View.List; this.sbInfo.Panels[1].Text = "List"; } }
private void rdoDetails_CheckedChanged(object sender, EventArgs e) { RadioButton rdb = (RadioButton)sender; if (rdb.Checked) { this.lwFilesAndFolders.View = View.Details; this.sbInfo.Panels[1].Text = "Details"; } } The panel text is set in exactly the same way as in PaintListView above. That concludes the StatusBar example. If you run it now, you should see something like this:
658
659
The above screenshot shows the Options dialog in Microsoft Word 2003 as it is typically configured. Notice the two rows of tabs at the top of the dialog. Clicking each of them will show a different selection of controls in the rest of the dialog. This is a very good example of how to use a tab control to group related information together, making it easier for the user to find the information she or her is looking for. Using the tab control is easy. You simply add the number of tabs you want to display to the controls collection of TabPage objects and then drag the controls you want to display to the respective pages.
660
Multiline RowCount SelectedIndex TabCount TabPages Image List DispalyRectange ShowToolTips SelectedTab
661
662
5. Add another tab page to control by clicking Add. 6. Change the Text property of the tab pages to Tab One and Tab two respectively, and click OK to close the dialog. 7. You can select the tab pages to work on by clicking on the tabs at the top of the control. Select the tab with the text Tab One. Drag a button on the control. Be sure to place the button within the frame of the TabControl. If you place it outside then the button will be placed on the form rather than on the control. 8. Change the name of the button to btnShowMessage and the text of the button to Show Message. 9. Click on the tab with the Text property Tab Two. Drag a TextBox control onto the TabControl surface. Name this control txtMessage and clear the Text property. 10. The two tabs should be look like these two screenshots:
663
664
You access a control on a tab just you would any other control on the form. We get the Text property of the TextBox and display it in a message box. Earlier in the chapter, we saw that it is only possible to have one radio button selected at a time on a form (unless you put them in group boxes). The TabPages work is precisely the same way as group boxes and it is therefore possible to have multiple sets of radio buttons on different tabs without the need to have group boxes. The last thing you must know to be able to work with a tab control is how to determine which tab is currently being displayed. There are two properties you can use for this purpose: SelectedTab and SelectedIndex. As the names imply, SelectedIndex will return the index of the tab or 1 if no tab is selected.
Summary
In this chapter we visited some of the most commonly used controls when we creating Windows Application and saw how they can be used to create a simple, yet powerful user interface. We discussed the properties and events of these controls, with examples of their use, and looked at how to add event handlers for the particular events of a control. The controls discussed in this chapter were:
Label Button RadioButton CheckBox ListBox ListView GroupBox RichTextBox StatusBar ImageList TabControl
In the next chapter, we will be looking at more complex control, and more advanced controls.
665
Chapter 16
666
As a developer, you generally think of the application as the set of objects that converse and work together to implement the functionality of the system. To user, however, the application is generally perceived as the GUI elements that allow them to interact with that functionality. User is less impressed by the way data is stored on the persistent storage device. Since they are accustomed with this style of storage, the system allows them to find and sort the data. The way in which data is presented is generally the way in which the program is thought about, when it is used or reviewed. For this reason, you should strongly consider the GUI elements when you are writing applications. Too often, developers think more in terms of features and less in terms of how the pieces of an overall application flow together. By using the .NET base class library visual and other elements properly, you wont has this problem in your applications.
When we talk about Visual Elements, we are generally talking about two specific concepts elements appear directly on Windows Forms, and elements are visible to users. This combination is important because many elements in the .NET base class library are available to you as a developer to use directly on a form without being directly visible to users. Elements in the .NET base class library and its extensions break down into three general categories, which we look at in this chapter:
In the previous chapter we looked at some of the most common control used in Windows Application development. With controls such as these it is possible to create impressive dialogs, but very few full scale Windows applications have a user interface consisting solely of a single dialog. Rather, these applications use a Single Document Interface (SDI), or a Multiple Document Interface (MDI). Applications of either of these types usually make heavy use of menus and toolbars, neither of which we discussed in the previous chapter, but well make compensation for that now. We will start this chapter as we left of the previous one, by looking at controls, starting with the menu controls and then moving on to toolbars, where well see how to link buttons on toolbars to specific menu items and vice versa. Then well move on to creating SDI and MDI applications, with the focus on MDI applications, as SDI applications are basically subsets of MDI applications.
667
So far weve only consumed controls that ship with the .NET Framework. These controls are, ad weve seen, very powerful and provide a wide range of functionality, but there are times where they are not sufficient. To overcome this, it is possible to create custom controls, and well look at how that is done towards the end of this chapter.
General Components The general components that the .NET base class library supports and that you can place directly on your forms this category, the largest by far, occupies most of this chapter. Set of user defined components The .NET base class library and C# permit you to create your own components this process. These components can be either visual elements written from scratch to perform a specific action or extensions to the existing .NET base class library components such as owner drawn components. Other components in the visual spectrum The examples are Standardized dialog boxes, Tool tips, and Printing support.
16.3 Menus
How many Windows applications can you think of that do not contain a menu of some kind? The chances are that the number is very close to none. Menus are therefore likely to be important part of any applications you will write for the Windows Operating System. To assist us in creating menus for our applications, Visual Studio .NET provides us with that lets us create simple menus quickly, and more refined with a little more work.
on an item, and will typically display information relevant to that item. Technically there is a third menu type, named MenuItem, which is also derived fro the Menu Class. A MenuItem represents the individual items displayed in a menu. In the picture below, the Type Here field represents a MenuItem. The MenuItem will be discussed in detail shortly. ContextMenuStrip and MenuItem are also derived from the base class Menu.
When you drag the MenuStrip control from the Toolbox to the design surface you will see that this control places itself both on the form itself and in the control tray, but can be edited directly on the form. To create new menu items you simply place the pointer in the box marked Type Here as shown in the following picture:
669
Type the caption of the menu in the highlighted box, including an ampersand (&) in front of the letter you want to function as the mnemonic character for the menu item this is the character that appears underlined in the menus item and which can be selected pressing Alt and the key together.
670
DENOTE: That it is quite possible create several menu items in the same menu with the same mnemonic character. The rule, is that a character can be used only once for each pop up menu (Rules are meant to Broken, but this rule is cannot broken as Microsoft decide to do that so on). For example in the Files pop up menu, once in the View menu etc. if you accidentally assign the same mnemonic character to multiple menu items in the same pop up menu, you ll find that only the one closest to the top of the control will respond to the character.
To create a separator in the menu, you simple type a single dash (-) as the text. DENOTE: That you cannot do this for top level menu items, only for submenus items, which we will come to very shortly.
When you click in the highlighted box, you will notice that the properties displayed in the Properties window changed. This is because the majority of the properties that can be used with menus are used with respect to the individual menu items.
Description By setting this value to true, you specify that the menu should appear on a new line. Using this property you can create menus with multiple top level rows. Submenu items with this property set will be placed in a new column. This property is not visible in the Properties Window.
671
Mnemonic
Owner Draw
Indicates whether the menu is checked. A default item is drawn with boldface. If a user doubles click a MenuItem that contains sub items, and one of these items is a default item that item is selected. An item with Enabled set to false will be graved and cannot be selected. Indicates whether the menu will be populated with a list of the child windows in an MDI. This property indicates where a menu will be positioned when it is merged with another menu. Well look at menu merging when we discuss MDI applications later in this chapter. This property returns the mnemonic character that is associated with the MenuStrip Item. The mnemonic character is the first character following an ampersand (&). This property is not visible in the Properties windows. If you set this property to true, you take responsibility for all drawing of the MenuItem. If you want to add images to your menus, you must set this property to true and implement handlers for the items Drawn Item and Measure Item events. If this property is set to true, a check is displayed as radio button rather than a check mark. The shortcut is key combination which access the menu item directly for example, Ctrl + Shift + B for build function in the Visual Studio .NET Environment Setting this property to true means that the shortcut text is displayed in the Menu Item. The text of the MenuStrip item. Include an ampersand (&) before a character in the string to assign the mnemonic character.
How many events are needed for a MenuItem? One you would think the Click event. In fact there are five events of interest you can subscribe to , two of which you must use if you drawing the items yourself. Lets look at the events now, and then move on to an example using this control. Name Click () Description This event occurs when a user clicks a menu item. You can also raise this event manually by calling the Perform Click () method of the MenuItem. Occurs when the MenuItem need to be drawn. If you set the Owner Draw property to true, you must handle this event. Occurs before a MenuItem is drawn. If you are drawing the Menu Item yourself, you should calculate and return the width and height for the item in this event. Occurs when the MenuStrip item list of sub items is displayed. You can use this event to perform validation of the availability of the items and set their state appropriately. Occurs when a user places the mouse pointer over the item or when he or she changes the focus using the keyboard.
Draw Item()
Measure Item()
Popup ()
Select ()
673
In Visual Studio.NET, you can create a context menu strip by dragging it onto the form and adding items to it, in exactly the same way as you would a MainMenu control. The only difference is that you cannot have any top level items in a context menu. To bind the context menu to a particular control on the form, you select the control and sets its ContextMenu property to point to the context menu youve created. We are now ready to create an example using the menus. Well keep this example basic as well see more advanced example of menus as we discus MDI application. Well create one main menu and a context menu strip in this example: Now lets try it by examples:
Example Try it out Eagles Usingmenus Step by Step Example: Using Version 2005
1. Create a new Windows application called Eagles Usingmenu in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using Menu. 2. Add a MenuStrip control and a ContextMenuStrip control to the form by selecting it from the toolbox (menu and toolbars). Name the controls as MainMenuFiles and ContextMenuFonts respectively. 3. Add the following items to the MenuStrip control by selecting it and typing the text into the menu items. When you type text in the menu item using the designer, you are setting the Text property of the item. After setting the text for an item, use the Properties window to change the default name chosen by Visual Studio .NET. The menu names MenuItemFiles is know as top level menu. Remember that you create a separator by typing a single dash in the menu and create a mnemonic characters by adding an ampersand (&) in front of the letter you wish to choose: Name Text &Files &New &Open &Save E&xit
4. Now select the contextmenustrip, and create the following menu item just as you did above. Name menuItemBold menuItemItalic Text &Bold &Italic
674
menuItemUnderline
&Underline
5. Now add a single RichTextBox control to the form. Name it as rtfText and set its Dock property to fill to make it fill the entire form, and clear its Text Property. 6. Select the RichTextBox control and select the ContextMenu property. From the drop down list, select ContextMenuFonts to bind the contextmenustrip to rich text box.
I Hope you should now have a form that looks something like this:
7. Now Run the Application and you will see a window some and try to type and use the menu items and you should see something like this:
675
Now lets add the Program Code Adding the Event handlers
We are now ready to add code to our menus. Well keep the Open, Save, and New methods simple, and well use a fixed file for the demonstration in the next chapter well look at using the common dialogs that allows the user to select a file to open or save. To add a handler for the Click event of a menu item, you simply double click it, as for buttons and other controls. We will add handlers for the New, Open, Save, and Exit menu items. Clicking on a separator is not possible and noting should be done when the user clicks the files menu, so theres not need to add click event handlers to this menu item. Now we are almost entering the coding part by just double clicking the new menu item: private void menuItemNew_Click_1(object sender, EventArgs e) { this.rtfText.Clear(); }
676
We said wed keep this simple, and we did. The sender parameter is a reference to the menu item that was clicked. In this case we know that it was the New item, but an event handler can be assigned to many items, in which case this identifies the menu to be used. Now Repeat the steps with the Open, Save, and Exit, and the code as follows: private void menuItemOpen_Click_1(object sender, EventArgs e) { // Now we are Loading the file fomr the computer try { this.rtfText.LoadFile("../../eagles.rtf"); } catch (System.Exception err) { MessageBox.Show("Error While Loading", "EaglesGroup", MessageBoxButtons.OK, MessageBoxIcon.Error); }
private void menuItemSave_Click_1(object sender, EventArgs e) } { // Saving the File try { this.rtfText.SaveFile("../../eagles.rtf"); } catch (System.Exception err) { MessageBox.Show("Error While Saving the File", "EaglesGroup", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void menuItemExit_Click_1(object sender, EventArgs e) { // Exit all the application Application.Exit(); }
677
The LoadFile () method of the RichtTextBox class does exactly that it loads the contents of an RTF as can be exported from WordPad or Word, or ASCII file into the rich text box. Note that we have put error handling in here to deal with situations where the text file does not exist. However, there is another way of archiving this check, which we will look at now: The EaglesMenuItemFiles item contains the other items in our main menu. Because of that, every time the menu item is asked to show its members, it dispatches a Popup event. If we subscribe to that event, we can check if the file exists and disable the Open menu item if it doesnt. Well subscribe to the event by selecting the eaglesmenuitemfiles control, and double clicking on the Popup event in the Events list in the Properties window.
678
Then we just add the code to the event handler itself: private void EaglesMenuItemFiles_Popup(object sender, System.EventArgs siddhu) { // The follwoing Code will check wether the file exist by setting the Enabled property to the return value of the File.Exist method this.EaglesMenuItemFiles.Enabled = System.IO.File.Exists("../../eagles.rtf"); } The static method Exists of the File class returns a Boolean which is true if the file exists and false otherwise which is exactly what we want the Open menu item to reflect, so we simply set the value of the Enabled property to the return value of this function.
We are now with the main menu and can move on to the context menu. We add the Click events just as we did in the main menu by double clicking the items and adding the following code:
private void menuItemBold_Click(object sender, EventArgs e) { Font newFont = new Font(rtfText.SelectionFont, (rtfText.SelectionFont.Bold ? rtfText.SelectionFont.Style & ~FontStyle.Bold : rtfText.SelectionFont.Style | FontStyle.Bold)); rtfText.SelectionFont = newFont; } private void menuItemItalic_Click(object sender, EventArgs e) { Font newFont = new Font(rtfText.SelectionFont, (rtfText.SelectionFont.Italic ? rtfText.SelectionFont.Style & ~FontStyle.Italic : rtfText.SelectionFont.Style | FontStyle.Italic)); rtfText.SelectionFont = newFont; } private void menuItemUndeline_Click(object sender, EventArgs e) { Font newFont = new Font(rtfText.SelectionFont, (rtfText.SelectionFont.Underline ? rtfText.SelectionFont.Style & ~FontStyle.Underline : rtfText.SelectionFont.Style | FontStyle.Underline)); rtfText.SelectionFont = newFont; }
679
Now lets see how the above code works: In each of the three functions we create a new font from the one that is currently being used by the selection in the rich text box. If the style of the font is already set, we remove it form the new font, otherwise we include the style in the font. We then set the font of the selection to the new font. The single line that creates the object can look a bit daunting so well explain it here. To create the objects we make use of the ternary operate we first saw this in earlier chapter. Lets look at the code form the menuItemBold_Click method (): private void menuItemBold_Click(object sender, EventArgs e) { Font newFont = new Font(rtfText.SelectionFont, (rtfText.SelectionFont.Bold ? rtfText.SelectionFont.Style & ~FontStyle.Bold : rtfText.SelectionFont.Style | FontStyle.Bold)); rtfText.SelectionFont = newFont; } On the second line of the first statement, we examine whether the Bold property of the selected font is true. If it is, then we must create a new style for the font we are creating, which retains all the styles that are currently set except for the bold style, which is the code between the ? And the: on the third line. On the fourth line of the statement, after the colon, this code is run if the value of the Bold property is false, whereby we ad in the bold style rather than remove it. Finally the entire sequence of events just discusses is wrapped in parentheses, often used to separate out the ternary operator logic from other code and aid readability.
This concludes the first example of MenuStrip and the Context menu.
16.8 ToolStripMenu
While menus are great for providing access to multitude of functionality in your application, some items benefit being placed in a toolbars/toolstrip as well as on the menu. These items are those that are used frequently by the user, such as Open and Save, and a toolbar provides one click access to such commonly used functionality.
680
The following screenshot has been taken from the Microsoft Word.
A button on the toolbar usually contains a picture and no text, though it is possible to have buttons with both. Examples, with no text are those found in Word as see above in the screenshot that includes text can be found in Internet Explorer and as well as in the Visual Studio .NET Environment. If you let the mouse pointer rest above a button in a toolbar, it should display a tooltip that provides some clue as the purpose of the button, especially when only an icon is displayed. Unlike the menu controls weve just discussed the ToolStripMenu control is not merely a container for other objects. You can set several properties on the control itself, such as where it is positioned on the screen. All the buttons on the toolstrip menu object and they hold the information about which image to display, the style of any text displayed with the icon, and tooltips.
In the version 2005 .NET the toolstrip menu has more feature than compare to the version 2003 .NET. Well start describing the properties and event of the ToolStripMenu control and then move on to the ToolBarButton.
Name Appearance
AutoSize
Description This property controls the appearance of all the buttons contained within the control. You can set this property to Flat or to Normal. The normal setting will draw a 3D border around the button. Setting this property to false allows you to change the size of the control. The default, true, allows the control to size itself to make room for images and text.
681
Returns the collection of buttons contained in the control This property controls the size of the buttons. If the AutoSize property is true this property has no effect. If this property is set to true, the control will draw a border at the top of the ToolBar control If you have toolbar buttons that provide a drop down list, this property determines whether an arrow is drawn to the right of the button. The image list from which the images used on the buttons contained in the control are taken. Setting this property to true will make the control display tooltips for each button contained in the control. If this property is true, and the toolbar is too long to display all the buttons it contains in one line, it will wrap to the next line.
Button DropDown
682
Click DisplayStyleChanged Double Click Drag Drop Drag Enter Drag Leave Drag over Mouse Down Mouse Enter Mouse Hover Mouse Leave Mouse Move Mouse Up Paint QueryAccessibilityHelp QueryContinueDrag
thus which action to take. It occurs when the ToolStripItem is clicked It occurs when the Display Style has changed It occurs when the item is double clicked with the mouse. It occurs when the user drags an item and user releases the mouse button, indicating that the item should be dropped into this item. It occurs when the user drags an item into the client area of this item It occurs when the user drags an item and the mouse pointer is no longer over the client area of this item. It occurs when the user drags an item over the client area of this item. It occurs when the mouse pointer is over the item and a mouse button is pressed It occurs the mouse pointer enter the item. It occurs when the mouse pointer over the item, It occurs when the mouse pointer leaves the item. It occurs when the mouse pointer is moved over the item. It occurs when the mouse pointer is over the item and a mouse button is released. It occurs when the item is redrawn It occurs when a accessibility client application invokes help for the ToolStripItem It occurs during a drag and drop operation and allows the drag source to determine whether the drag and drop operation should be canceled.
Name DropDownMenu
683
Enabled
Pushed
Style
MenuItem to the button. If the Style property of the button is DropDownButton the MenuItem will be displayed when the user clicks the button. By setting this property to false you make the button unavailable to the user. If you are using bitmap images on the button, then the button is only able to draw the image in monochrome. The index of the image to use. The image list is assigned to the ToolStrip control. You can use this property when the style of the toolstrip button is set to ToggleButton. Setting this property to true will make the button appear grayed. Unlike setting the Enable property to false, this setting cause the entire button face to become hazed. If the style of the ToolStrip button is ToggleButton then the setting this property to true will make the button appear pressed. There are four different style that can be used: Push Button: Appears like a normal button Toggle Button: When this style is selected the button can appear to be pressed and will remain in the state until pressed again. An example of such a button is the Bold button on the toolstrip used in Microsoft Word Separator: A button with this style is not drawn which is exactly the point; it creates a small space between buttons. DropDownButton: A button with this style can be assigned a ContextMenu. This menu will be dropped down when the user clicks the button. Combo Box : This will display the Combo box in the ToolStrip Label: This style will help to hold the Information about what the
684
Text ToolTipText
user has given in the Label as in Text Property. Progress Bar: The is a new feature Style which can be make available to display in the ToolStrip it self. The text to display in the toolstrip button The tooltip text of the button.
The following table will show you the public properties of the ToolStripItem objects Name Anchor Description It obtains or sets the edges of the container to which a ToolStripItem is bound and determines how a ToolStripItem is resized with its parent. It obtains or sets a value indicating whether to use the Text property or the ToolTipText property for the ToolStripItem ToolTip It obtains or sets a value indicating whether the ToolStripItem should be placed on a ToolStrip It obtains or sets the background color for the item. It obtains or sets the background image layout used for the ToolStripItem. It gets the size and location of the item. It gets a value indicating whether the item can be selected. It gets the area where content, such as text and icons, can be placed within a ToolStripItem without overwriting background borders. It obtains or sets whether text and images are displayed on a ToolStripItem It obtains or sets which ToolStripItem borders are docked to its parent control and determines how a ToolStripItem is resized with its parent. It obtains or sets a value indicating whether the ToolStripItem can be activated by double clicking the mouse It Obtains or sets a value indicating whether the parent control of the
Auto ToolTip
Available Back Color Background Images Layout Bounds Can Select Content Rectangle
685
Font Fore Color Height Image Image Align Image Index Image Key Image Scaling Image Transparent Color IsDisposed IsOnDropDown IsOnOverflow Margin Merge Action Merge Index Overflow
ToolStripItem is enabled. It Sets or obtains the font of the text displayed by the item. It obtains or sets the foreground color of the item. It obtains or sets the height, in pixels, of a ToolStripItem. It obtains or sets the image that is displayed on a ToolStripItem. It obtains or sets the alignment of the image on a ToolStripItem. Obtains or sets the index value of the image that is displayed on the item. It obtains or sets the key accessor for the image in the ImageList that is displayed on a ToolStripItem. It obtains or sets a value indicating whether an image on a ToolStripItem is automatically resized to fit in a container. It obtains or sets the color to treat as transparent in a ToolStripItem Image It gets a value indicating whether the object has been disposed of. It gets a value indicating whether the container of the current Control is a ToolStripDropDown. It gets a value indicating whether the Placement property is set to Overflow. It Obtains or sets the space between the item and adjustment items. It obtains or sets how child menus are merged with parent menus. It obtains or sets the position of a merged item within the current ToolStrip It obtains or sets the whether the item is attached to the ToolStrip or ToolStripOverFlowButton or can float between the two. It obtains or sets the owner of this item. It gets the parent ToolStrip of this ToolStripItem. It obtains or sets the internal spacing, in pixel, between the items contents and its edges It gets the current layout of the item.
686
RightToLeft
Right To LeftAutoMirrorImage Selected Size Tag Text Text Align Text Direction TextImageRelation ToolTipText Visible Width DoDragDrop Get Current Parent GetPreferredSize Invalidate Perform Click Select Tab Stop Stretch
It obtains or sets a value indicating whether items are to be placed from right to left and text is to be written form right to left. Its a mirrors automatically the ToolStripItem image when the RightToLeft property is set to YES. It gets a value indicating weather the item is selected It obtains or sets the size of the item. It obtains or sets the text that is to be displayed on the item. It obtains or sets the text that is to be displayed on the item. It obtains or sets alignment of the text on a ToolStripLabel. It gets the orientation of text used on a ToolStripItem. It obtains or sets the position of ToolStripItem text and image relative to each other. It obtains or sets the text that appears as a ToolTip for a control It obtains or sets a value indicating whether the item is displayed. It obtains or sets the width in pixel of a ToolStripItem. It begins a drag and drop operation It gets or retrieves the ToolStrip that is the container of the current ToolStripItem. It retrieves the size of a rectangular area into which a control cab be fitted. Invalidates some or all of the surface of the control and causes the control to be redrawn It activates the ToolStripItem when it is clicked with the mouse. It selects the item. It obtains or sets a value indicating whether the user can give the focus to an item in the ToolStrip using the TAB key. It obtains or sets a value indicating whether the ToolStrip stretches from end to end in the ToolStripContainer.
687
ShowItemToolTips
It obtains or sets a value indicating whether the ToolTips are to be displayed on the ToolStrip
16.22 Creating Tool Strips Just double click or drag and drop the toolstrip control to the Windows Forms, you can dock it on any edge you like by default, the dock property is set to Top, but you can set it to Bottom, Left, Right, Fill, or whatever you prefer. To actually add the items to a tool strip at design time, click the Items property at the design time, which opens the Items Collection Editor you can see in the following picture. You can add items to the tool strip as with the other editors weve see just select the type of item you want to add from the list before Add button and click the Add button to add a new button to the ToolStrip, and remove the button with a cross mark to removes a button. You can also set the text in an item with the Text property in the Item Collection Editor, an image from application resources or directly from a file to use for an item with the Image property, and the style of the button with the DisplayStyle property and TextImageRelation properties to specify the arrangement of text and image on the items where they are applicable. You can add one of these items to a tool strip from the item editor: ToolStripButton It is normal push button ToolStripLabel It non - selectable ToolStripItem that renders text and images and the display hyperlinks. ToolsStripSeparator It is a small space between other buttons used to space and group buttons. ToolsStripComboBox It is a ToolStripComboBox that is properly, rendered in a ToolStrip ToolStripTextButton It is a combination of a standard button on the left and a drop down button on the right. ToolStripSpitButton It is a combination of a standard button on the left and a drop down button on the right. ToolStripDropDownButton It is a button that can display a drop down menu. We will be adding a few of these types of items to the ToolStrip in the ToolStrip example on the chapter.
688
Handling Tool Strip Button Clicks When a button item in a tool strip is clicked, the tool strip items Click event happens. You can simply double click an item to generate an skeleton handler for the event much like you do for standard buttons and then put the code there you want to get executed on the click event. Heres how that works in the ToolStrip example on the Program where we reporting that the text of the clicked button in a message box. private void toolStripButton1_Click(object sender, EventArgs e) { MessageBox.Show("You Have clicked me " + sender.ToString(), "EaglesGroup"); } 16.23 Drop- Down and Split Buttons Drop down and split buttons are one of the most useful styles of ToolStrip buttons, these buttons can display a drop down menu if you click their down arrow. The only difference between a drop down and a split button is that a drop down only displays a drop down menu, whereas a split button can display a drop down menu as well as work as a push as push button if you click the button itself, instead of the down arrow that appears at their end. You can add menus items to these buttons in the form editor much like you would do in a menu strip case. Another way to add a menu to a Drop Down button is to create a context menu strip, and assign that menu to the buttons DropDown property. To see how this works, take a look at the ToolStrip example on the CD which is made available with this book. Weve added three menu items, they are Red, Blue, and Green, to drop down menu and implemented the event handler for these items like this:
689
private void redToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show("You Have Clicked " + sender.ToString(), "EaglesGroup"); } private void greenToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show("You Have Clicked " + sender.ToString(), "EaglesGroup"); } private void blueToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show("You Have Clicked" + sender.ToString(), "EaglesGroup"); } DENOTE: You can also add buttons to the drop down or split buttons with the Items Collection Editor, which you open with the DropDownItems Property in the Properties Window. Thats all it takes, you can see the active drop down button in the below picture.
690
Typically, ToolStrip buttons correspond to frequently used menu items. To connect a ToolStrip to a menu item, you can use that menu items Perform Click method to make it seem as though the item itself was clicked. private void toolStripDropDownButton1_Click(object sender, EventArgs e) { pickColorToolStripMenuItem.PerformClick(); }
16.25 Creating ToolStrip Image Buttons To Display images in ToolStrip button, you only need to set the Image property of the button in the Items Collection Editor to the image you want to use. Adding Combo boxes and Other Control to ToolStrip One of the common non button controls you see in ToolStrip is the Combo box control, which lets the user select an item from a list, or type their own entry. In the previous version of the Visual Studio Version 2002 and Version 2003, it was difficult to add the combo box or such controls to Toolbars, but now in the Visual Studio 2005 and 2008 it is very easy to add these controls. You can add combo boxes, text boxes, and progress bars, right from the Items Editor. Thats what the example we are going to see and the example already in the CD also which is made available with this book. Weve added a few item to the combo box, like Times New Roman, Arial, and added this code to its SelectedIndexChanged event handler: private void toolStripComboBox1_Click(object sender, EventArgs e) { MessageBox.Show("Selected item text: " + toolStripComboBox1.SelectedIndex.ToString() ,"EaglesGroup"); }
Adding Buttons to a ToolStrip at Run Time As you might except, you can add buttons to ToolStrip at the run time. To do that, just double - click the Click To Add Button, and enter the following code:
691
private void button1_Click(object sender, EventArgs e) { eagles1.Size = new System.Drawing.Size(75, 23); eagles1.Name = "ToolStripButton1"; eagles1.Text = "new button"; this.EaglesToolStrip .Items.Add(this.eagles1); }
16.26 Tool Strip Containers You see in software like Microsoft Word or Outlook, that you can dock and move the menus and tools strips around and place them wherever you feel like, you can get the same functionality in you application with a control called tool strip container. For this just drag and drop the ToolStripContainer and make it dock fill so that you can make your ToolStrip or even the MenuStrip any where you can like in the Window for this you can see the Example in the CD named EaglesVisualCSharp\Chapter 16\Example Using ToolStrip\Eagles Using ContentPanel
Example Try it out Eagles UsingToolStrip Step by Step Example: Using Version 2005
1. Create a new Windows application called Eagles UsingToolStrip in the directory C:\EaglesVisualCSharp\Chapter 16 2. Add a ToolStrip control to the form by double click the controls in the Toolbox (Menu & Containers). Name the control toolFonts. 3. Go the item properties of the ToolStrip and add three buttons and one DropDown button where you can see something like this picture below:
692
4. Now add RichTextBox, ContextMenu and name its Design Name Properties as rtfText and for the ContextMenu as ContextMenuFont, and change the Anchor property of the RichTextBox to Left, Top, Right, Bottom, and the Dock property to None. 5. Now add the three MenuItem to the ContextMenuFonts control and set the properties as follows:
Bodoni MT
6. Add the MenuStrip and set the text property of item as follows and as well as the Design Name properties also, and change the Design Name properties of the MenuStrip to EaglesMenuItemFiles. Remember that you create a separator by typing a single dash in the menu and create a mnemonic character by adding an ampersand (&) in front of the letter you wish to choose: Name MenuItemFiles Text &Files
693
7. Now add the Images to the ToolStrip control by click the items properties and click the ellipse (..) symbol and you see the Items Collection Editor and add the four buttons and set the properties as follows: Name toolStripButton1 Text
Design Name = toolBold Display Style = Image Text = null Image = refer the path below this table Design Name = toolItalic Display Style = Image Text = null Image = refer the path below this table Design Name = toolUnderline Display Style = Image Text = null Image = refer the path below this table Design Name = toolFontFamiles Display Style = Image Text = null Image = refer the path below this table Drop Down = ContextMenuFonts
toolStripButton2
toolStripButton3
toolStripDropDownButton1
Images click the Ellipse (...) symbol and go to the following path <DRIVE: \Program Files\Microsoft Visual Studio 8 \ Common7 \ Graphics \ bitmaps \ Tlbr_W95. The Names are BLD.bmp, ITl.bmp, and UNDRLN.bmp And For the last final item you create an image A.bmp or you can download form the Internet. For this image I create image and it already available in the CD with this book so you can find the Image in the CD named as Font.bmp.
All Rights Reserved To EaglesGroup
694
Now lets add the Program Code Adding the Event handlers
1. Begin by double clicking the New Menu item: private void menuItemNew_Click(object sender, EventArgs e) { this.rtfText.Clear(); this.Text = "New Eagles"; }
695
2. Now double click the Open Menu Item and the add the following code: private void menuItemOpen_Click(object sender, EventArgs e) { try { this.rtfText.LoadFile("../../eagles.rtf"); this.Text = "eagles.rtf - Eagles"; } catch (System.Exception eagles) { MessageBox.Show("Error While Loading the File:\n" + eagles.Message, "EaglesGroup", MessageBoxButtons.OK, MessageBoxIcon.Error); this.Text = "New - Eagles"; } }
696
3. Enter the Code for the Save Menu Item as follows: private void menuItemSave_Click(object sender, EventArgs e) { try { this.rtfText.SaveFile("../../eagles.rtf"); this.Text = "eagles.rtf - Eagles"; } catch (System.Exception eagles) { MessageBox.Show("Error While saving file:\n", "EaglesGroup" + eagles.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); this.Text = "New - Eagles"; } }
4. Double click the Exit Menu Item and enter the following code: private void menuItemExit_Click(object sender, EventArgs e) { Application.Exit(); }
5. Now enter the code for the ContextMenuFont (menuItemstimes) as follows: private void menuItemstimes_Click(object sender, EventArgs e) { //Creating a new font with correct font family. Font newFont = new Font("Times New Roman", rtfText.SelectionFont.Size, rtfText.SelectionFont.Style); rtfText.SelectionFont = newFont; }
697
private void menuItemsMT_Click(object sender, EventArgs e) { Font newFont = new Font("Bodoni MT", rtfText.SelectionFont.Size, rtfText.SelectionFont.Style); rtfText.SelectionFont = newFont; }
7. Now we are going to enter code for the ToolStrip just double click the toolBold button and enter the following code: private void toolBold_Click(object sender, EventArgs e) { Font newFont; try { newFont = new Font(rtfText.SelectionFont, rtfText.SelectionFont.Style | FontStyle.Bold ); } catch (System.Exception err) { newFont = new Font(rtfText.SelectionFont, rtfText.SelectionFont.Style & ~FontStyle.Bold ); } rtfText.SelectionFont = newFont; }
698
8. The code for the toolItalic as follows: private void toolItalic_Click(object sender, EventArgs e) { Font newFont; try { newFont = new Font(rtfText.SelectionFont, rtfText.SelectionFont.Style | FontStyle.Italic ); } catch (System.Exception err) { newFont = new Font(rtfText.SelectionFont, rtfText.SelectionFont.Style & ~FontStyle.Italic ); } rtfText.SelectionFont = newFont; }
private void toolUnderline_Click(object sender, EventArgs e) { Font newFont; try { newFont = new Font (rtfText.SelectionFont ,rtfText.SelectionFont.Style | FontStyle.Underline ); } catch (System.Exception err) { newFont = new Font(rtfText.SelectionFont, rtfText.SelectionFont.Style & ~FontStyle.Underline); } rtfText.SelectionFont = newFont; }
699
10. When you run the application you should see the window like this:
16.27 SDI and MDI Applications Traditionally there are three kinds of application that can be programmed for Windows. These are follows: Dialog based application. These present themselves to the user as a single dialog from which all functionality can be reached. Single Document Interfaces (SDI). These present themselves to the user with a menu, one or more toolbars and one window in which the user can perform some task. Multiple Document Interface (MDI). These present themselves to the user in the same manner as an SDI does, but have the ability to hold multiple open windows at the time.
Dialog based applications are usually small single purpose applications that aim themselves at a specific task that needs a minimum of data entered by the user, or targets a very specific type of data. An example of such an application is the Microsoft Calculator, which comes with the Windows Operating System. Single Document Interface are usually aimed at solving one specific task, as they allow the user to load a single document into the application to be worked on. This task however, usually involves a lot of user interaction, and a very often the user will want the ability to save or load the result of his or her work. Good example of SDI applications is
700
Work Pad, Notepad, and Paint, which comes with the Windows Operating System and also the program which we used to work before Eagles UsingToolStrip.
However, only one document can be open at one time, so if a user wants to open a second document, a fresh instance of SDI application will be opened which will have no reference to the first instance and so any configuration you do one instance will not be carried over into the other. Thus in one instance of Notepad, you might have a messagebox when you try to open a new (without saving) that will ask you to save or no or cancel. if you press save the document will save or if you press no the notepad will close without saving so you might lose the data if you press the cancel it still remains and do nothing. Multiple Document Interface are very much the same as SDI application, except they are able to hold more than one document open in different windows at any given time. Example of MDI applications are Microsoft Word, Adobe Acrobat Reader.
701
A fourth type application was introduced with the Microsoft Office 2003. This type appears to be a cross between an SDI and MDI in that the windows presented to the user do not occupy the same area and each window shows up in the task bar. Essentially the application themselves are MSI applications because the main application will not shut down until all the windows are closed, and you can select which open document to view using the Windows menu item, but the user interface itself is presented as an SDI. In this following section we will focus on creating an MDI application and the tasks involved in doing so. The reason behind this is that any SDI application is basically a subset of an MDI, so if you are able to create an MDI you can also create an SDI. In fact in last section, we will create a simple SDI application that we will use to demonstrate using the using the Windows Common Dialogs.
16.28 Building MDI Applications What Is involved in Creating an MDI? First of all, the task you want to the user to be able to accomplish should be one where he or she would want to have multiple documents open at a time. A good example of this a text editor, or as in the screenshot above. Secondly, you should provide toolbars for the most commonly used tasks in the application, such as setting the font style, and loading and saving documents. Thirdly, you should provide a menu that includes a Window menu item, which allows the user to reposition the open window in respect of each other tile and cascade and presents a list of
702
all open windows. Another feature of MDI applications is that if a window is open and that window contains a menu, that menu should be integrated into the main menu of the application. An MDI application consists of at least two different windows. The first window you create is called an MDI Container. A window that can be displayed within that container is called an MDI child. We will refer to the MDI container as MDI container or main window interchangeably and to the MDI child as MDI child or child window To create an MDI application, you start out in just the same way as you do any other application, by creating a Windows application in Visual Studio .NET. To change the main window of the application from a from to an MDI container you simply set the IsMdiContainer property of the form to true. The background of the form changes to indicate that it is now merely a background that you should not place visible controls on, although it is possible to do so, and may even be reasonable under certain circumstances. To create a child window you ad a new form to the project by selecting a Windows Form from the dialog brought up by selecting Project | Add New Item. This form becomes a child window to a reference to the main window. You cannot set this property through the Properties panel, so you will have to so this using code. Two things remain before the MDI application is able to display itself in its most basic mode. You must tell the MDI container which windows to display, and then you must then display them. You simply do this by creating a new instance of the form you wish to display, and then calling Show () method. On it. The Constructor of the form to display as a child should hook itself up with the parent container. It does so by setting its MdiParent property to the instance of the MDI container.
703
Example Try it out Eagles CreatingMDI Step by Step Example: Using Version 2005
1. Create a new Windows application called MdiBasic in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using MDI 2. Select the form and set the following properties: Name Name IsMdiContainer Text Window State Value frmContainer True Eagles Creating MDI Maximized
3. Add a new form to the solution by choosing Windows Form from the Project | Add New Item menu. Name the frmChild. 4. Now add the following code to the IntializeComponent () method of the frmContainer and the code as follows: public Form1() { InitializeComponent(); frmChild eagles = new frmChild(); eagles.MdiParent = this; eagles.Show(); }
704
5. Now run the application and you should see the window like this:
Now we will see some real example which can be more useful:
Example Try it out Eagles MDIEditor Step by Step Example: Using Version 2005
1. Create a new Windows application called EaglesTextEditor in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using MDI\Eagles TextEditor 2. Add the following properties on the form: Name Name IsMdiParent Text WindowState Value eaglesMainForm True EaglesTextEditor Maximized
3. Now add the well add the code form the previous toolbar example in the EaglesMenuExample project select Project | Add Existing Item and browse to the Eagles UsingToolStrip.csproj and the rename the file Form1.cs to eaglesEditor.cs and then just drag and drop it to the Eagles MDIEditor, for instance we had shown the screenshot below
705
These steps are very similar to those of the Eagles MDI Basic application, other than using an existing form rather than creating a new one. However what follows is where things get interesting. 706
All Rights Reserved To EaglesGroup
4. After that just remove the EagleMenuFiles menu strip form the eaglesEditor.cs from the design view and at the same time remove the event handlers also. 5. Now change the constructors of the eaglesMainForm form to: public eaglesMainForm() { InitializeComponent(); Eagles_UsingToolStrip.eaglesEditor eaglesmdichild = new Eagles_UsingToolStrip.eaglesEditor(); eaglesmdichild.MdiParent = this; eaglesmdichild.Show(); } 6. Now run the application and you should have see something like this:
707
7. Now add the MenuStrip to the eaglesMainForm.cs and name the name the control as EagelesMainMenu properties as follows: Name menuItemFiles menuItemNew menuItemOpen menuItemClose menuItemSepFiles0 menuItemSave menuItemSaveAll menuItemFiles1 Text &Files &New &Open &Close &Save Save & All Top Level Yes No No No No No No No
8. Notice that MenuStripItem Windows should be a top level menu item that is, it should be placed to right of the Files Menu: 9. Now add seven more items and set the following properties in the eaglesEditor.cs and set the Merge Index to 1. before doing this remove the MenuStrip which we added before for the previous example and add the new menu strip and set the text and design name as follows: And change the Merger Type to ADD Name menuItemEdit menuItemUndo menuItemRedo menuItemSeperatorEdit0 menuItemCut menuItemCopy menuItemPaste Text &Edit &Undo &Redo Cu&t &Copy &Paste
10. And also add six more items and set the following properties as shown below: this six items should be added in the EagelesMainMenu which we add a new menu strip in the eaglesMainForm.cs and follow the below table to set the name and text properties. Name Text E&xit &Window &Tile &Cascade Open Windows Top Level No Yes No No No No
708
11. Now the you run the application and the form should look something like this:
12. Notice that while you are running the application you will see the Edit menu has bee nicely inserted in the Files menu. The reason this happened is that we set the Merge Index to 1 and the Merge Index of the Edit Menu has default value of -1 but we need to change it. Because the Merger Type to ADD, to the tight of all top level menu items that have a Merge Order less then or equal to its Merger Index 13. The Merge Index Value are as follows: Merger Index menuItemFiles menuItemEdit menuItemWindow Value 0 1 2
14. Another thing you will notice is that in the File Menu item contains with a check mark. The text of this item as the text of the eagleseditor.cs from In this menu all open window will be listed without us having to code a single line. This is the result of the setting the MdiList property of the MenuItemWindowOpen Menu item to true.
709
15. Now we are going to the Coding part. Just go the eagleseditor.cs form and double click the menuItemUndo and enter the following code: private void menuItemRedo1_Click(object sender, EventArgs e) { rtfText.Redo(); } private void menuItemCut1_Click(object sender, EventArgs e) { rtfText.Cut(); } private void menuItemCopy1_Click(object sender, EventArgs e) { rtfText.Copy(); } private void menuItemPast1_Click(object sender, EventArgs e) { rtfText.Paste(); }
710
16. Now the RichTextBox control provides us with a method that corresponds exactly to our entire menu item, so we simply call these functions. Just as we did in the Eagles UsingMenu example, we need to check if the menus should be enabled or disabled and we do this in the Popup event handler. These items well subscribe to the event in the constructer of the form eagleseditor. string caption; public eagleseditor(Eagles_MDIEditor.eaglesMainForm parent, string caption) { InitializeComponent(); this.MdiParent = parent; //Set the caption or title of the form this.Text = caption; } 17. Then we add the event handler for the menuItemEdit1_popup and the code as follows: private void menuItemEdit1_Popup(object sender, EventArgs e) { //If there is no text selected, we cannot cut it, this.menuItemCut1.Enabled = rtfText.SelectedText.Length > 0 ? true : false; // If there is no text selected, we cannot copy it. this.menuItemCopy1.Enabled = rtfText.SelectedText.Length > 0 ? true : false; //The CanPast mehtod of the RichTexBox tells us if there's nothering to past this.menuItemPast1.Enabled = rtfText.CanPaste(DataFormats.GetFormat (DataFormats.Rtf )); //The CanUndo mthod of the ReichTexBox tells us if we can undo an action this.menuItemUndo1.Enabled = rtfText.CanUndo; //The CanRedo property of the RichTextBox tells us if we can redo an action this.menuItemRedo1.Enabled = rtfText.CanRedo; }
711
DENOTE: Once again, the RichTextBox helps us out. It is possible to check all of the items to see if they should be enabled or not, simply calling a function or querying a property. The only method that needs further explanation is CanPaste (). This method takes the text that you want to past and returns a Boolean value which is true if it is possible to do the paste. Now lets move to the menus in the eaglesMainForm.cs. well start with the New menu item on the Files menu. When New is clicked we want to create an additional window. Weve already seen how to do this, as it already happens in the constructor, but theres a problem. At the moment all of our windows have the exact same caption Editor which makes it impossible to distinguish between them in the MdiList we create. To change this, well add a new parameter to the constructor of the eagleseditor.cs form in which well send the text that should be displayed in the new windows caption: string caption; public eagleseditor(Eagles_MDIEditor.eaglesMainForm parent, string caption) { InitializeComponent(); this.MdiParent = parent; //Set the caption or title of the form this.Text = caption; }
This change means that we have to change the call to the constructor that is made in the constructor of the container and the code as follows: public eaglesMainForm() { InitializeComponent(); Eagles_MDIEditor.eagleseditor newForm = new eagleseditor(this, "Editor 1"); newForm.Show(); }
712
18. Now we are ready to create new windows. Double click the New menu item and add the following code: private void menuItemFiles_Click(object sender, EventArgs e) { string caption = "Editor" + nextFormNumber++; Eagles_MDIEditor.eagleseditor newForm = new Eagles_MDIEditor.eagleseditor(this, caption ); newForm.Show(); }
In the above code we had mention that nextFormNumber it is a variable for that we need to declare the variable for declare the variable the code as follows:
private int nextFormNumber = 2; private void menuItemFiles_Click(object sender, EventArgs e) { string caption = "Editor" + nextFormNumber++; Eagles_MDIEditor.eagleseditor newForm = new Eagles_MDIEditor.eagleseditor(this, caption ); newForm.Show(); }
If we choose to use the number of windows currently in the array of the forms (MDIChildren) we would have a problem if two forms had been opened, and the forms with number 1 was subsequently close. Well therefore simply add one to this number each time a new form is opened. The reason the next form number is two rather than one we start the constructor used the text Editor 1 to initialize the first window. After that we create a new instance of the editor form and show it.
713
19. If you run the code and add a new window, you will notice that the events in the Edit menu target the correct window which is lucky, because we didnt do anything to achieve this. Because the events handlers are defined for each instance of the form, the events are sent to the correct place every time. Also you will see the two windows showing up in the Open Windows List:
20. Now we want to be able to close the window again. The eaglesMainForm.cs has a property called ActiveMdiChild, which lets us identify the child window we want to close. Double click the Close menu and add the Following code: private void menuItemOpen_Click(object sender, EventArgs e) { eagleseditor frm = (eagleseditor)this.ActiveMdiChild; if (frm != null ) //Make sure the child is valid before using it { frm.Close (); // this will close the current window } }
714
First, we cast the form contained in the ActiveMdiChild property to a Eagles_MDIEditor class. Then we make sure that the instance is not null before doing anything with it, and then call Close () on the window. We are not going to cover implementing the other File menu items, such as the Open, Save and Save-All options use the standard open and save file dialogs which are discussed in the next section. The Exit menu item uses the very same code as we see in the earlier chapter and examples. 21. Now double click the Tile button and enter the following code: private void menuItemTile_Click(object sender, EventArgs e) { this.LayoutMdi(MdiLayout.TileHorizontal); }
22. Now double click the Cascade menu and enter the following code: private void menuItemCascade_Click(object sender, EventArgs e) { this.LayoutMdi(MdiLayout.Cascade); }
The LayoutMdi () method on the container window allows you to change the layout of all the MDI children.
715
This concludes our discussion of SDI and MDI application. If you run the code you should be able to create something like this which shown in the following picture I had opened three documents:
16.29 Populating a List Box Imagine that you are trying to show users all the files that exist in a given directory, to allow them to pick the file they want. You could put a larger number of check boxes on a form and allow users to pick one. But how would you know ahead of time how many you would need. One alternative is to simply create them at runtime and allow users to click the one they want. However, if you have a large directory, with a large number of files in it, the list would become impossible to mange, even in a short period. How do you show something that make up a list of items when you dont know how many items youll have. The best way we an do is with the standard Windows list box control.
The C#.NET base class library visual elements contain a list box component that is a complete wrapper around the list box control. This component allows you to display multiple items in a small amount of space and to control. This component allows you to display multiple items in a small amount of space and to control how those elements are sorted you to display all the files in a given directory for a user, and allow him to browse through them quickly and easily. The picture below shows the form used to for this example. This form contains the text box that holds the name of the directory to browse as well as the List button to start the listing processes. The list box itself is prominent in the middle of the form and is followed by the Close button that allows you to close down the form and themselves, the application.
716
Example Try it out Eagles UsingListBox Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles UsingListBox in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using List box for Populating 2. Now drag and Drop two buttons and name the as List and Close and set their design name as btnList and btnClose. 3. Now Add List box and a label and set the Text property as listdrive and lbldisplay and a textbox and name it as txtenter 4. After adding the stuffs in the Windows Form you should have a window form like this
717
5. Now we are moving to the coding part for using the system files we need declare some namespace which is System.IO; which will help us to directory the files and folder from the computer. And add the code as follows: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO;
6. After adding the namespace just double click the List Button and enter the following code:
private void btnList_Click(object sender, EventArgs e) { if (this.txtenter.Text.Length != 0) { //Lading the list box string[] files = Directory.GetFiles(this.txtenter.Text); foreach (string siddhu in files) { this.listDrive.Items.Add(siddhu); } }
718
7. Now Double click the Close button and Enter the following code for the Exit: private void btnClose_Click(object sender, EventArgs e) { Application.Exit(); }
8. Now run the Application and you should see the window like this and try to enter the Drive which I used to Enter Drives C, and D, :
Now lets see how the above program works: The process of listing the items is simple enough; you see the Directory components to create an interface to the directory itself. Lets see the following code: string[] files = Directory.GetFiles(this.txtenter.Text);
The Directory.GetFiles retunes the names of the files that are specified in the directory and match the search pattern specified by you. Then the directory object is quarried for an array of file objects to store in the list box. Finally, the array is iterated over, and each element is used to populate the list box. This concludes our discussion of Populating a List Box.
719
16.30 Adding a border to a Form Forms have many attributes that can be set at design time. For example, you can set the title and size of the form and determine whether the form contains a help button on the caption. In classic Windows applications, you cannot change certain attributes without doing a great deal of work behind the scenes. One attribute that could not be easily changed was the border style of the form. If you want to change the form to have no border, for example. So that you can blend it with other windows on the screen, you would have to destroy the original form object and re create it with the new style. This solution was, obviously, less than optional. With the new C#.NET base class library system, you can modify virtually any attribute of any object at runtime without incurring any penalty. One easy thing to change is the form border style. In this example, you see exactly how to modify the form border at runtime to get things just the way you want them. The following picture shows the form used this example. The individual border styles are shown as radio button because the style is mutually exclusive,
720
Example Try it out Eagles AddingBorder Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles AddingBorder in the directory C:\EaglesVisualCSharp\Chapter 16\ Example Using Border to Form 2. Now drag and drop two radio buttons and one button and set the properties as follows: Name button1 radiobuton1 Radiobutton2 Property Text = Close Design Name = btnClose Text = Fixed Dialog Design Name = rdoFixedDialog Text = No Border Design Name = rdoNoBorder
3. Now Double click the Fixed Dialog Radio button and enter the following code: private void rdoFixedDialog_CheckedChanged(object sender, EventArgs e) { this.FormBorderStyle = FormBorderStyle.FixedDialog; Text = "Eagles:" + "Form Border = FixedDialog"; } 4. Now Double click the No Border button and enter the following code: private void rdoNoborder_CheckedChanged(object sender, EventArgs e) { this.FormBorderStyle = FormBorderStyle.None; Text = "Eagles:" + "Form Border = No - Border"; }
721
5. Now enter the code for the Close button as follows: private void btnClose_Click(object sender, EventArgs e) { Application.Exit(); }
6. Now Run the Application and try it as I run this is the result I get:
Now lets see how the above code works: As you can change the border style of the form during the run time we have used the FormBorderStyle property, which represents the border style to be displayed on the form. The FormborederStyle.FiexrDialog border style is applied which prevent the form from being resized. this.FormBorderStyle = FormBorderStyle.FixedDialog;
DENOTE: For example, having a form that has both a dialog box style border and no border. It just doesnt make any sense to have multiple border style in the single form.
722
16.31 Adding a Form Icon Sometimes the little things in life make users happy, like an informative icon in the corner of a form. By default the C#.NET base class library provides an icon for all the forms which are created in the System. By that icon isnt particularly distinctive. Like the pyramid of blocks used by the MFC application, the C# form icon is boring. It would be useful to be able to load a more distinctive icon into a place and use it when the program is running. It could be even nicer to change that icon at runtime to indicate various program states. Fortunately, the .NET base class library makes this process easy too. Lets see this by a working example:
Example Try it out Eagles ChangingIcon Step by Step Example: Using Version 2005
1. Create a new Windows application and name it as Eagles ChangingIcon in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using icon at Runtime 2. And add two buttons and one label and set their properties as follows: Name button1 button2 lable1 Text Text = Icon Design Name = btnIcon Text = Exit Design Name = btnExit Text = Select an Icon Design Name = lblDisplay
3. And double click the Icon button and enter the following code: private void btnIcon_Click(object sender, EventArgs e) { OpenFileDialog siddhu = new OpenFileDialog(); if (siddhu.ShowDialog() == DialogResult.OK) { //Load the Icon file System.Drawing.Icon sri = new System.Drawing.Icon(siddhu.FileName); //now we can set the form to be that icon this.Icon = sri; } }
All Rights Reserved To EaglesGroup
723
4. Now Enter the code for the Exit button as follows: private void btnExit_Click(object sender, EventArgs e) { Application.Exit(); } 5. Now run the application and Try to change the icon I try and change and the picture as shown below:
16.32 Adding a Button on Runtime Although the integrated environment is wonderful for designing and building forms which you can use in your application, sometime that environment is not enough. Imagine that you want to create an application that is dynamic, changing in response to the input a user might select. You might need to dynamically create new components on the form and then use them in you r application. If you are accustomed to work only with a form created by the Visual Designer, you probably have no idea how to create and use them. In this section we will explain and guide you to create a button at runtime and at the same time we create event handler for the newly created button also. Lets see the by using the Example:
724
Example Try it out Eagles CreatingButton Step by Step Example: Using Version 2005
1. Create a new Windows application and name it as Eagles CreatingButton in the Directory C:\EaglesVisualCSharp\Chapter 16\Example Using Button at Runtime 2. Add two buttons and one label and set their property as follows: Name button1 button2 label1 Property Text = Add Button Design Name = btnAdd Text = Exit Design Name = Exit Text = Click to Add New Button Design Name = lblDisplay
3. Before we are entering to the coding part we need to create a variable in the form constructor and the method to write the code as follows: namespace Eagles_CreatingButton { public partial class Form1 : Form { private System.Windows.Forms.Button eagles = new Button();
725
4. Now Double click the Add button and enter the code as follows:
private void btnAdd_Click(object sender, EventArgs e) { eagles.Location = new System.Drawing.Point(75, 20); eagles.Size = new System.Drawing.Size(175, 23); eagles.TabIndex = 3; eagles.Text = "Button Created RunTime"; eagles.Click += new System.EventHandler(this.eagles_Click); this.Controls.Add(this.eagles); }
5. Now Enter the event handler for the newly created button as follows:
protected void eagles_Click(object sender, System.EventArgs sri) { MessageBox.Show("You Click the New button", "EaglesGroup", MessageBoxButtons.OK, MessageBoxIcon.Information); }
6. Enter the Code for the Exit button as follows and run the application private void btnExit_Click(object sender, EventArgs e) { Application.Exit(); }
726
Now lets see how the program works: The button named AddNewbutton dynamically add button to the runtime form. The second button simple Exit the application. The variable which we are declaring in the form1.cs constructor is the help to create the run time button. But how when we click the button it shows the message box. It is because we are creating a click event also for the button which as been added private System.Windows.Forms.Button eagles = new Button();
The most interesting parts of this listing are how the button is placed on the form and how the events for the button are handled. As you can see nothing is magical about the dynamic creating of button. They are done exactly in the same way as the system generates the code for them in the first place. Thy are done exactly when you set up a delegent to handle the click event for the button, all you do is handling the code as though the system had written it for you. One thing this application sample point out is that can easily add new handlers to visual elements at runtime. This feature is important because the way in which you handle
727
something may depend on the information you dont have runtime, such as the type of user you are working with. To add a new visual element to a form, you must perform several important steps: Create the components, such as button Assign the properties to the button to position it placed the text on it, and to do whatever other tailoring you want to for the component. Finally, to make the component appear on the form, you need to add the component to the form list of control using the following line: this.Controls.Add(this.eagles);
DENOTE: If you do not add this line, you find that the button never appear on the form at runtime, even though it is been created properly This concludes the discussion of the Adding the button on the run time.
16.33 Creating a Custom Controls: There are times when the control that ship with Visual Studio .NET just dont meet you needs. The reasons for this can be many the controls dont draw themselves in the way you want them to, or the controls are restrictive in some way, or the control you need simply doesnt exist. Recognizing this, Microsoft has provided us with the means to create controls that meet our needs. Visual Studio.NET provides a project type name Windows Control Library, which you can use when you want to create a control yourself. One useful element of C# is that it comes with so many pre built components to do nearly everything that you can think of doing in an application. Unfortunately, the thrill of accessing that huge .NET base class library goes away when you cant find components to do a task for you that you have been doing yourself. Having a huge class library of visual components, C# comes with an answer to the that problem the Custom Control Two distinct kinds of home made controls can be developed, named user control or composite control and custom controls User or composite control These controls build on the functionality of existing controls to create a new control. Such controls are generally made to encapsulate functionality with the user interface of the control, or to enhance the interface of a control by combining several other controls into one unit.
728
Custom controls These controls can be created when no controls fits your needs, that is, you start from scratch. It draws its entire user interface no existing controls are used in the creating of the control. You will normally need to create a control like this when the user interface control you want to create in unlike that of any other available control. In this section, well focus on user control as the second option of designing and drawing a custom form scratch is beyond the scope of me to give in this Book. As you can see in the GDI+ chapter gives you the means to draw items by yourself, and you should then be able to move on to custom controls easily. Custom controls can be written quickly and easily in C# to accommodate virtually any need. Furthermore, by taking advantage of the huge amount of basic functionality addressed by the underlying .NET class library, you can easily make complex components with a minimum of fuss or coding.
ActiveX Controls as used in Visual Studio 6 existed a special kind of files with the extension OCX. These files were essentially COM DLLs. In .NET a control exists in exactly the same way as any other assembly, and because if that the OCX extensions has disappeared and control exists in DLLs.
User control inherits from the System.Windows.Forms.UserControl class. This base class provides the control you are creating with all the basic features a control in .NET should include leaving you only the task of creating the control. Virtually anything can be created as a control, ranging from a label with a nifty design to full blown grid controls.
729
Unlike user controls, custom controls derive from the System.Windows.Forms.Control class rather UserControl.
We take a number of things for granted when we are working with controls. If you control doesnt fulfill those exceptions, the chances are that people will be discouraged from using it. These criteria are:
The behavior of the design time control should be very similar to its behavior at run time. This means that if the control consists of a Label and a TextBox that have been combined to create a Label Textbox, the Label and TextBox should both be displayed at design time and the text entered for the Label should also be shown at design time. While this is fairly easy in the above example, it can present problems in more complex cases, where youll need to find an appropriate compromise. Access to the properties of the control should be possible from the designer in a logical manner. A good example of this the ImageList control that presents a dialog from which you can browse to the images you want to include, and once the image are imported, they are shown in a list in the dialog. Over the next few topics we will introduce you to the creation of controls by means of an example. The example creates the LabelTextbox and demonstrates the basics of creating a user control project, creating properties and event and debugging controls.
Example Try it out Eagles CreatingUserControl Step by Step Example: Using Version 2005
As the name of the control implies, this is a control that combines two existing controls to create a single one that performs in, one go, a task extremely common in Windows programming: adding a label to a form, then adding a text box to the same form and positioning the text box in relation to the label. Lets look at what a use of this control will expect it to do. It should be possible for the user to position the text box either to the right of the label or below. If the text box is positioned to the right of the label, it should be possible to specify a fixed distance from the left edge of the control to the text box in order to align text boxes below each other The usual properties and event of the text box and label should be available to the user.
730
1. Create a new Window Control Library project called Eagles LabelTextbox in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using UserControls
The form designer presents you with a design surface that looks somewhat different from, what we used to. First of all the surface is much smaller than normal, and secondly it doesnt look like a dialog at all. You should not let this new look discourage you in any way things still work as usual. The main difference is that up until no we have been placing control on a form, but now we are creating a control to be placed on a form.
2. Click the design surface and bring up the properties for the control. Change the Name of the control to ctrLabelTextBox. 3. Double click a Label in the TextBox to add it the control, placing it in the top left handed corner of the surface. Change its Name property to lblTextBox. Set
731
the Text Property to Label. Set the AutoSize property to true but it default set to true. This will make the label control size itself to the size of the text. 4. Double click a TextBox in the Toolbox. Change its Name property to the txtLabelText and clear the Text property. At design time we do not know how the user will want ot position these control. Because of that we are going to write a simple code that will position the Label and TextBox. That same code will determine the position of the controls when a Eagles LabelTextbox control is placed on a form. The design of the control looks anything but encouraging not only is the TextBox floating freely on the surface, the surface is too large. However this is of no consequence, because unlike what weve been used to up until now, what you see is not what you get! The control we are about to add the control will change the appearance of the control, but only when the control to a form.
The first thing we want to do is position the controls relative to each other. The user should be able to decide how the controls are positioned and for that we add but two properties to the control. One property is called Position and gives the user a choice between two option: Right and Below. If the user chooses Right then the other property comes into play. This property is called TextBox Margin and is an int that represents the number of pixels from the left edge of the control to where the TextBox should be placed. If the user specifies 0 the TextBox is placed with its right edge aligned with the right edge of the control. Now lets see about adding the Properties In order to give the user a choice between Right , and Below we start by defining an enumeration with these two value, Return to the control project, go to the code editor and add this code as follows:
732
public ctrLabelTextBox() { InitializeComponent(); } public enum PositionEnum { Right, Below } This is just a normal enumeration as we see now. Now for the magic we want to position to be property the user can set through code and the designer. We do this by adding a property to the ctrLabelTextBox class. First, however, we create two member fields that will hold the values the user selects: private PositionEnum mPosition = PositionEnum.Right; private int mTextboxMargin = 0;
private PositionEnum Position { get { return mPosition; } set { mPosition = value; MoveControls(); } }
The property is added to the class like any other propery.if we are asked to return the property, we return the mPosition member field, and if we are asked to change the Position, we assign the value to mPosition and call the method Move Controls () well return to Move Controls () in a short while, for now it is enough to know that this method position the two controls by examining the values of mPosition and mTextboxMargin. .
733
The Textbox Margin property is the same, except it works with an integer: public int TextboxMargin { get { return mTextboxMargin; } set { mTextboxMargin = value; MoveControls(); } }
Adding the Event Handlers Before we move on to the test the two properties. We will add two event handlers as well. When the control is placed on the form, the Load event is called. You should use this evetn to initialize the control and any resources the control may use. We handle this event in order to move the controls and size the controls to fit neatly around the two controls it contains. The other event well add is the SizeChanged evetn. This event is called whenever the control is resized, and we should handle the event to allow the control to draw itself correctly. We subscribe to the events in the constructor of the control: // This will handle the SizeChanged event this.SizeChanged += new System.EventHandler(this.OnSizeChanged); // This will handle the Load event this.Load += new EventHandler(this.OnLoad); Then we add the event handlers: private void OnSizeChanged(object sender, System.EventArgs sri) { MoveControls(); } Once again, we call MoveControls () take care of the positioning of the controls. It is time to see this method, before we test the control again:
734
private void MoveControls() { switch (mPosition) { case PositionEnum.Below: // place the top of the Textbox just below the label this.txtLableText.Top = this.ldlTextBox.Bottom; this.txtLableText.Left = this.ldlTextBox.Left; //changes the width of the Textbox to equal the width of th control this.txtLableText.Width = this.Width; this.Height = txtLableText.Height + ldlTextBox.Height; break; case PositionEnum.Right: //set the top of the textbox to equal that of the label txtLableText.Top = ldlTextBox.Top; //if the margin is zero, we'll place the textbox next to the label if (mTextboxMargin == 0) { int width = this.Width - ldlTextBox.Width - 3; txtLableText.Left = ldlTextBox.Right + 3; txtLableText.Width = width; } else { //if the margin isn't zero contain a value has specified by the user txtLableText.Left = mTextboxMargin; txtLableText.Width = this.Right - mTextboxMargin; } break; }
The value in mPosition is tested in a switch statement to determine whether we should place the text box below or to the right of the label. If the user chooses below, then we move the top of the text box to the position that is the bottom of the label. We then move the left edge of the text box to the left edge of the control and set the width of it to the width of the control. If the user chooses Right, then there are two possibilities. If the TextboxMargin, is zero, then we start by determining the width that is left in the control for the text box. We then set that left edge of the text box to just a nudge right of the text and set the width to fill remaining space. If the user did specify a margin then we place the left edge of the text box at the position and set the width again.
735
We now ready to test the control before we move on, build the project.
16.34 Debugging User Controls Debugging a user control is quite different from the debugging a Windows Application When you run the program you will have a output like this:
736
Now we will create a simple custom control to display a clock that updates itself every second on the display.
As you can see, the clock is a simple component. It just display the time in hours, and minutes and updates itself every second. Take a look at the code that implements this custom control, which is shown as the Eagles Clock Example:
Example Try it out Eagles CreatingClockControl Step by Step Example: Using Version 2005
1. Create a new Windows Control Library and name it as Eagles Clock and create it in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using UserControls\Eagles Creating Clock 2. After that right click the control and view code and add the following namespace: using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using System.Timers; 3. Now you need to declare the variable as follows: private System.Timers.Timer eaglestimer;
4. Now add the code to the IntializeComponent () method as follows: public UserControl1() { InitializeComponent(); eaglestimer = new System.Timers.Timer(); eaglestimer.Interval = 100; // this code will set the Interval to 1 second eaglestimer.Enabled = true; }
737
5. Now create Event handler named OnTimeEvent and the code as follows: public void OnTimeEvent(object source, EventArgs sri) { Invalidate(); } 6. Now we need to create another handler event which will make the clock to display in the User Control.cs for this we need to use the OnPaint () method which we will learn more on this on the GDI+ chapter. protected override void OnPaint(PaintEventArgs sri) { //The follwoing code will get the curren time from you system DateTime eaglesdt = DateTime.Now; //Now we are formating it to a string string siddhutime = eaglesdt.ToShortTimeString(); // Now we need to display it StringFormat style = new StringFormat(); style.Alignment = StringAlignment.Center; sri.Graphics.DrawString(siddhutime, Font, new SolidBrush(ForeColor), ClientRectangle, style); base.OnPaint(sri); }
Now we are going to add this User Control to the Windows Application for adding in the Windows application follow these simple steps: 1. Create a new Windows Application and name it as Eagles Display Clock in the following directory C:\EaglesVisualCSharp\Chapter 16\Example Using UserControls\Eagles Display Clock 2. Now Right click the solution explorer and select the Add Existing Item menu as shown in the following picture:
738
Once you add the Existing project which we create the project named as Eagles Clock and select the project and you will see in the toolbox option the user control will be place automatically as shown in the following picture:
3. Now just drag and drop the UserControl form the toolbox and add it to the Windows Application thats it now you run the application and you should see the Window like this:
739
Now we see the Common Dialogs The Built in Dialog Boxes: There are a number of built in dialog boxes in Visual C#.NET its greate because developing your own file open, file save, and other dialog boxes not only involves a lot of work, but gives you program a different look from what Windows users are alredy familier with it. Well describe some of the dialogs whose names are follows:
Folder Browser Dialogs Open File Dialogs Save File Dialogs Font Dialogs Color Dialogs Print Preview Dialogs Print Dialogs
You use the ShowDialog method to display the dialog at run time and check it return value such as Dialog.Result.OK or Dialog.Result.Cancel to see which button the user has
740
clicked. Here the possible return values from this method, from the DialgogResult enumeration: Abort The dialog box returns value in Abort Cancel The dialog box return value in Cancel Ignore the dialog box return value is Ignore No The dialog box return value is no None Nothing is returned from the dialog box. OK The dialog box return value is OK Retry The dialog box return value is Retry Yes The dialog box return value is Yes
Folder Browser Dialogs: As youd expect from its name, the Folder Browser dialog lets the user select the folder. As you can see the dialog box in the following picture:
Folder Browse dialog are supported with the FolderBrowserDialog class. If ShowNewFolderButton is True , by default it will be. The dialog also shows a Make an New Folder button. With this select it. You can use this class when you only want to allow the user to select folders, not files. The user can browse through the folders which are presented to him in the form of tree; much like in Windows Explorer. But only the folder from the file system can be selected; virtual folder cant be selected.
741
The following table will give you the public properties of the Folder Browser Dialog Name Description Description It obtains the description text displayed above the tree view control in the dialog box. It obtains the root folder where the browsing starts from. It obtains the path selected by the user. It obtain a value indicating whether the New Folder button appears in the folder browser dialog box.
The following table will show you the available methods on the Folder Browser Dialog Name Show Dialog Description It runs a common dialog box
The following table will show you the public event of the Folder Browser Dialog Name Help Request Description It occurs when the users click the Help Button on the dialog box
742
Example Try it out Eagles FolderBrowser Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles FolderBroswer in the directory D:\EaglesVisualCSharp\Chapter 16\Example Using FolderBrowserDialogs 2. Add a Label control and a Button in the windows forms as shown in the below picture and change the property of the both control design as Label = lbldisplay and Button = btnBrowse and change the Text property as Label = null and Button = Browse:
3. Now add the Folder Browse Dialog form the menu and container tab form the toolbox and then double click the browse button and the enter the following code as follows: private void btnBrowse_Click_1(object sender, EventArgs e) { if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) { lblDisplay.Text = folderBrowserDialog1.SelectedPath.ToString(); } }
743
4. Now run the application and you should have the output like this:
Folder Browse Dialog is actually a powerful searching tool that lets the user select a folder on which he or she can perform search for files based on the criteria set in the user interface. Promoting the user for selecting a folder is done with the piece of code: private void btnBrowse_Click_1(object sender, EventArgs e) { if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) { lblDisplay.Text = folderBrowserDialog1.SelectedPath.ToString(); } } The selected Path works both ways that is if you set its value to a directory path, the Browse for Folder dialog starts browsing from that path only. Another useful property to know about is the Root Folder property, which lets you specify one of the special folder that the Browse For Folder dialog can show as the root folder, and only list its subdirectories when you show it here how it works.
744
Lets say, we set the root folder to Program Files like the following code: folderBrowserDialog1.RootFolder = Environment.SpecialFolder.ProgramFiles(); The following table will show you the list of the Environment.SpecialFolder values:
Description This directory as a common storehouse for application specific data for the current roaming user. This directory serves as a common storehouse for application specific data that is used by all users. This directory is for components that are shared across application This directory serves as a common storehouse for the Internet cookies. This is the logical Desktop rather than the physical file system location This directory is used to physical store files objects on the desktop. There is no need to confuse this directory with the desktop folder itself, which is a virtual folder. This directory serves as a common storehouse for the users favorite items. This directory serves as a common storehouse for the internet history This directory serves a common storehouse for the temper internet files This directory serves as a common storehouse for the application specific data that is used by the current, no roaming user. It Represents the My Computer folder It Represents the My Documents It represent the My Music folder It represents the My Pictures folder
745
The directory that serves as a common storehouse for documents The Program Files directory This is the directory that contains the user most recently used documents This is the directory that contains the Send to MenuItem This is the directory that corresponds to the user start up program group This system directory This directory serves as a common storehouse for the document templates.
746
Open File Dialogs are supports with the OpenFileDialog class. You can let users select multiple files with the MulitSelect property. You can use the Read-Only property to determine if a read only check box appears in the dialog box the read only checked property indicates whether the read only check box is selected. And the filters property sets the current file name filter string , which determines the choice that appear in the Files of type box in the dialog box. The name and the path selected by the user is stored in the Filename property of the OpenFile Dialog object; and theres a neat shortcut here you can use the OpenFile method to open the selected file directly.
The following table shows the public property of the OpenFileDialog Object:
Description It obtains if the dialog box adds an extension to file names if the user doesnt supply the extension. It obtains if the dialog box displays a warring if the user specifies a nonexistent file. Finds whether the dialog box display box displays a warning if the user gives a path that does not exits It obtains the default file extension It obtains the file name selected in the file dialog box. It obtains the file names of all selected files It obtains file name filter string, which sets the choices that appear in the save as file type or File of type box. It obtains the index of the filter selected in the File Dialog box. It obtains the initial directory used in the File dialog box. It obtains finds whether the dialog box allows multiple file selections. Finds weather the read only check box is checked. It finds whether the dialog box should restore the original directory before closing
747
Finds whether the help button should be displayed or not. It finds whether the dialog displays a read only check box, Obtains the First dialog box title It obtains a value specifying if the dialog box accepts only valid that in Win32, filename,
The following Table shows the public methods of the OpenFileDialog objects: Name Open File Description It opens the file selected by the user, with the read only permission. The file is specified by the File Name Property It resets all options to their default Values It shows the dialog box
Reset ShowDialog
The following table shows the public events of the OpenFileDialog as follows:
Description It occurs when the user click the Open or Save button. It occurs when the user clicks the Help button.
Example Try it out Eagles OpenFile Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles OpenFile in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using Open File Dialog 2. Add the following control and make the changes as shown in the following table:
748
Control Picture Box (1) Button (1) Open File Dialog (1)
To be Changed Design Name = picDisplay Text = Open Design Name = btnOpen Design Name = default
3. Now double click the Open button and add the following code: private void btnOpen_Click(object sender, EventArgs e) { openFileDialog1.InitialDirectory = "C:"; if(openFileDialog1.ShowDialog () == DialogResult.OK ) { picDisplay.Image = Image.FromFile(openFileDialog1.FileName); } }
749
4. Now run the application and select the picture and you should see the following output:
The above program lets the user to open an image in a picture box. To configure the Open File Dialog, we need add an OpenFileDialog control to the project. To specify that we want the user to be able to open the JPEG or GIF or files, we use the Filter property of this control, which sets the possible file types that this dialog can open. In this case, well set that property to this string at design time: Jpeg files (*.jpg) | *.jpg | GIF files (*.gif) | *.gif | All files (*.*) | *.*. This gives the user three prompts on the runtime. This concludes the Open File Dialog class:
Save File Dialogs Save File dialog are supported by the SaveFileDialog class. These dialog let the user specify the name of a file to save data to. These dialogs are the same as the standard Save File Dialog box used by Windows; you can see a Save File dialog in following picture:
750
The following table shows the public properties of the Save File Dialog Class: Name Add Extension Description It Obtains or sets whether the dialog will add an extension to a file name if the user doesnt supply an extension It obtains whether the dialog box displays a warning if the user specifies a file that does not exist Obtains whether the dialog box display a warning if the user specified a path that does not exist It sets the dialog box asks the user if it should create a file if the user specifics a non existent file. It obtains the sets default file extension It obtains the file name selected in the File dialog box.
Check File Exists Check path Exists Create Prompt Default Ext FileName
751
FileNames Filter
It Obtains or sets the file names of all selected files It obtains the current file name filter string, which sets the choices that appear in the Save file type or Files of type box. It obtains the index of the filter selected in the file dialog box It obtains the initial directory used in the File dialog box. It obtains the dialog displays a warning if the user specifics a name that already exists. Obtains the dialog box should restore the original directory specifies a name that already exists. It obtains or sets whether the Help button should be displayed. Obtains or sets the File Dialog box title. It obtains the dialog box accepts only valid that is Win32 file name
The following Table shows the public methods of the Save File Dialog Class Name OpenFile Reset ShowDialog Description It opens the file with read/ write permission selected by the user It resets all dialog options to their default values It shows the dialog
The Following Table shows the public events of the Save File Dialog class:
Description It Occurs when the user click the Open or Save Button It occurs when the user click the
All Rights Reserved To EaglesGroup
752
Example Try it out Eagles SaveFile Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles SaveFile in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using Save File Dialog 2. Add the following Controls to the Windows Form as Follows:
Things to be Changed Text = Save Design name = btnSave Text = Null Design Name = EaglesText Design Name =Default
753
4. Now Add the using directive in form1.cs as follows: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO;
754
5. Now declare a variable name EaglesName; as follows in the code: public partial class Form1 : Form { string EaglesName;
public Form1()
6. Now double- click the Save button and enter the following code: private void btnSave_Click(object sender, EventArgs e) { if (saveFileDialog1.ShowDialog () == DialogResult.OK ) { EaglesName = saveFileDialog1.FileName; EaglesFile(); } }
7. Now you build you will have the Error because we need to write the code for the EaglesFile (); and type the following code as follows in the Form1.cs protected void EaglesFile() { try { Stream Siddhu = File.OpenWrite(EaglesName); using (StreamWriter Sri = new StreamWriter(Siddhu)) { Sri.Write(EaglesText.Text); } } catch (IOException Eagles) { MessageBox.Show(Eagles.Message, "Eagles Pad", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } }
755
8. Now run the application and the out put will be like this and the then enter some text in the Rich Text box and the click the save button.
Color Dialog
Color dialog let the user to select the color in an easy way. The principal property you can use of these dialogs is the Color Property, which returns a color object, ready for use. You can see a color dialog box in the picture below:
756
The following Table shows the public properties of the ColorDialog objects:
Name Allow Full Open Any color Color Custom Colors Full Open Show Help Solid Color only
Description It obtains the user can use the dialog box to define custom colors It Obtains the dialog box display all available colors in the set of basic colors It obtains the color selected by the user It obtains the set of custom colors in the dialog box It obtains the control used to create custom colors are visible when the dialog box is opened. It obtains a Help button appears in the color dialgo box It obtins the dialog box will restrict users to selecting solid colors only.
757
The following table shows the public methods of the Color Dialog box Name Reset ShowDialog Description It resets all dialog options to their default values It shows the dialog
Example Try it out Eagles ColorDialog Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles ColorDialog in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using Color Dialog 2. Add the following controls in the window form as follows in the tables: Controls Button (1) Thing to be Changed Text = Choose Color Design Name = btnColor Text = Welcome to EaglesGroup Design Name = lblDisplay Design Name = default
Label (1)
758
4. Now add the following code by double clicking the choose color button: private void btnColor_Click(object sender, EventArgs e) { if (colorDialog1.ShowDialog() == DialogResult.OK) { lblDisplay.BackColor = colorDialog1.Color; } }
759
5. Now run the application and click the button and the select the color and the back color of the label control will change when I change I get this out put:
The Font Dialog Class: Font Dialog let the user to select a font size, face, color, and so on. You can see the font dialog box at the work in the following picture:
760
The following table will show the public properties of the Font Dialog Class: Name Allow Simulations Description It finds in the dialog box allows the graphics device interface (GUI) font simulations. Finds whether the dialog box allows vector font selections. It finds whether the dialog box display both vertical and horizontal fonts or only horizontal fonts. It obtains the selected font color It finds in the dialog box specifies an error condition if the user attempts to select a font or style that does not exist It obtains the selected font It finds that the dialog box specifies an error condition if the user attempts to select a font or style that does not exist It obtains the maximum point size a user can select It obtains the minimum point size a user can select It finds whether the dialog box contains an apply button It finds wheheter the dialog box display the color choice It finds whether the dialog box contains controls that allow the user to specify strike through, underline, and text color option It finds whether the dialog box display a Help button.
Allow Vector Fonts Allow Vertical Fonts Color Fixed Pitch Only
Show Help
761
The following table shows the public methods of FontDialog Class: Name Reset Description It results all dialog options to default values
It shows the dialog Show Dialog The following table shows the public events of the Font Dialog Class: Name Apply Help Request Lets work it out Using Font Class Dialog Description It occurs when the user clicks the apply button It occurs when the user clicks the Help button
Example Try it out Eagles FontDialog Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles FontDialog in the directory C:\EaglesVisualCSharp\Chapter 16\Example Using Font Class Dialog 2. Add the following in the Windows Form as describe in the table Controls RichTextBox (1) Things to be changed Text = null Design Name = EaglesText
Text = Select Font Design Name = btnselectfont Design Name = default ShowColor = True
762
4. Now double click the Select Font button and the add the following code: private void btnselectfont_Click(object sender, EventArgs e) { if (fontDialog1.ShowDialog() == DialogResult.OK) { EaglesText.Font = fontDialog1.Font; EaglesText.ForeColor = fontDialog1.Color; } }
763
5. Now run the application and Enter the text and the press the select font button and the select font text and size and color and then press ok button when I did this I got the following output:
Printing Documents
The way you print documents in Visual C# has become fairly involved, revolving, around the PrintDocument class. You add an object of this class to a project, and then handle events, like PrintPage, which is called every time a new page is to be printed. When it is added to the form, the PrintDocument component appears in the tray at the bottom of the Windows Form designer. You re responsible for handling the printing yourself, you have passed a Graphics object, and you use the methods of that object, like DrawString, which draws strings of text, to draw the document you want to print. Because this Graphics object corresponds to the printer, what you draw with it will appear in the printer. In the following Examples you see on this topic print out a single page, so we ll make it a point here to show how you handle mucilage documents as well. In this case, our example, called Eagles Printing in designed to print out two pages, one with the red
764
rectangle, and one with the blue rectangle. You will find Print, Print Preview, and Page Setup menu items in that example file menu. Besides PrintDocuments objects, there are a number of dialog boxes you use to support printing. The first of these dialog boxes Is the Print dialog itself.
Print Dialogs
Print dialog let the user print documents, and these dialogs are supported with the PrintDialog Class. Before displaying a Print dialog, you set the Document property of a print dialog object to a PrintDocument object, and the PrinterSettings property to a PrinterSettings object of the kind set by page setup dialogs. When the dialog is closed, you can print the document by assigning the PrintDialog objects PrinterSettings property to the PrinterSettings property of the PrintDocument object and use the PrintDocument object Print method to actually print the document. Here I have shown the code that might look: private void btnPrint_Click(object sender, EventArgs e) { printDialog1.Document = printDocument1; printDialog1.PrinterSettings = printDocument1.PrinterSettings; printDialog1.AllowSomePages = true; if (printDialog1.ShowDialog() == DialogResult.OK) { printDocument1.PrinterSettings = printDialog1.PrinterSettings; printDocument1.Print(); } } You can see a print dialog in the below picture:
765
766
The dialogs major property is Document, which sets the document to be preview, and the document must be a Print Document object. There not much else to do here this dialog simply displays the document as it will be printed. Print preview dialogs are based on the Print Preview Control object, any you can set some of the properties of that control directly, such as the columns and rows properties with Print PreviewDialog1.PrintPreview Control.Rows You can also use PrintPreviewControl objects directly to create you own custom print preview dialog boxes.
767
You can use the Printer Settings property of this dialog box to get a PrinterSettings object that holds the setting that the user has specified, and assign that object to a PrintDocument objects PrinterSettings property to make sure that the settings the user wants are assigned to the document itself. I have shown the code below that it might look: private void button3_Click(object sender, EventArgs e) { pageSetupDialog1.Document = printDocument1; pageSetupDialog1.PrinterSettings = printDocument1.PrinterSettings; pageSetupDialog1.PageSettings = printDocument1.DefaultPageSettings; if (pageSetupDialog1.ShowDialog () == DialogResult.OK ) { printDocument1.PrinterSettings = pageSetupDialog1.PrinterSettings ; printDocument1.DefaultPageSettings = pageSetupDialog1.PageSettings ; } }
768
Document Name
PrinterSettings
The following table shows the public method of the PrintDocument objects: Name Print Description It prints the document
The following Table shows the public events of the PrintDocument objects: Name Being Print End Print PrintPage QueryPageSettings Description It happens when the Print method is called to start a print job. It happens when the last page of the document has printed It happens for each to print you draw the page in this events handler It happens before each Print Page event.
The following table shows the static and shared properties of the PrinterSettings Name Description It return the name of all printers Installed Prints installed on the computer
769
The following table shows the public properties of the PrinterSettings objects: Name Can Duplex Collate Copies Default Page Settings Duplex From Page IsPlotter IsValid Landscape Copies Maximum Copies Maximum Page Paper Sizes Paper Sources Paper name Printer Resolutions Print Range Print to File Supports Color To Page Description True if the printer supports double sided printing. It obtains weather the printed document is colleted It obtains the number of the document to print It obtains the default page setting for this printer It obtains the printer setting for double sided printing It obtains the page number of the first page to print It return whether the printer is a plotter It returns whether the Printer name property designates a valid printer It holds the angel, in degrees, used for landscape orientation It holds the maximum number of copies that the printer allows you to print at one time. It obtains the maximum From Page to TO Page that can be selected in a Print Dialog It holds the paper size that are supported by this printer It holds the paper source trays that are available on the printer. it obtains the name of the printer to use It obtains the resolutions supported by this printer T obtains the page number to print, as specified by the user It obtains whether this printer supports color printing. It returns whether this printer supports color printing It obtains the number of the last
770
page to print. The following table shows the public methods of the Printer Settings Name Create Measurement Graphics Clone Description Obtains a Graphics object that contains printer information Create a copy of this PrinterSettings.
The following table shows the public methods of the PrintDialog objects: Name Reset ShowDialog Description It resets all dialog options It shows the dialog
771
The following table shows the events of the Print Dialog Objects: Name Help Request Description It occurs when the value the user click the Help button
The following table show the public property of the Print Preview Dialog objects: Name Accept Button Description It obtains the button is automatically clicked when the user presses the Enter Key It obtains whether a control box is displayed in the caption bar of the form It obtains the document to preview It obtains the border style of the form It obtains whether a Help Button should be displayed in the caption box of the form. It obtains whether the Maximize button is displayed in the caption bar of the form It obtains the maximum size of the form can be resized to. It obtains whether the minimize button is displayed in the caption bar of the form. It obtains the Print Preview Control contained in this form It obtains wether the form is displayed in the Windows taskbar It obtains the size of the form It obtains the starting position of the form at run time. It obtains whether the form should be displayed as your applications the topmost form.
Control Box Document Form Border Style Help Button Maximize Box Maximum Size Minimum Size Print Preview Control Show in Task Bar Size Start Position TopMost
772
Allow Orientation Allow Paper Allow Printer Document Min Margins Page Settings PrinterSettings Show Help
773
Show Network
The following table shows the public event of the page setup dialog class:
Example Try it out Eagles Printing Step by Step Example: Using Version 2005
1. Create a new Windows Application and name it as Eagles Printing C:\EaglesVisualCSharp\Chapter 16\Example Using Print 2. Add a second form to the project and leave the default name Form2.cs 3. Add the following Controls in the Form1.cs[Design] as illustrated in the below table Control Button Button Button Button PrintDialog1 PrintDocument PrintPreviewDialog1 PageSetupDialog1 Things to Be changed Text = Page Setup... Design name = btnpagesetup Text = Print Preview... Design Name = btnprintpreview Text = Custom Print Preview... Design Name = btnCutomPrint Text = Print Design Name = btnPrint Design Name = default Design Name = default Design Name = default Design Name = default
774
5. Now double click the Page setup button and the add the following code:
private void btnpagesetup_Click(object sender, EventArgs e) { pageSetupDialog1.Document = printDocument1; pageSetupDialog1.PrinterSettings = printDocument1.PrinterSettings; pageSetupDialog1.PageSettings = printDocument1.DefaultPageSettings; if (pageSetupDialog1.ShowDialog() == DialogResult.OK) { printDocument1.PrinterSettings = pageSetupDialog1.PrinterSettings; printDocument1.DefaultPageSettings = pageSetupDialog1.PageSettings; } }
775
6. Now double click the print preview button and the add the following code : private void btnprintpreview_Click(object sender, EventArgs e) { printPreviewDialog1.Document = printDocument1; printPreviewDialog1.ShowDialog(); }
7. Now double click the Custom print button and the add the following code : private void btnCutomPrint_Click(object sender, EventArgs e) { printPreviewControl1.Show(); }
8. Now double click the Print button and the add the following code :
private void btnprint_Click(object sender, EventArgs e) { printDialog1.Document = printDocument1; printDialog1.PrinterSettings = printDocument1.PrinterSettings; printDialog1.AllowSomePages = true; if (printDialog1.ShowDialog () == DialogResult.OK) { printDocument1.PrinterSettings = printDialog1.PrinterSettings; printDocument1.Print(); } }
776
9. Now run the application and you should see the following output after getting this output try to click the buttons on the application:
Summary
In this chapter we have been look almost the control in the .NET framework and the user control as well and the common dialogs also the use of the dialog in the applications. We looked at how to open and to save files, and after reviewing the .NET framework printing classes, we showed you how to add printing capabilities to your applications.
777
Chapter 17
778
Deploying an Application
17.0 Introduction to Deploying an Application
Now that the application works, how do you deploy it? The good news is that in .NET there is no Registry to to-do with; you could, in fact, just copy the assembly to a new machine. One of the big features of .NET is that installation can often be done by using the simple XCOPY. In .NET assemblies simply consist of number of files, and registry is no longer needed to store assembly configuration, so copying files can often be enough to install an application. You will soon, come to find some good reasons not use XCOPY for installing Windows Application for the deployment of Windows application XCOPY should be used only for the simplest applications. With small applications that are only installed on a few systems, XCOP can do a good job, but for bigger application or applications or applications that are installed to a lot of systems we have to think about a better installation mechanism. XCOPY does not register or verify assembly locations and it cannot take advantage of Windows Installer Zero Administration Windows ZAW features, which means that files can be overwritten unintentionally, and theres no built in uninstall. DENOTE: The system32 folder files it can be overwritten using this ZAW Microsofts Zero Administration facilities the job of the system administration to update and to install applications automatically on client systems, and to do central administration of applications.
779
Visualize here the idea of the solution gets articulated Planning is mainly used to analyze and design the solution Developing most of the development takes place Become Stable is where no more new feature are introduced, but instead bugs are fixed and beta and finally release version of the softwares or the products are sent to the customers site or to CD.
Between these four stages you can see the three major milestones but these major milestones doesnt finalize a sequence as with todays application development, the customers goal can often change, and in a later process stage you can detect that some parts doesnt work as expected. Thus developing can also happen to the planning stages to get some prototypes to work, and design can still change in the development phase.
780
Visual Studio provides extensive help for deployment. The process is to add a Setup and Deployment project to your application project. For example, assuming you are in the EaglesFileCopier project, choose Add Project, New Project from the File menu and choose Setup and Deployment Projects. You should see the dialog box shown in the following Picture
You have a variety of choices here. For a Windows project such as this one, your choices include: Cab Project Merge Module Project Setup Project Setup Wizard Remote Deploy Wizard Web Setup Project
781
Example Try it out EaglesFileCopier Step by Step Example: Using Version 2005
1. Select New project and the select the Other Project Types and the select the Setup and Deployment and the select the CAB Project and name it as EaglesFileCopier in the directory C:\EaglesVisualCSharp\Chapter 17\Example Using The Cab project 2. And then click OK button and you will see in the Solution Explore the project had been added as I have been shown in the following screenshot:
782
3. Now right click the Solution Explorer and the select the Add the then Existing Project as shown in the following picture:
4. I have added the Existing Project which we used to create an example program named as Eagles CreatingButton. Or you can add any kind of the project after you add you should see the changes in the Solution Explorer as I have got this:
All Rights Reserved To EaglesGroup
783
5. Right-clicking the project brings up a context menu. Choose Add, and you have two choices: Project Output . . . and File. ... The former offers a menu of its own, as shown in the following picture:
784
6. And you choose the Project output menu and you will see the following as I have shown in the following picture: Here you can choose to add sets of files to your Cab collection. The Primary output is the target assembly for the selected project. The other files are optional elements of the selected project that you might or might not want to distribute.
7. In this case, select Primary output. The choice is reflected in the Solution Explorer, as shown in the following picture:
785
8. You can now build this project, and the result is a .cab file sees the Visual Studio Output window to find out where the .cab was created. But easily you find it in the following path (C:\EaglesVisualCSharp\Chapter 17\Example Using The Cab project\EaglesFileCopier\EaglesFileCopier\Debug) if had created as what weve say in the first point. 9. After you find the file open the .Cab file and the run the file you will see the Eagles CreatingButton.exe and just run it 10. If you do not have WinZip, you can use the expand utility -D lists the contents of a .cab file this option is inbuilt feature of the Microsoft Windows the following screenshot will show you the method:
11. You see the executable file you expect, along with another file, OSD30.OSD this name of this file may vary. Opening this file reveals that it is an XML description of the .cab file itself, as shown in following screenshot:
786
Example Try it out EaglesFileCopierSetup Step by Step Example: Using Version 2005
1. Right-click the project and select Add, you see additional options in the pop-up menu. In addition to Project Output and File, you now find Merge Module and Component. 2. As you did with the Cab project, use the Add option to add the Primary output to the Setup Project. 3. Merge Modules are mix-and-match pieces that can later be added to a full Setup project. 4. Component allows you to add .NET components that your distribution might need but which might not be on the target machine.
All Rights Reserved To EaglesGroup
787
5. The user interface for customizing Setup consists of a split pane whose contents are determined by the View menu. Access the View menu by right-clicking the project itself, as shown in the following picture:
6. As you make selections from the View menu, the panes in the IDE change to reflect your choices and to offer you options. 7. If you choose File System, the IDE opens a split-pane viewer, with a directory tree on the left and the details on the right. Clicking the Application Folder shows the file you've already added the Primary output, as shown in the following screenshot:
788
8. You are free to add or delete files. Right-clicking in the detail window brings up a context menu, as shown in the following picture: You can see there is great flexibility here to add precisely those files you want.
789
You can easily modify these properties. For example, you can modify the property Manufacturer to change the folder in which the product will be stored under Program Files.
790
791
Here you can add folders for fonts, add items to the User's Favorites Folder, and so forth. Most of these are self-explanatory.
792
793
DENOTE: Careful! There is nothing more dangerous than touching the Registry. In most .NET applications this will not be needed, because .NETmanaged applications do not use the Registry. The very first time I got my computer screw-up by changing the registry. I am not telling you to make changes in the registry if you are Pro sure you can do as I got learn after I got my computer screwed up.
When you click a step in the process, the properties for that form are displayed. For example, clicking the Welcome form under Install, Start displays the properties shown in the following screenshot
794
The properties offer you the opportunity to change the Banner Bitmap and the text displayed in the opening dialog box. You can add dialog boxes that Microsoft provides, or import your own dialog boxes into the process.
795
If an application gets corrupted, the application can self repair by using the repair features of Windows Installer packages. An automatic rollback will be done if the installation fails. After the installation fails everything is left as before: no additional Registry Keys, no files, etc. are left on the system. With an uninstall, all the relevant files, Registry keys, etc. are removed the application can be completely uninstalled. No temporary files are left out, and the Registry is also reinstated. By reading the tables of the MSI database files it possible to get the information about such things as what files are copied, and what the registry keys are written.
Summary
In this chapter we have covered the functionality of the Windows Installer and how to create Installer packages using the Visual Studio.NET the windows Installer it easy to do standardized installations, uninstalls, and repairs. When developing Windows Applications, the best way is to build a Windows Installer package, and with Visual Studio.NET this can easily be done.
796
Chapter 18
797
Web Services
18.1 Overview of Web Services
NET Web Services help you write components whose methods can be invoked across the Internet using any .NET programming language. Developers who are creating web services can build one upon another, taking advantage of the connectivity that is at the heart of the Web. Adding value takes precedence over reinventing the wheel. The list of web services that might be useful to developers and end users seems boundless. A bookstore might provide a web service that takes an ISBN and returns the price and availability of a title. A hotel's web service might take a date range and number of guests and return a reservation. Another web service might take a telephone number and return a name and address. Yet another might provide information about the weather or shuttle launches. Microsoft has announced a number of commercial .NET services as part of its .NET My Services initiative. Among these are its Passport service for identifying and authenticating users (see http://www.passport.com), as well as services for managing storage, notification, appointments, and a host of other applications. These services, as well as the ones you write, can be integrated with your applications just like any other business object. In such a world, a single application might draw on and stitch together the services of hundreds of small web services distributed all over the world. This takes the Web to an entirely new dimension: not only is information retrieved and exchanged, but also methods are invoked and applications are executed.
798
others. Two other protocols have been proposed for discovery: UDDI, a joint effort by a number of companies including IBM and Microsoft, and Discovery, a proprietary offering from Microsoft. WSDL is an XML schema used to describe the available methodsthe interfaceof a web service. Discovery enables applications to locate and interrogate web service descriptions, a preliminary step for accessing a web service. It is through the discovery process that web service clients learn that a service exists, what its capabilities are, and how to properly interact with it. A Discovery (.disco) file provides information to help browsers determine the URLs at any web site at which web services are available. When a server receives a request for a .disco file, it generates a list of some or all of the URLs at that site that provide web services.
799
Visual Studio .NET creates a skeleton web service and even provides a Web Service example method for you to replace with your own code, as shown in The following example below: using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; [WebService(Namespace = "http://eaglesgroupcom/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class Service : System.Web.Services.WebService { public Service () { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod] // public string HelloWorld() // { // return "Hello World"; // } public double Add(double x, double y) { return x + y; } [WebMethod] public double Sub(double x, double y) { return x - y; } [WebMethod] public double Mult(double x, double y) { return x * y; }
800
[WebMethod] public double Div(double x, double y) { return x / y; } [WebMethod] public double Pow(double x, double y) { double retVal = x; for (int i = 0; i < y - 1; i++) { retVal *= x; } return retVal; } }
Create five methods: Add( ) Sub( ), Mult( ), Div( ), and Pow( ). Each takes two parameters of type double, performs the requested operation, and then returns a value of the same type. For example, here is the code for raising a number to some specified power:
public double Pow(double x, double y) { double retVal = x; for (int i = 0;i < y-1;i++) { retVal *= x; } return retVal; }
801
To expose each method as a web service, you simply add the [WebMethod] attribute before each method declaration:
[WebMethod] You are not required to expose all the methods of your class as web services. You can pick and choose, adding the [WebMethod] attribute only to those methods you want to expose. That's all you need to do; .NET takes care of the rest.
802
Clicking a method brings you to a page that describes the method and allows you to invoke it by typing in parameters and pressing the Invoke button. The following picture illustrates.
803
If you type 3 into the first value field and 7 into the second field, you will have asked the web service to add. The result is an XML page describing the output, as shown in the following picture
804
805
The details of the WSDL document are beyond the scope of this book, but you can see that each method is fully described in a structured XML format. This is the information used by SOAP to allow the client browser to invoke your web service methods on the server.
806
Chapter 19
807
Overview of ADO.NET
19.0 Overview of ADO.NET
Most applications require some kind of data access. Desktop applications need to integrate with central databases, Extensible Markup Language (XML) data stores, or local desktop databases. ADO.NET data-access technology allows simple, powerful data access while maximizing system resource usage.
ADO.NET addresses these issues by implementing a disconnected data access model by default. In this model, data connections are established and left open only long enough to perform the requisite action. For example, if an application requests data from a database, the connection opens just long enough to load the data into the application, and then it closes. Likewise, if a database is updated, the connection opens to execute the UPDATE command, and then closes again. By keeping connections open only for the minimum required time, ADO.NET conserves system resources and allows data access to scale up with a minimal impact on performance.
808
Data access in ADO.NET relies on two entities: the DataSet, which stores data on the local machine, and the Data Provider, a set of components that mediates interaction between the program and the database.
809
Data access in ADO.NET is facilitated as follows: a Connection object establishes a connection between the application and the database. This connection can be accessed directly by a Command object or by a DataAdapter object. The Command object provides direct execution of a command to the database. If the command returns more than a single value, the Command object returns a DataReader to provide the data. This data can be directly processed by application logic. Alternatively, you can use the DataAdapter to fill a DataSet object. Updates to the database can be achieved through the Command object or through the DataAdapter. The generic classes that make up the data providers are summarized in the following sections.
810
well as an OracleConnection class optimized for connecting to Oracle databases. The Connection object contains all of the information required to open a channel to the database in the ConnectionString property. The Connection object also incorporates methods that facilitate data transactions.
811
InsertCommand.
DeleteCommand. UpdateCommand.
When the Update method is called, changes in the DataSet are copied back to the database, and the appropriate InsertCommand, DeleteCommand, or UpdateCommand is executed.
812
Summary
ADO.NET is a data-access technology that is primarily disconnected and designed to provide efficient, scalable data access. Data is represented within a DataSet object, which is a disconnected, in-memory copy of part or all of a database. A data provider is a set of classes that provide access to databases. The main components of data providers are: Connection Command DataReader DataAdapter
813
Chapter 20
814
GDI +
20.1 Introduction to GDI +
In this chapter, we will have a real introduction to programming using the Graphics Device Interface classes (GDI+), the drawing technology of the .NET Framework. Mapping applications, games, Computer Aided Design / Computer Aided Manufacture (CDA/CAM), drawing programs, charting programs, and many other types of applications requires developers to write graphics code for their Windows Form applications. Writing custom controls can also require graphics code. With this latest class library, Microsoft has made writing graphics code easier that it ever has been before.
In VB6 and before, for example, graphics support was spread throughout, and you could use the graphics methods of forms and pictures boxes as needed. But now with the Visual C# 2003 and 2005, similar to Java, the graphics capability has been lumped together into huge classes, primarily the Graphics Class. This, among other things, means that the cherished AutoRedraw property of forms, which made redraw them if needed as and when theyre uncovered or restored after being minimized has been stripped out of Visual C# entirely. This is turn, means that redrawing forms is all you again. Writing graphics code is one of the most enjoyable programming tasks. Is very rewarding to change your code and see the results in a visible from immediately. Whether you are writing a custom graphics window that presents something in your applications in a new and different way, or writing a custom control that makes your application more stylish and more useable, your application will be well received by general public.
First, we will look the mechanics of drawing using the GDI+, and write simple graphics example programs. Then we go to the high level of extensive capabilities of GDI+ such as clipping. After the overview on each of the above topics, well look at what class we are using to implement the features. Knowing what we can do and understanding the class purpose is half the battle.
815
816
PathGradient Brush Solid Brush Texture Brush DENOTE: As with the Pen Class, there are number of predefined solid color brushes in the Brush class.
20.4 Imagining
Imagine trying to draw the kind of picture you see in digital photographs or even icons with vector graphics you could do it, but assembling such images from lines and curves would be just about impossible. Instead, you store those kinds of images are bitmaps, which are simple arrays of points corresponding to pixels of the screen. In other words, bitmaps store the actual pixel setting needed to display the corresponding image. Handling and working with such bitmaps, is actually more complex working with vector graphics, so GDI+ supports the Bitmaps Class, with all kinds of built in methods to display and handle the images.
20.5 Typography
Typography is all about displaying text. GDI+ has a lot of support for typography, allowing you to display text in different fonts, sizes, and styles such as italic and bold, and colors. The typography supported by GDI+ also supports a technique called antialiasing, which makes text appear smoother on the screen, avoiding the jagged edges of text that used to typical in the early days of personal computing.
817
writing a custom control, we will declare a class that derives from System.Windows.Forms.UserControl. In either of these classes, we override the virtual function OnPaint (). Windows will call this function whenever any portion of our window needs to be repainted. With this event, a PaintEvetnArgs class is passed as an argument. There are two pertinent pieces of information in PaintEvetnArgs: a Graphics object, and ClipRectangle. Well explore the Graphics class now. Well touch on clipping near the end of the chapter.
As in Java, the Graphics class is a large class, with many methods available to use. Now that we are working with the Graphics Class explicitly, well take an example to see how to draw and fill figures by using methods of Graphics Class. The Graphics Class encapsulation a GDI+ drawing surface. There are three basic types of drawing surfaces they are as follows: Windows and Controls on the Screen Pages begin sent to a printer Bitmaps and images in memory.
The Graphics class provides us with function so that we can draw on any of these drawing surfaces. Among other capabilities, we can use it to draw arcs, curves, Bezier curves, ellipse, images, lines, rectangle, and text.
We can get a Graphical Object for the Window in two different ways. The first is to override the OnPaint () method. The Form Class inherits the OnPaint () method from Control and this method is the event handler for the Paint event that is raised whenever the control is redrawn. We can get the Graphics object from the PaintEvetnArgs that is in with the event: protected override void OnPaint (PaintEvetnArgs e) { Graphics g = e.Graphics; // here we apply the code for the drawing }
818
At other times, we may want to draw directly into our window without waiting for the Paint event to be raised. This would be the case if we are writing code for selecting some graphical object on the window similar to selecting icons in Windows Explorer. Or by dragging some object with the mouse. We can get a Graphics object by calling the CreateGraphics () method on the form, which is another method that From, which is another method that Form inherits from Control: protected void Form1_Click (object sender, System.EventArgs e) { Graphics Siddhu = this.CreateGraphics (); Siddhu.Dispose (); // this is more important }
Building an application that handles drawing and drooping to a somewhat involved affair, and is beyond the scope of this chapter. In any case, this is a less common technique. Primarily, we will do almost all of our drawing in response to an OnPaint () method. The following table shows the Public Class shard methods of the Graphics Objects Name FromHwnd FromImage Description It returns a new Graphics object from the specified handle to the Window. It returns a new Graphic object by a given Image object.
The following table shows the public Property of the Graphics Objects Name Clip DpiX DpiY IsClipEmpty PixelOffsetMode SmoothingMode Description It holds the drawing region of the Graphics Objects It holds the horizontal resolution of the Graphics object. It holds the vertical resolution of the Graphics object. Its true if the clip region is empty It indicates how pixel are offset when drawn, affecting both drawing quality and speed. It obtains the quality for rendering with the Graphics object
819
The following table shows the public Methods of the Graphics Objects Name Clear Dispose DrawArc DrawBezier DrawBeziers DrawClosedCurve DrawCurve DrawEllipse DrawIcon DrawInconUnstratched DrawImage DrawImageUnscaled DrawLine DrawLines DrawPath DrawPie DrawPolygon DrawRectangle DrawString FillClosedCurve FillEllipse FillPath FillPie FillPolygon FillRectangle FillRectangles FillRegion GetHdc Description It Clears the drawing surface, filling it with the background color. It deletes and deallocates the Graphics Object It Draw an arc It Draw an Bezier Curve It draws a Bezier Curves It Draws a closed curve It draws an curve It draws an ellipse It draws an icon It draws an icon without scaling the icon. It draws an image It draws an image without scaling the image It draws a line. It draws a series of line. It draws a GraphicsPath It draws a pie section It draws a polygon It draws a rectangle It draws a text string It fills a closed curve It fills an ellipse It fill the inside of a path It fills a pie section It fills a polygon It fills a rectangle It fills rectangles It fills the inside of a region It obtains Windows Device context handle for this Graphics object. It obtains the nearest color to a given color. It obtains the length of a string to display It saves this object as a GraphicsState object It sets the clipping region.
820
A using construct automatically calls Dispose () method when an object goes out of scope. This following code shows the correct use of the using Keyword in this context:
using (Graphics Siddhu = this.CreateGraphics ()) { Siddhu.DrewLine (Pens.Black, new Point (0, 0), new Point (4, 5)); }
821
According to the documentation the above code is precisely equivalent to : Graphics Siddhu = this.CreateGraphics (); try { Siddhu.DrawLine (Pens.Black, new Point (0, 0), new Point (4, 5,)); } finally { If (Siddhu! = null) ((IDisposable) Siddhu).Dispose (); }
822
we draw a horizontal line that is one pixel wide from point 1, 1 to point 5, 1 the following pixel will be drawn as shown in the below picture:
When we draw a vertical line that is one pixel wide and four pixel long, from point 2, 1 to point 2, 4 following pixels will be colored in gray:
When we draw a diagonal line form point 1, 0 point 5, 4 the following pixels will be drawn as shown in the following picture:
823
When we draw a rectangle with the upper left corner at 1, 0 and a size of 4,3 the rectangle will be drawn as in the following picture:
There is something interesting to note here. We specified a width of 4, and there are 5 pixels drawn in the horizontal direction, if you consider the mathematical lines running the pixel, this rectangle is only four pixels wide, and the line drawn falls half a pixel outside and half a pixel inside of mathematical line that we specified.
824
There is more to the scenario that this, if we draw with anti aliasing, other pixels will be half colored in, creating an appearance of a smooth line, and partially avoiding a stair step appearance to diagonal lines. Here is a line drawn without anti aliasing:
The same line drawn with anti aliasing appears as follows in the picture:
Understanding the relationship between the coordinates passed to drawing functions, and the resulting effect on the drawing surface makes it easy to visualize exactly which pixels will get affected by a given call to a drawing function. There are three structs that we will use often to specify coordinates when drawing Point, Size, and Rectangle.
20.10 Point
GDI+ uses Point to represent a single point with integer coordinates. This is a point in a two dimensional plane a specification of a single pixel. Many GDI+ functions, such as DrawLine (), take a Point as an argument. We declare and construct a Point struct as follows: Point sri = new Point (1, 1); There are public properties, X and Y, to get and set the X and Y coordinates of a point.
20.11 Size
GDI+ uses Sizes to represent a size in pixel. A size struct contains both width and height. We declare and construct a Size as follows:
825
Size sri = new Size (5, 5); There are public properties, Height and Width, to get and set the height and width of a Size.
20.12 Rectangle
GDI+ uses this structure in many different places to specify the coordinates of a rectangle. A Point structure defines the upper left corner of the rectangle and a Size structure defines its size. There are two constructors for Rectangle. One takes an argument the X position, the Y position, the width, and the height. The other takes a Point and a Size structure. Two examples of declaring and constructing a Rectangle are as follows: Rectangle Siddhu = new Rectangle (1, 2 5, 6); Point p = new Point (1, 2); Size sri = new Size (5, 6); Rectangle siddhu1 = new Rectangle (p, sri); There are public properties to get and set all aspects of the location and size of a Rectangle. In addition, there are other useful properties and methods to do such activities as determining if the rectangle intersects another rectangle, taking the intersection of two rectangles, and taking the union of two rectangles.
826
First we will be Using Visual2003 and 2005 we are using the same folder but the DENOTE: For both the Studio 2003 Version: version name will be indicated in each folder as you can see in the CD which has made available along with this book. Enjoy Programming. Example Try it out Eagles GraphicsPath
827
4. Run the application, and you should see the following path drawn :
Example Try it out Eagles GraphicsPath Step by Step Example: in version 2005
1. Create a new Windows application called Eagles DrawingPaths in the directory C:\EaglesVisualCSharp\Chapter 20. 2. Add the following using directive for System.Drawing.Drawing2D to the top of the code: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Drawing.Drawing2D;
828
4. Run the Application and you should see something like this:
829
Now lets see how the above program runs and works The code to construct this path is a quite complex. The constructor for GraphicsPath takes two arguments. The first argument is a Point array; here we use the C# syntax for declaring and initializing the array in the same place, and create each new Point object as we go: new Point[] { new Point (30, 30 ), new Point (200, 20), new Point (250,300), new Point (30, 175), new Point (250, 160)},
The Second argument is an array of bytes that we also construct right in place: new byte[] {(byte) PathPointType.Start, (byte) PathPointType.Line, (byte) PathPointType.Line, (byte) PathPointType.Line , (byte) PathPointType.Line }); Finally, we call the DrawPath () method: e.Graphics.DrawPath (Pens.Black , path);
As you can see in the version 2005 when you created the protected function you have automatically added the following code to your form base.OnPaint(e);
20.14 Regions
The regions class is a complex graphics shape is comprised of rectangle and paths. After constructing a Region. We can draw that region using the method FillRegion ().
830
Example Try it out Eagles Region Step by Step Example: in version 2005
1. Create a new Windows application called Eagles DrawingRegions in the directory C:\EaglesVisualCSharp\Chapter 20. 2. Add a using directive for System.Drawing.Drawing2D to the top of the code as we did it for last example: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
3. Enter the following code into the body of Form1.cs protected override void OnPaint(PaintEventArgs siddhu) { Rectangle r1 = new Rectangle(10, 10, 50, 50); Rectangle r2 = new Rectangle(40, 40, 50, 50); Region r = new Region(r1); r.Union(r2); GraphicsPath path = new GraphicsPath (new Point [] { new Point (45, 45), new Point (145, 55), new Point (200, 150), new Point (75, 150), new Point (45, 45) }, new byte [] { (byte ) PathPointType.Start , (byte ) PathPointType.Bezier , (byte ) PathPointType.Bezier , (byte ) PathPointType .Bezier , (byte ) PathPointType.Line }); r.Union(path); siddhu.Graphics.FillRegion(Brushes.Black, r); base.OnPaint(siddhu); }
All Rights Reserved To EaglesGroup
831
Now lets see how the above program runs and works The code to construct a region is also require complex, though the most complex part of our example is constructing any path that will go into the region, and you have already see how to construct these from the previous example. Constructing regions consists of constructing rectangle and paths, before calling the Union () method. If we desired the intersection of a rectangle and a path, we could have used the Intersection () method instead of the Union () method. Further information on paths and regions is not particularly needed for an introduction to GDI+, so we will not explore them in any more depth in this chapter.
Colors
As we can use many of the drawing operation in GDI+ involve a color. When drawing a line or rectangle, we will need to specify what color it should be.
In GDI+, colors are encapsulated in the Color structure. We can create a color by passing red, green, and blue values to a function of the Color structure, but this is almost never necessary. The color structure contains approximately 150 properties that get a large variety of present colors. Forget about red, green, blue, yellow and blue if we need to do some drawing in the color of LightGoldenrodYellow or LavenderBlush, there is a predefined color made just for us! We declare a variable of type Color and initialize it with a color from the Color structure as follows:
All Rights Reserved To EaglesGroup
832
Were almost ready to do some drawing, but a couple of notes before we go deep: DENOTE: Another way to represent a color is to break it down into three components: Hue, Saturation, and Brightness. The Color structure contains utility methods to do this, namely: Getbrightness (); GetHue (), and GetSaturation ().
You can use the ColorDialog to experiment with colors. In a new Windows application, drag a ColorDialog control onto your form, and add the following line to the Form1 constructors, after the IntializeComponent () call: this.colorDialog1.ShowDialog (); Now run the application, and click the Define Custom button. You will see a dialog box that allows you to pick a color using the mouse and see the RBG values for the color. You can also get the Hue, Saturation, and Luminosity values for the color, but when the Luminosity corresponds to Brightness. You can also directly enter the RGB values and see the resulting color.
Colors in GDI+ have a fourth component, the Alpha Component. Using this component, we can set the capacity of the color, and this allows us the create fade in / fade out effects, such as the menu effects in Windows 2000 and Windows XP. Using the Alpha component is beyond the scope of this chapter.
833
The following table shows the pubic properties of the Pen objects. Name Alignment Brush Color CompoundArry CustomEndCap CustomStartCap DashCap DashOffset DashPattern DashStyle EndCap LineJoin PenType StartCap Width Description It obtains the alignment for drawing objects It obtains the brush object of this Pen It obtains the Pens color It obtains an array of dashes and spaces to configure a Pen It obtains the cap style used at the end of the line. It obtains the cap style used at the beginning of the line. It obtains the cap style used at the beginning or end of dashed lines. It obtains the length from the beginning of the line to the beginning of a dash pattern It obtains an array of dashes and spaces It obtains the style used for dashed lines It obtains the cap style used at the end of the lines. It obtains the style used to join the ends of overlapping lines It gets the style of lines this Pen draws It obtains the cap style used at the beginning of lines It obtains the width of this Pen in pixel.
The following table shows the public methods of the Pen Object Name Clone Dispose SetLineCap Description It creates a copy of this Pen It deallocates and Dispose of this Pen It sets the style of cap used to end lines.
834
Example Try it out Eagles Using Pen Class Step by Step Example: in version 2005
1. Create a new Windows Application called Eagles DrawingLines in the Directory C:\EaglesVisualCSharp\Chapter 20 2. Enter the Following code into the body of Form1.cs
protected override void OnPaint(PaintEventArgs sri) { Graphics siddhu = sri.Graphics; using (Pen GreenPen = new Pen (Color.Green , 1)) // the 1 indicates the thichness of the line { if (ClientSize.Height / 30 > 0) // ClientSize.Height //ClientRectangle { for (int y = 0; y < ClientSize.Height; y += ClientSize.Height / 30) { sri.Graphics.DrawLine (GreenPen, new Point (0,100), // this zero is the begin of the line and 100 is the center of the form new Point(ClientSize.Width, y)); } } } base.OnPaint(sri); }
3. Now run the Application, and you should see some thing like this:
835
Now lets see how the above program runs and works Earlier in the chapter, we introduced the Graphics class. The first thing that we do in the OnPaint () method is to get the Graphics object from the PaintEventArgs parameter: Graphics Siddhu = e.Graphics;
DENOTE: That because we are passed the reference to the Graphics object, and we did not create it, we do not need to manually call Dispose () on it. However, since we are using a potentially resources hungry Pen object for this example we have wrapped the rest of the code in a using block, as described earlier, which will ensure that the object is destroyed as soon as possible. When we construct the pen, we pass as parameters to the constructor a color and a width of the pen. In this example, the color is green, and the width is 1. This is the line of code to construct the pen: using (Pen GreenPen = new Pen (Color.Green, 1)) Every window into which we can draw has a client area, which is rectangle that exists within the border and defines the exact area into which we can draw. We can get the client area from ClientSize, which is public, read only property of the form inherited from Control. It contains the size that is the width and height of the client area of the window into which we are drawing. The following code starts a loop that goes from zero up to the height of the client area given ClientSize.Height in steps of 10, ClientSize.Height / 10 is bigger than zero without this, the loop will run indefinitely if the form is resized below a certain height, since ClientSize.Height / 10 is the loop increment, and if this is zero well loop forever. if (ClientSize.Height / 30 > 0) { for (int y = 0; y < ClientSize.Height; y += ClientSize.Height / 20)
Now we can draw the lines when we draw each line, we pass the Pen that we just created, along with the starting point and end of the line:
836
sri.Graphics.DrawLine (GreenPen, new Point (0,100), // this zero is the begin of the line and 100 is the center of the form new Point(ClientSize.Width, y));
Just as for Graphics objects, it is important to either call Dispose () on Pen objects when we are finished with them, or use the using block, otherwise our applications may deplete the Windows Resources. In this example, we constructed a Pen. However, there is an easier way to get a Pen. The Pen Class contains properties for getting approximately 150 pens, one for each of the pre defined colors that we learned about previously. The following version of the example works identically to the previous one, but instead of constructing a Pen, we get it from the Pen Class: protected override void OnPaint(PaintEventArgs sri) { Graphics siddhu = sri.Graphics; using (Pen GreenPen = new Pen (Color.Green , 1)) // the 1 indicates the thichness of the line { if (ClientSize.Height / 30 > 0) { for (int y = 0; y < ClientSize.Height; y += ClientSize.Height / 20) { sri.Graphics.DrawLine (GreenPen, new Point (0,100), // this zero is the begin of the line and 100 is the center of the form new Point(ClientSize.Width, y)); } } } base.OnPaint(sri); }
837
In this case, we did not create the Pen, so it is not necessary to call Dispose (). There are many more features of the Pen class. We could create a pen to draw a dashed line, ore we could create a pen with a width thicker that one pixel. There is an Alignment property of the Pen class that allows us to define whether the pen is draw to the left or right or even above or below of the line that we specify. By setting the StartCap and EndCap properties, we can specify that our lines are ended with an arrow, a diamond, a square, or rounded off. We can even program a custom start cap and end cap using the CustomStartCap and CustomEndCap properties. After learning about images, we will see how to specify a Brush with a Pen, so that we can draw the line using a bitmap instead of a solid color.
838
One more brush that we will mention is the PathGradientBrush, which creates an elaborate shading effect, where the shading runs from the center of the path to the edge of the path. This should remind us the childhood when we shape maps with colored pencils, making the color darker at the boundary between the different states and countries. DENOTE: Remember Always call Dispose () on Brush objects.
Just as for Graphics objects and Pen objects, it is important to call Dispose () on Brush object that we create, or use the using block, otherwise our application may deplete the Windows Recourses.
Example Try it out Eagles Using Brush Step by Step Example: in version 2005
1. Create a new Windows Application called Eagles UsingBrushes in the directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
3. In the constructor of the Form1.cs add a call to SetStyle () after the call to IntializeComponent () public Form1() { InitializeComponent(); SetStyle(ControlStyles.Opaque , true); }
839
5. Now run the application and you should see something like this:
840
Now lets see how the above program runs and works The first thing to remark about is the call to SetStyle () in the forms constructor. SetStyle () is a method of the Form Class: public Form1() { InitializeComponent(); SetStyle(ControlStyles.Opaque , true); }
This method, changes the behavior of the Form class, so that it will not automatically draw the background of the window. If we include this line, but we dont draw the background of the Window ourselves, then anything underneath the window at the time of creation would show through, which is not what we want. Thus our next activity is to draw our own background onto the client area of our window. Just as with the Pen Class, there is a Brushes Class that contains properties for getting about 150 brushes, one for each pre defined color. We use this class to get most of the brushes in this example, with the exception of the LinearGradientBrush which we create ourselves. The first call to FillRectangle () draw the background of the client area of our window:
siddhu.FillRectangle(Brushes.Brown , ClientRectangle);
The creation of the LinearGradientBrush takes a rectangle specifying the size of the rectangle, the two colors to be used for the gradient, and the angle, in this case 45: Brush linearGradientBrush = new LinearGradientBrush(new Rectangle(10, 60, 50, 50), Color.BlueViolet , Color.HotPink , 45); siddhu.FillRectangle(linearGradientBrush, new Rectangle(10, 60, 50, 50)); // The below code will manually call the Dispose () method. linearGradientBrush.Dispose();
841
When we specified the rectangle for the brush, we used a rectangle of width 50, and height 50, which is the same, size as the rectangle used when we defined the brush. The result of this is that the brush area just fits the rectangle used when we defined the brush. The result of this is that the brush area just fits the rectangle that we want filling in. Try changing the rectangle defined in the creation of the brush so that the width and height are 10 and see what happens. Also, try changing the angle to different the values to see the change in effect.
This means that we have an unprecedented flexibility in specifying the desired size of our font. One possible use for this might be if we are writing a text drawing routine needs to work in an acceptable way on very high resolution display, low radiation display, and printers. When drawing text, given a specific font, and given a specific surface, we often to known the width in pixel of a special string of text. It is pretty clear why different fonts will have an effect the width in pixel of a string a smaller font will result in a width of fewer pixel. However, it is equally as important to know the drawing surface, because the pixel resolutions of different drawing surfaces are different. Typically, the screen has 72 pixels per inch. Printers can be 300 pixels per inch, 600 pixels per inch, and sometimes even
842
more. We use the MeaseureString () method of the Graphics object to calculate the width of a string for a given font. The Font Style property refers to whether the type is italicized, emboldened, struck through, or underlined. DENOTE: Always call Dispose () on Font objects. It is important to call Dispose () on Font objects that we create, or use the using block, otherwise our application may deplete Windows Resources.
When drawing text, we use a Rectangle to specify the bounding coordinates of the text to be drawn. Typically, the height of this rectangle should be the height of the font or a multiple of the height of the font. This would be different when drawing some special effect using clipped text.
The StringFormat, class encapsulates text layout information, including alignment and line spacing.
Example Try it out Eagles Font Class Drawing Step by Step Example: in version 2005
1. Create a new Windows Application called Eagles DrawTex in the directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. In the constructer of the Form1.cs add a call to SetStyle () after the call to IntializeComponent (). We also change the bounds of the window to give us enough room to display the text that we want to display. The modified constructor is as follows: public Form1() { InitializeComponent(); SetStyle(ControlStyles.Opaque, true); Bounds = new Rectangle(0, 0, 600, 400); }
843
3. Now, add the following code on the OnPaint () method to Form1.cs: protected override void OnPaint(PaintEventArgs siddhu) { Graphics g = siddhu.Graphics; int y = 0; g.FillRectangle(Brushes.Tomato , ClientRectangle); // Draw left justified text Rectangle rect = new Rectangle(0, y, 500, Font.Height); g.DrawRectangle(Pens.Blue, rect); g.DrawString("Welcome to EaglesGroup" +" This is left justified" , Font, Brushes.Black, rect); y += Font.Height + 20;
844
// Now we Draw right justfied text Font aFont = new Font("Bodoni MT", 14, FontStyle.Bold | FontStyle.Italic); rect = new Rectangle(0, y, 500, aFont.Height); g.DrawRectangle(Pens.Blue, rect); StringFormat st = new StringFormat(); st.Alignment = StringAlignment.Far; g.DrawString("Welcome to EaglesGroup" + " This text is right justified", aFont, Brushes.Blue, rect, st); y += aFont.Height + 20; // Now we are manually call the Dispose () method aFont.Dispose(); // Now we Draw Centered Text Font cFont = new Font("Bodoni MT", 12, FontStyle.Underline); rect = new Rectangle(0, y, 500, cFont.Height); g.DrawRectangle(Pens.Blue, rect); st = new StringFormat(); st.Alignment = StringAlignment.Center; g.DrawString("Welcome to EaglesGroup" + " This text is Centered and underlined.", cFont, Brushes.White , rect, st); y += cFont.Height + 20; // Now we are calling the Dispose () method again cFont.Dispose(); // Now we draw multiline text Font mulFont = new Font("Bodoni MT", 12); rect = new Rectangle(0, y, 500, mulFont.Height * 3); g.DrawRectangle(Pens.Blue, rect); String longString = "EaglesGroup (C) 1978 - 2010"; longString += "All Rights Reserved to EaglesGroup"; longString += "EaglesS (R) "; longString += "Welcome to EaglesGroup"; g.DrawString(longString, mulFont, Brushes.Black, rect); // Now we are calling the Dispose () method again mulFont.Dispose(); base.OnPaint(siddhu); }
845
4. Now compile the code and run the application and it will create this window as shown below:
Now lets see how the above program runs and works This example contains a few of the most common text drawing operations. As usual, we assign a reference to the Graphics object to a local variable. When drawing the text, we calculate the bounding rectangle for our text. We get the height of the font using the Height property, when we draw the text, we apss the text, the font, a brush, and a bounding rectangle: Rectangle rect = new Rectangle(0, y, 500, Font.Height); g.DrawRectangle(Pens.Blue, rect); g.DrawString("Welcome to EaglesGroup" +" This is left justified" , Font, Brushes.Black, rect); y += Font.Height + 20; We only specify the rectangle in which the text will go. The baseline of a font is the imaginary line that most of the characters of the font be seated on. GDI+ and the font itself determine where the actual baseline will go we have no control over that. When we draw the text, we pass a brush to the DrawString () function. In this example, we only pass brushes that have a solid color. We could just as easily have passed other
846
types of brushes, such as a gradient brush. After we have introduced images in the next section, we will demonstrate drawing text using a TextureBrush. The first time that we draw text in this example, we use the default font for the form. This font is referenced in the Font property, which is inherited from Control. g.DrawString("Welcome to EaglesGroup" +" This is left justified" , Font, Brushes.Black, rect); The next time that we draw text in this example, we create a new instance of a Font: Font aFont = new Font("Bodoni MT", 14, FontStyle.Bold | FontStyle.Italic); This example also shows not only how to create a new instance of a font, but how to give it a style. In this case, the style is bold and italic. The example shows creating a StringFormat object, so that we can draw right justified and centered text. In GDI+, right justified text alignment is referred to as Far alignment. Left- justified text is Near alignment. StringFormat st = new StringFormat(); st.Alignment = StringAlignment.Far; Finally, we draw some multi line text. Using the GDI+, it could not be easier. All we need to do is to specify a rectangle where the width is less than the length of the string in pixels, and the height is sufficient to draw multiple lines. In this case, we made the height equal to three equal to three times the font height.
847
technique know as double buffering. Certain other graphics technique involves drawing in layer, where first we draw the background, then we draw objects on top of the background, and finally we draw some text on top of the objects. If this drawing is done directly to the screen, the user will see a flickering effect. Double buffering eliminates this flickering effect. Well take a look at a double buffering example a bit later. Image itself is an abstract class. There are two descendants of Image: Bitmap, and Metafile. The Bitmap class is a general purpose image, with height and width properties. Our examples in this section will use the Bitmap class. We will load a Bitmap image a file and draw it. We will also create a brush from it and use that brush to create a pen to draw line, and also use that brush to draw some text. Well take a look at Metafile class near the end of this chapter, when we are taking an overview of the advanced features of GDI+ DENOTE: Remember Always call Dispose () on Brush objects. It is important to call Dispose () method on Image objects that we create or use the using blocks; otherwise our application may deplete the Windows resources. There are several possible source of bitmap. We can load the bitmap from a file, or create the bitmap form another existing image, or it can be created as an empty image, onto which we can draw. When we read the image from a file, it can be .JPEG, .GIF, or .BMP format. The following is a very simple example to read an image form a file and draw it in a window:
Example Try it out Eagles Image Drawing Step by Step Example: in version 2005
1. Create a new Windows Application called Eagles ImageDrawing in the directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. First, we need to declare a private variable in our Form1.cs to hold the image after we read it form a file. After the declaration of the components variable, add the declaration of the Image as follows:
public partial class Form1 : Form { private Image theImage; public Form1() { InitializeComponent(); } }
848
3. Now modify the constructor so that it appears as follows: public Form1() { InitializeComponent(); SetStyle(ControlStyles.Opaque, true); theImage = new Bitmap ("C:/eagles.bmp"); } 4. Now, add the following code in the OnPaint () method to the Form1.cs protected override void OnPaint(PaintEventArgs siddhu) { Graphics g = siddhu.Graphics; g.DrawImage(theImage, ClientRectangle); base.OnPaint(siddhu); } 5. Last step, we need to dispose of the Image that is stored in a member variable of our class. Modify the Dispose () method of the Form1.Designer.cs class as follows: protected override void Dispose(bool disposing) { if (disposing && (components != null)) { theImage.Dispose(); components.Dispose(); } base.Dispose(disposing); }
849
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
7. Now run the application and you should see the window like this:
DENOTE: For the image which you are see in the application and in the window above as shown it will automatically load when you install the Examples in you computer from the CD which is been provided along with this book if you cant find the image you can find in the EaglesGroup Applications Software\logos (folder). If you want to change the image yes it is possible but remember to change the following code: theImage = new Bitmap (eagles.bmp);
850
Now lets see how the above program runs and works In the constructor, we instantiate a Bitmap object and assign it to our Image variable that we declared.
Then, in the OnPaint () method, we draw the image. When we draw the image, we pass a Rectangle as one of the arguments to the DrawImage () method, if the image is not the same size as the rectangle that we pass to DrawImage (), GDI+ automatically resize the image to fit in the specified rectangle. One way to enforce that GDI+ will not resize the image is to pass the size of the image, retrieved from the Width and Height properties, to the DrawImage () method.
Example Try it out Eagles Drawing Ellipse Step by Step Example: in version 2005
1. Create a new Windows application and called as Eagles Drawing Ellipse in the directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. Add the following code as show: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
851
3. Add the declaration of the components variable, add the declaration of theImage as follows: public partial class Form1 : Form { private Image theImage; private Image smallImage; public Form1() { InitializeComponent(); } }
4. In the Form1.cs constructor, we will create smallImage from the Image. When we create it, we specify a rectangle that is half the height the width of theImage. This creates a smaller version of the original image: public Form1() { InitializeComponent(); SetStyle(ControlStyles.Opaque, true); theImage = new Bitmap("C:/eagleslogo1.bmp"); smallImage = new Bitmap(theImage, new Size(theImage.Width / 2, theImage.Height / 2)); }
5. Add the following code to the OnPaint () method: protected override void OnPaint(PaintEventArgs sri) { Graphics g = sri.Graphics; g.FillRectangle(Brushes.White, ClientRectangle); Brush tBrush = new TextureBrush (smallImage , new Rectangle (0, 0, smallImage.Width , smallImage.Height )); g.FillEllipse (tBrush, ClientRectangle ); tBrush.Dispose (); base.OnPaint(sri); }
852
6. And dont forget to add the Dispose () method in the Form1.Designer.cs the code as follows: protected override void Dispose(bool disposing) { if (disposing && (components != null)) { theImage.Dispose(); smallImage.Dispose(); components.Dispose(); } base.Dispose(disposing); }
7. Now run the application and you should see the window like this:
DENOTE: For the image which you are see in the application and in the window above as shown it will automatically load when you install the Examples in you computer from the CD which is been provided along with this book if you cant find the image you can find in the EaglesGroup Applications Software\logos (folder). If you want to change the image yes it is possible but remember to change the following code:
853
Now lets see how the above program runs and works
When we create the TextureBrush, we pass a rectangle to the constructor to specify what part of the image will be used for the brush. In this case, that we will use the entire image. Whatever is drawn using the TextureBrush uses the bitmap instead of a solid color. Most of the code for this example has already been explained in this chapter. The difference is that we call the FillEllipse () method instead of the FillRectangle () method, of the Graphics class, passing our newly created texture brush, and the clientRectangle draws the ellipse in the window: g.FillEllipse (tBrush, ClientRectangle ); Now lets see an example using a Pen from an image using that brush.
Example Try it out Eagles Using Pen Step by Step Example: in version 2005
1. Create a new Windows application named called Eagles UsingPen in the directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. Add the following code as show: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
3. Add the declaration of the components variable, add the declaration of theImage as follows:
public partial class Form1 : Form { private Image theImage; private Image smallImage; public Form1() { InitializeComponent(); } }
854
4. In the Form1.cs constructor, we will create smallImage from the Image. When we create it, we specify a rectangle that is half the height the width of theImage. This creates a smaller version of the original image: public Form1() { InitializeComponent(); SetStyle(ControlStyles.Opaque, true); theImage = new Bitmap("C:/eagleslogo1.bmp"); smallImage = new Bitmap(theImage, new Size(theImage.Width / 2, theImage.Height / 2)); } 5. Add the following code on the OnPaint () method: protected override void OnPaint(PaintEventArgs siddhu) { Graphics g = siddhu.Graphics; g.FillRectangle(Brushes.White, ClientRectangle); Brush tbrush = new TextureBrush(smallImage, new Rectangle(0, 0, smallImage.Width, smallImage.Height)); Pen tPen = new Pen(tbrush, 40); g.DrawRectangle(tPen, 0, 0, ClientRectangle.Width, ClientRectangle.Height); tPen.Dispose(); tbrush.Dispose();
6. Now run the application and you should have the window like this: base.OnPaint(siddhu); }
855
Example Try it out Eagles Using Pen Step by Step Example: in version 2005
1. Creating a new Windows application called new Eagles DrawingText directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. Add the following code as show: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
3. Add the declaration of the components variable; add the declaration of theImage as follows:
public partial class Form1 : Form { private Image theImage; private Image smallImage; public Form1() { InitializeComponent(); } }
4. In the Form1.cs constructor, we will create smallImage from the Image. When we create it, we specify a rectangle that is half the height the width of theImage. This creates a smaller version of the original image: public Form1() { InitializeComponent(); SetStyle(ControlStyles.Opaque, true); theImage = new Bitmap("C:/ eagleslogo2.bmp"); smallImage = new Bitmap(theImage, new Size(theImage.Width / 2, theImage.Height / 2)); }
856
5. Add the following code to the OnPaint () the code as follows: protected override void OnPaint(PaintEventArgs siddhu) { Graphics g = siddhu.Graphics; g.FillRectangle(Brushes.White, ClientRectangle); Brush tbrush = new TextureBrush (smallImage, new Rectangle (0, 0, smallImage .Width , smallImage.Height )); Font trFont = new Font ("Bodoni MT", 32, FontStyle.Bold | FontStyle.Italic ); g.DrawString("Welcome To EaglesGroup Visual C# Tutorial", trFont, tbrush, ClientRectangle); tbrush.Dispose(); trFont.Dispose(); base.OnPaint(siddhu); } 6. When we run this code, it appears as follows:
DENOTE: The Call to the DrawString () method, is similar to previous uses of that method. It takes as arguments the text the font, texture brush, and a bounding rectangle: g.DrawString("Welcome To EaglesGroup Visual C# Tutorial", trFont, tbrush, ClientRectangle);
857
Example Try it out Eagles Using Pen Step by Step Example: in version 2005
1. Create a new Windows application called Eagles DoubleBuffer, and add the following OnPaint () method, which a draws a large number of lines in random colors. protected override void OnPaint(PaintEventArgs sri) { Graphics g = sri.Graphics; Random r = new Random(); g.FillRectangle(Brushes.White, ClientRectangle); for (int x = 0; x < ClientRectangle.Width; x++) { for (int y = 0; y < ClientRectangle.Height; y += 10) { Color c = Color.FromArgb(r.Next(255), r.Next(255), r.Next(255)); using (Pen p = new Pen(c, 1)) { g.DrawLine (p, new Point(0, 0), new Point(x, y)); } } }
base.OnPaint(sri); }
858
2. Add the following code also: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
3. Now run the application, you can see the drawing take place in the window. After all the drawing is completed, window look like this:
DENOTE: Now well add the double buffering if you replace the OnPaint () method with this version, the graphics are drawn all at once, after a second or two for this we created a new Windows application so the old program still you can have in the CD and new one which is going to get changes are in the following directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005\Eagles DoubleBufferering one
859
4. Add the replace code the code as follows: protected override void OnPaint(PaintEventArgs siddhu) { Graphics displayGraphics = siddhu.Graphics; Random r = new Random(); Image i = new Bitmap(ClientRectangle.Width, ClientRectangle.Height); Graphics g = Graphics.FromImage(i); g.FillRectangle(Brushes.White, ClientRectangle); for (int x = 0; x < ClientRectangle.Width; x++) { for (int y = 0; y < ClientRectangle.Height; y += 10) { Color c = Color.FromArgb(r.Next(255), r.Next(255), r.Next(255)); Pen p = new Pen(c, 1); g.DrawLine(p, new Point(0, 0), new Point(x, y)); p.Dispose(); } } displayGraphics.DrawImage(i, ClientRectangle); i.Dispose(); base.OnPaint(siddhu); }
Now lets see how the above program runs and works The part of the code responsible for drawing the lines is straightforward weve seen the DrawLine() method earlier in the chapter. The only real thing of note in this part of the code is the FromArgb () static Color method, which creates a Color struct from the three supplied integer values, corresponding to the red, green and blue parts of the color. In the double buffering code, we create a new image that has the same height and width of the ClientRectangle with the following line: Image i = new Bitmap(ClientRectangle.Width, ClientRectangle.Height); We then get a Graphics objects from the image using the following line: Graphics g = Graphics.FromImage(i);
860
All of the drawing operations are the same as the previous code, except that they now draw into the image instead of directly onto the window. Finally, at the end of the function, we draw the image of the window: displayGraphics.DrawImage(i, ClientRectangle); Because the lines are drawn first to an invisible image, you do have to wait a short while before you see anything.
We have only just touched on the many capabilities of GDI+. There is much more that you can do with it far more than can be achieved in a single chapter. However, to round off this chapter, we will introduce several areas of these advance capabilities.
20.22 Clipping
There are three contexts where clipping is important. First, when the OnPaint () method gets called, in addition to the Graphics object, the event is passed a clipping rectangle. For simple drawing routines, we dont need to pay much attention to this clipping rectangle, but if we have a very elaborate drawing routine that takes a lot of time, we can reduce this drawing time by testing against this clipping rectangle before we draw. We know the bounding rectangle of whatever graphic or figure that we need to draw. If this bounding rectangle does not interest with the clipping rectangle, then we can skip the drawing operations. The following screenshot shows one window containing a text and pictures that is partially obscured by another window.
861
After the calculator has been closed, and after the Windows Operating System has brawn the border of the Window, the chart window would look like this:
862
At this point, the OnPaint () method for the bar chart window would now be called, with the clipping rectangle set to the area exposed by the closed window, shown above in black. The bar chart would now need to draw the portions of its window that were previously underneath the overlaying window. It would not need to redraw, the text even if the OnPaint () method tried to draw into the window in an area, other than the exposed area, it could not. Any drawing that it did would be ignored. The bar chart window knows the bounding rectangle for the cars bar, and can determine if this rectangle intersects with the exposed portion of the window. Having determined that it does not interest, the drawing routine will not redraw the part of the display covering the text. Sometimes when drawing, if we need to draw only part of a figure or graphics, it is more convenient to draw the entire figure, and clip the drawing to just what we want to see. We may have an image, and want to draw just a portion of that image. Rather than create a new image that is just a portion of the original image, we can set the clipping rectangle, and then draw the image such as just the portion that we want to see shows through the clipping area. When creating a marquee, this is the technique that we would use. By successively changing where we draw the text, and at the same time setting a clipping region, we can create the effect of horizontal moving text. Finally, there is a technique where we can create a view port into a larger graphic. The user can move this view port around, perhaps by dragging the mouse on the graphics, or manipulating scroll bars. The view port also may be moved programmatically based on other actions that the user takes. In this case, setting a clipping region and drawing such that only what we want to see shows through is a good technique.
863
See the Clip property of the Graphics class for more information.
DENOTE: Its important to realize that you cant draw graphics in a form its Load event, because the forms drawing surface hasnt been created yet. You must use the Paint event, instead of the Load event. For example, we are going to create an example named Eagles PainterMouse in this section that lets you select what graphics you want to figure to draw and then lets you draw that figure with the mouse.
864
values 128, 128, 128; bright blue has the red, green, blue color with the values of the 0, 0, 255), and so on. Color c = Color.FromArgb (255, 0, 0); Pen RedPen = new Pen (c); g.DrawLine (RedPen, point1, point2);
The color structure also comes with dozens of built in colors, which are the same as those used in the Pens and Brushes classes. You can find these colors listed in the following table: DENOTE: You can recover red, green, and blue values for a color using the Color structures R, G, and B members (these members are read only).
865
The following Tables Shows the Colors of the Pens and Brushes Classes Alice Blue Aquamarine Black Blue Violet Cadet Blue Coral Cyan Dark Goldenrod Dark Orchid Dark Sea Green Dark Turquoise Deep Sky Blue Fire Brick Fuchsia Gold Green HotPink Ivory LavenderBlush LightBlue LightGoldenrodYellow LightPink LightSkyBlue LightYellow Linen MediumAquamarine MediumPurpule MediumSpringGreen MintCream NavajoWhite Olive OrangeRed PaleGreen PapayaWhip Red SeaSheel SkyBlue Teal Transparent Wheat Yellow Antique White Azure Blanched Almond Brown Chartreuse Cornflower Blue Dark Blue Dark Olive-Green Dark Red Dark SalateBlue Dark Violet Dim Gray Floral White Gainsboro Goldenrod Green Yellow IndianRed Khaki LawnGreen LightCoral LightGray LightSalmon LightSlateGray Lime Magenta MediumBlue MediumSeaGreen MediumTurquois MistyRose Navy oliveDrab Orchid PaleTurquoise PeachPuff RosyBrown Sienna SteelBlue Thistle Turquoise White YellowGreen Aqua Beige Blue Burly Wood Chocolate Corns Silk Dark Cyan Dark Orange Dark Salmon Dark Slate Gray Deep Pink Dodger Blue Forest Green Ghost White Gray Honeydew Indigo Lavender LemonChiffon LightCyan LightGreen LightSeaGreen LightSteelBlue LimeGreen Naroon MediumOrchid MediumLightBlue MediumLightBlue Moccasin OldLace Orange PaleGoldenrod PaleVioletRed Purpule SeaGreen Silver Tan Tomato Violet WhiteSmoke
866
20.25 System.Drawing.Drawing2D
The classes in this namespace provide advanced two dimensional and vector graphics functionality. We could use these classes to build a sophisticated drawing image processing applications. Vector Graphics is technique where the programmer doesnt address pixels at all. Rather, the programmer record multiple vectors indicating such Operations as draw fomr one point to another, draw a rectangle at a certain locations, etc. Then the Developer can apply scaling, rotation, and other transformations. Having applied the transformations, all the operations are rendered at once to the window. This namespace include the Matrix class, which defines geometric transforms. Using this class, we can do transforms on the drawing operations. For instance, using the Matrix class, we can draw an oval that is at a slant. Also included in this namespace is the GraphicsPath class, which we have already touched on. Using this class, we can define a complex path and draw the entire path at once. 20.26 System.Drawing.Imaging The classes in this namespace provide advanced imaging support, such as support for metafile. A metafile describes a sequence of graphics operations that can be recorded and later played back, and there are classes within the System.Drawing.Imaging namespace that allows us to extend the GDI+ to support other image formats.
DENOTE: In this following example program you can load the image as you wish form your computer, instead of the image which we used to give in the form for change you can try to load any kind of the image
To handle images by suing the Graphics Class, you can use methods like DrawImage, which draws images where you want them. Now that we know more about the Graphics Class, well take a look at that example. There are many overload forms of DrawImage. With the one we are using here, you pass the Image object to work with the destination rectangle to drawn in; the source rectangle to copy pixels from and the graphics units which are pixels. For this scrolling we can use the scroll the image, you use the scrollbar position and simply redraw the image.
867
Example Try it out Eagles AdvanceImage Step by Step Example: in version 2005
1. Creating a new Windows application called new Eagles AdvanceImage directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. Add the following using directive for the System.Drawing.Drawing2D to the top of the code: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
3. Now go to the Form1.cs[Design] and drag and drop a picture box and name it as picbox
868
4. And add HScrollBar and VScrollBar and make a design as the picture below looks :
5. Now add a button and enter the Enter the text in the Design Name as btnload and in the Text property Name it as Load as shown in the below picture
869
6. Now here come the tricky part the coding please enter the following code into the body of the Form1.cs. private void ShowScrollBars() { vScrollBar1.Visible = true; hScrollBar1.Visible = true; if (picbox.Height > picbox.Image.Height) { vScrollBar1.Visible = false; } if (picbox.Width > picbox.Image.Width) { hScrollBar1.Visible = false; } }
7. After entering the above mentioned code into the Form1.cs body and enter the following code again: public void ScrollBars_Scroll(object sender, ScrollEventArgs siddhu) { Graphics graphics = picbox.CreateGraphics(); graphics.DrawImage(picbox.Image, new Rectangle (0, 0, picbox.Width - hScrollBar1.Height, picbox.Height vScrollBar1.Width), new Rectangle(hScrollBar1.Value, vScrollBar1.Value, picbox.Width - hScrollBar1.Height, picbox.Height - vScrollBar1.Width), GraphicsUnit.Pixel); }
870
8. Now go to the Form1.cs[Design] and go to the toolbox and drag and drop the OpenFileDialog and name it as opnfld as shown below and go the filter and change it as shown in the picture below:
9.
Now Double click the Load button and enter the following code: private void btnload_Click(object sender, EventArgs e) { if (opnfld.ShowDialog() != DialogResult.Cancel) { picbox.Image = Image.FromFile(opnfld.FileName); hScrollBar1.Maximum = picbox.Image.Width - picbox.Width; vScrollBar1.Maximum = picbox.Image.Height - picbox.Height; ShowScrollBars(); } }
871
10. After that the most important thing you need to do now go to the Fomr1.Designer.cs file and look for the + symbols which contains the Windows Form Designer code which look like this and click the + and then look for the vScrollbar1 and hScrollbar1 and add the following code and do it in the same way which has been shown in the following method:
// // hScrollBar1 // this.hScrollBar1.Location = new System.Drawing.Point(85, 216); this.hScrollBar1.Name = "hScrollBar1"; this.hScrollBar1.Size = new System.Drawing.Size(250, 17); this.hScrollBar1.TabIndex = 1; this.hScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(ScrollBars_Scroll); // // vScrollBar1 // this.vScrollBar1.Location = new System.Drawing.Point(335, 50); this.vScrollBar1.Name = "vScrollBar1"; this.vScrollBar1.Size = new System.Drawing.Size(16, 183); this.vScrollBar1.TabIndex = 2; this.vScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(ScrollBars_Scroll);
872
11. Now run the Application and you should see a window like this:
12. After that you click the Load button and load the image as you like and try to scroll the both the bars in the picture box it should scroll if the picture is bigger in size. For the example in this below picture we had loaded a picture which is bigger in size
873
Now lets see how the above program runs and works
The code which makes the scroll bar to scroll according to the height and width of the image which has been loaded in the Picture Box, lets look at the following code: private void ShowScrollBars() { vScrollBar1.Visible = true; hScrollBar1.Visible = true; if (picbox.Height > picbox.Image.Height) { vScrollBar1.Visible = false; } if (picbox.Width > picbox.Image.Width) { hScrollBar1.Visible = false; } } The above code if you take a look you will see that if the image height is lesser than the picture box then the Vertical Scroll Bar will be hiding, and the same thing goes to the Horizontal Scroll Bar.
And for the loading the picture form the file, we need to have a Open File Dialog box which can make you to select the picture that which can be located easily form the user to import the picture to the picture box. private void btnload_Click(object sender, EventArgs e) { if (opnfld .ShowDialog() != DialogResult.Cancel) { picbox.Image = Image.FromFile(opnfld.FileName); hScrollBar1.Maximum = picbox.Image.Width - picbox.Width; vScrollBar1.Maximum = picbox.Image.Height - picbox.Height; ShowScrollBars(); } } There are many features of the Dialog Class, but we only use a part for this program by just importing the picture form a file, or a folder to the picture box.
874
And more over we need to have a scroll event which make the user to easily scroll the bars when the picture is bigger in the width, so how that is possible let look the code: public void ScrollBars_Scroll(object sender, ScrollEventArgs se) { Graphics graphics = picbox.CreateGraphics(); graphics.DrawImage(picbox.Image, new Rectangle(0, 0, picbox.Width - hScrollBar1.Height, picbox.Height - vScrollBar1.Width), new Rectangle(hScrollBar1.Value, vScrollBar1.Value, picbox.Width - hScrollBar1.Height, picbox.Height - vScrollBar1.Width), GraphicsUnit.Pixel); } The above code you can see we are declaring the scrollbars event so that the user can easily scroll the picture either in vertical or horizontal.
Now we are going to create a new kind of window which is more complicated and more useful and which is almost like the Microsoft paint. For creating the window just follow the following steps and methods
Example Try it out Eagles PaintSoftware Step by Step Example: in version 2005
1. Creating a new Windows application called new Eagles AdvanceImage directory C:\EaglesVisualCSharp\Chapter 20\Graphics Path\Version 2005 2. Add the following using directive for the System.Drawing.Drawing2D to the top of the code: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
using System.Drawing.Drawing2D;
875
3. Add the following code in the IntializeComponent() method like this: public Form1() { InitializeComponent(); this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint); this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseUp); this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove); this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown); this.tlstrip.ItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.tlstrip_ItemC licked); } 4. Add the following code after the InitializeComponent() methods which should be like this: public Form1() { InitializeComponent(); } private Graphics g; private Point up; private Point down; private Rectangle r; private Tools Tool; private Point[] Points; private int NumberPoints = 0;
876
5. Now we need to add the enumeration names Tools which will help to hold the values, and the please add the following code in the Fomr1.cs body like this: enum Tools { Rectangle, Ellipse, Line, Draw } 6. Now go back to the Form1.cs [Design] view and open the toolbox and drag and drop the ToolStrip. And name the ToolStrip as tlstrip and make the Window like the following DENOTE: For more information and details for the ToolStrip and Context Menu we will be given in brief details in the Next chapter which is named as Advance Controls used in the Visual Studio.NET
877
7. After make the design right click the tlstrip and the go for the Properties and look for the Items, click the ellipse () symbol and you will Items Collection Editor. In that there is a list box which you see a lot of available tools like button label and so on, but we will look more details on the ToolStrip on the Next chapter, now select the Button form the List Box, but by default the button is already selected, if not select the Button and click the add button for four times and you can see the Buttons had been added to below the tlstrip like one by one as shown in the picture below:
878
8. Now just click the toolStripButton1 and you can see in the left side a lot of available tools but we now going to see only some of the them, Look for the Text Property and Change the name form toolStripButton1 to Rectangle and in the Design Name toolRectangle, follow the same thing for the reaming Buttons but the name is has to change as for toolStripButton2 = Ellipse, toolStripButton3 = Line, toolStripButton4 = Draw. After that click OK button.
9. Now look for the Property Name Display Type in the change the type to Text by default it has been selected to image but you need to change it to the Text as shown in the below picture:
879
10. Now go to the Form1.cs[Design] and you should see some thing like this in the Window:
880
11. Now we are going for the coding part Enter the following code into the body of the Fomr1.cs: private void tlstrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e) { if (tlstrip.Items[0] == e.ClickedItem) { Tool = Tools.Rectangle; } if (tlstrip.Items[1] == e.ClickedItem) { Tool = Tools.Ellipse; } if (tlstrip.Items[2] == e.ClickedItem) { Tool = Tools.Line; } if (tlstrip.Items[3] == e.ClickedItem) { Tool = Tools.Draw; } } private void Form1_Paint(object sender, PaintEventArgs e) { switch (Tool) { case Tools.Rectangle: g.DrawRectangle(Pens.BlueViolet, r); break; case Tools.Ellipse: g.DrawEllipse(Pens.BlueViolet, r); break; case Tools.Line: g.DrawLine(Pens.BlueViolet, up, down); break; case Tools.Draw: if (NumberPoints >= 2) { g.DrawLines(Pens.BlueViolet, Points); } break; } }
All Rights Reserved To EaglesGroup
881
private void Form1_MouseDown(object sender, MouseEventArgs e) { down = new Point(e.X, e.Y); } private void Form1_MouseMove(object sender, MouseEventArgs e) { if (Tool == Tools.Draw & e.Button == System.Windows.Forms.MouseButtons.Left) { Point p = new Point(e.X, e.Y); Array.Resize(ref Points, NumberPoints + 1); Points[NumberPoints] = p; NumberPoints += 1; if (NumberPoints >= 2) { g.DrawLine(Pens.BlueViolet, down, p); } down = p; } } private void Form1_MouseUp(object sender, MouseEventArgs e) { up = new Point(e.X, e.Y); r = new Rectangle(Math.Min(up.X, down.X), Math.Min(up.Y, down.Y), Math.Abs(up.X - down.X), Math.Abs(up.Y - down.Y)); switch (Tool) { case Tools.Rectangle: g.DrawRectangle(Pens.BlueViolet, r); break; case Tools.Ellipse: g.DrawEllipse(Pens.BlueViolet, r); break; case Tools.Line: g.DrawLine(Pens.BlueViolet, up, down); break; } }
882
12. Now go to the Form1.cs[Design] and double click the form which will guide to the Form1_Load in that enter the following code: private void Form1_Load(object sender, EventArgs e) { g = CreateGraphics(); } 13. Now run the application and you should have window like this:
Now lets see how the above code works: When you get a Graphics object for the entire from this way, that object corresponds to whose from, not just the client area. So the drawing origin is the upper left corner of the whole form above the Title bar. When a Graphics object is passed to you in the Paint event handler, that objects origin is at upper left of the client area that is , the area below the Title bar, Menu bar, and toolbars, if any . private void Form1_Load(object sender, EventArgs e) { g = CreateGraphics(); }
883
Now we can draw any graphic by using the Graphics object as needed. We also define an enumeration named Tools that holds these values, corresponding to the buttons in the toolbar: enum Tools { Rectangle, Ellipse, Line, Draw }
private void tlstrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e) { if (tlstrip.Items[0] == e.ClickedItem) { Tool = Tools.Rectangle; } if (tlstrip.Items[1] == e.ClickedItem) { Tool = Tools.Ellipse; } if (tlstrip.Items[2] == e.ClickedItem) { Tool = Tools.Line; } if (tlstrip.Items[3] == e.ClickedItem) { Tool = Tools.Draw; } }
The above code is used for, when the user clicks a toolbar button, we can assign a variable named Tool, a value from this enumeration, to specify what drawing tool line, and rectangle, etc we are using it currently. We record the point at which the mouse button went down in a Point variable named down, like this: private void Form1_MouseDown(object sender, MouseEventArgs e) { down = new Point(e.X, e.Y); }
884
The user now moves the mouse to the opposite coroner of the window defining rectangle and release the mouse button. We can now create a rectangle of the Rectangle class after finding the figures upper left corner, width, and height. Then all we needed to do is to check which kind of figure we are drawing predefined blue violet pen, but note that you can create pens of any color. private void Form1_MouseUp(object sender, MouseEventArgs e) { up = new Point(e.X, e.Y); r = new Rectangle(Math.Min(up.X, down.X), Math.Min(up.Y, down.Y), Math.Abs(up.X - down.X), Math.Abs(up.Y - down.Y)); switch (Tool) { case Tools.Rectangle: g.DrawRectangle(Pens.BlueViolet, r); break; case Tools.Ellipse: g.DrawEllipse(Pens.BlueViolet, r); break; case Tools.Line: g.DrawLine(Pens.BlueViolet, up, down); break; } }
The option Draw menu lets you to draw free hand with the mouse. To implement that, well add code to the MouseMove event handler and use the Graphics class DrawLine method. You pass this method a pair of points to connect with lines, so all we need to do is to store the last points passed to us in MouseMove, and pass it along with the new Point that has been passed to us in the current MouseMove to the DrawLine method. A Mouse Move event is not generated for every pixel the mouse passes over, rather only so many times a second. All we need to do is to connect the dots with short lines using DrawLine. So if you thing about it, what seems like freehand browsing is actually a number of very short straight lines drawn one after another in different directions. Heres how the code looks like to draw free one after another in different directions. Heres how the code looks like to draw free hand with the mouse. DENOTE: That we dont invoke the DrawLine method unless there are at least two points stored in the Points array.
885
private void Form1_MouseMove(object sender, MouseEventArgs e) { if (Tool == Tools.Draw & e.Button == System.Windows.Forms.MouseButtons.Left) { Point p = new Point(e.X, e.Y); Array.Resize(ref Points, NumberPoints + 1); Points[NumberPoints] = p; NumberPoints += 1; if (NumberPoints >= 2) { g.DrawLine(Pens.BlueViolet, down, p); } down = p; } } While drawing, we also keep storing these points in an array named Points. We use this array in Paint function to redraw all the points should the form require to be redraw. We do the painting on the Paint event by DrawLines function, which is basically a plural function of DrawLine. While DrawLine takes only a pair of points and connects them, DrawLines takes a whole array and points, and connects all the points in the array. Note that since DrawLines gets the number of lines to draw from the length of the array passed to it, well need to re dimension this array every time we add a new point to it. The code we need to write in for the Paint event to reenact a drawing performance: private void Form1_Paint(object sender, PaintEventArgs e) { switch (Tool) { case Tools.Draw: if (NumberPoints >= 2) { g.DrawLines(Pens.BlueViolet, Points); } break; } }
886
But the above code will only help you to draw only but when you minimize the window, or open any other windows and then maximize the paint window you will not see the drawing which you had drawn before, for the reappear for the drawing we call it as Repainting Window The repainting windows when you draw graphics in a form, then minimize, and then restore the form, or cover and then uncover it, you lose all the graphics and so you need to redraw the graphics as well, but in VB6 we dont need to redraw the graphics in such a situation, where the forms supported the AutoRedraw property, but now you need to redraw because that property no longer exists. You can do that in the forms Paint event handler, which is called when the form need to be drawn or painted. We can redraw the most recent graphics in the Painter example this way, by using the Paint event.
private void Form1_Paint(object sender, PaintEventArgs e) { switch (Tool) { case Tools.Rectangle: g.DrawRectangle(Pens.BlueViolet, r); break; case Tools.Ellipse: g.DrawEllipse(Pens.BlueViolet, r); break; case Tools.Line: g.DrawLine(Pens.BlueViolet, up, down); break; case Tools.Draw: if (NumberPoints >= 2) { g.DrawLines(Pens.BlueViolet, Points); } break; } }
By using the above mentioned code now you can minimize and then restore the Painter, the most recent figures will be reappears.
887
Summary
In this chapter, we covered some of the classes in the System.Drawing namespace. We saw how the Graphics class encapsulates a drawing surface. We review the mechanics of drawing, where the OnPaint event is called whenever our windows need to be redrawn.
We explored color and coordinate systems, image handling, drawind2D. We covered the Point, Size, and Rectangle structures that we use to specify positions and sizes on our drawing surface. Next, we saw some example of the drawing lines, shapes, text, and images.
Overall, the topics that we covered: Graphics Handling 2D Vector Graphics Imagining Typography Overview of Graphical Drawing The Graphics Class. Disposing of Objects Coordinate System Point Size Rectangle Graphics Paths Regions Colors Drawing Line Using the Pen Class Drawing Shapes using the Brush Class Drawing Text using the Font Class Drawing Using Images Drawing with a Texture Brush Double Buffering Advance Capabilities of GDI+ Clipping Drawing 2D Figures with Graphics Methods Specifying Drawing Color System.Drawing.Drawing2D System.Drawing.Imaging
888
Chapter 21
889
Windows Communication Foundation (WCF) Windows Presentation Foundation (WPF) Windows Workflow Foundation (WF) Windows CardSpace (WCS)
This framework supports Windows Vista, Windows XP, and Windows 2003 and 2008 server. WCF is introduced to overcome the problem of communication with applications that are based on other different platforms. WCS also address the problem of digital identities and phishing and is introduced to overcome the problem of user friendly interface that supports 2D and 3D graphics. It also overcomes the problem of Process Oriented architecture. All these four foundations provide different technologies in a single framework. This helps the developers by increasing their productivity. Now that you are aware of what .NET Framework 3.0 is and why it has been introduced, in the further topics, well discuss. .NET Framework 3.0 its four newly added foundations, such as WCF and WPF in detail.
890
891
workflow technology for all the windows based applications, such as Microsoft Office 2007 and Windows Share Point Services.
WF also addresses the problem of making changes in the running workflows. There are two types of workflow Sequential workflow and Stat machine workflow. WF includes for both the workflows. Sequential workflow is the one that performs the execution of the activities in a chronological order. It contains classes, loops and other control structures. This workflow is used by software based process and is easy to understand and develop. State machine workflow is the one that execute activities at a particular time. This time is based on the event occurred and the state of the machine. This workflow is used when you are not aware of execution time. For example, you have created an application and somebody calls the cancel event which is less predictable and you are not ware of the exact execution time, but you are interacting with people at same time. This interaction demands for state machine workflow.
892
21.5 Components of WF
Workflow which is basically a group of activates. These activities are classes that can be created in code. WF provides components, such ad Workflow Designer, which is a GUI for developing workflows. You can create the workflow activities using Base Activity Library (BAL), which comes with WF. BAL provides some of the common activates which help in creating custom activities easily and fast. Some of the common activities included in BAL are as follows: IF Else It is used for execution the multiple activities based on the conditions met. While It is used for execution the same activity multiple times till the time condition is true. Sequence It is used for execution activities on a particular time in a predefined order. Parallel It is used for execution two or more activity groups in parallel. Code It is used for executing a code snippet. Listen It is used for executing the activities based on the event received or occurred. InvokeWebService It is used for invoking a Web Service. State it is used in State machine workflow for representing a state. EvenDriven it is used to define a transition containing one or more activities at a time of particular event received. Policy It is used for executing the business rules which come with WF. WF also provides a runtime engine for executing the defined workflow. It also manages the execution of workflow. For running a runtime engine, WF provides runtime. As the following picture show the components of the Workflow (WF).
893
In the above picture, you can see that Workflow, Runtime engine, and services are part of host process which can be console or a windows application. And the picture also shows other components of WF such as BAL, and workflow designer.
894
issues which arise at the time of application communication. You can see the architecture of WCF as in the following picture:
The Above picture shows the different phase of WFC. These phases are as follows:
21.7 Contracts
Contracts phase gives you information about different features of the message system. Message system is the one which involves sending and receiving the messages from one end to another. In contracts there are four components, which are as follows: Data Contract It is used for describing message parameters. These parameters are XML based and used for creating a message that will be formed or used by the service. This allows any system to process the message.
895
Message Contract It is used for defining specific part of the message using the SOAP. This allows the message to be communicated in interoperable communication Service Contract It is used to indicate the signature which is distributed as an interface. Policy and Binding It is used to specify the transport media, such as HTTP, or TCP. It also includes some of the security requirement, which is a must for communication.
21.9 Messaging
Messaging phase gives information about the different channels, which are required at the time of processing a message. These channels help in message processing. This phase deals with the message content that need to be communicated. It uses transport and protocol channels for communicating the message body. Transport channel is used for reading and writing message. In addition, sometimes, there is a need to convert the message to an XML format and that too is performed by the transport channel. Protocols channel includes the protocols, which are used for processing a message. Some of the protocols are WS- Security as WS Reliability.
DENOTE: WS- Security is a protocol used for securing the message at the messaging phase. WS- Reliability is a protocol which gives assurance of message delivery.
896
897
898
When the user access the web site the Microsoft reminds the user to aware of the Phishing which will be like the following picture:
Now, the user needs to remember only the card instead of multiple usernames and password. Technically speaking, all the ideates created on a card need some provider for converting an identity into card. For this conversion, some organizations provide their own identity provides to create a card based on same. Even WCS comes with its own self issued identify providers which are accepted by web sites for validating user using the Card. These cards avoid the use of password. Due to this identity through a card, Phishers are unable to steal the password. Despite everything, if Phishers succeed in attracting the readers, they will steal some personal information. To avoid this, a new certificate is introduced knows as high assurance certificate. This certificate the original and Phishers based web sites. WCS is based on the identity metasystem. This system allows you to use the different digital identities across different platforms. There are two types of cards available, which are as follows: Personal Card - These Cards are based on the self issued identity providers. Managed Cards These Cards are based on identify providers provided by vendors other than Microsoft .
899
900
WPF works on Extensible Application Markup Language (XAML). This language is used by designers for creating a user interface. Even Microsoft comes with Expression Studio that uses XAML for developing User Interface for any web windows based application. In the above picture there are seven items. These items form the WPF architecture. This architecture is mainly represented the managed code. The CLR is used to handle tasks, such as memory management and error handling. CLR increases the productivity and makes the application robust. Presentation Framework, Presentation Core, and milcore are the important parts of the WPF architecture. Both Presentation Framework and Presentation Core are developed using managed code. On the other hand, milcore is developed using the unmanaged code. This is done so that milcore can communicate with Direct X easily. As DirectX is base on unmanaged code, the question arise, how does the unmanaged and managed code communicate with each other. This is done using the following class hierarchy: System.Threding.DispathcherObject It is used for managing the threads and concurrency System.Windows.DependencyObject It is used for properties to a user object, such as buttons. System.Windows.Media.Visual It is used for drawing the tree of the visual objects. These objects contain drawing instructions for managing the data. This class is the main entry point for communication between managed and unmanaged code. System.Windows.UIElemet This class is used for defining the layouts and events for the User Interface System.Windows.FrameworkElement It is used for providing policies and customization facility at the user end. This is also the enter point for animation. System.Windows.Controls.Control It is used for managing the controls used on the User interface. WFC provides the following user interface functionalities other than the basic functions. Documents WPF provides support for XPS and flow documents. XPS and flow documents. XPS are supported by XAML FixedDocument tag. It also used the FlowDocument tag for displaying the Flow Documents. XPS documents are the documents which are based on XML paper specification used by Windows Vista. The flow documents are those, which are used for optimizing the content according to the runtime variables, such as windows size and device resolution. Graphics WPF provides supports for 2D and 3D graphics. It provides brushes, shapes, and pens for drawing 2D graphics. It also provides XAML based elements for defining 3D graphics, which requiring lighting and camera position. WPF dont rely on GDI + for 3D graphics.
901
Images WFC uses the XAMls images tag for providing support for different types of images formats, such as jpeg, gif, png, and others. It uses Windows Imaging Component to provide software that displays and stores images. Media WPF uses the Media Element tag of XAML for displaying video and audio formats. These formats include WMV, AVI, and MPEG file types. You can use this tag with other XAML tags for displaying 3D cubes, etc. Animation WPF provides support for animation. You can use this support for creating storyboards, including timeline animations. Data Binding WPF provides support for data binding which is automatically performed in any WPF application. It also provides sorting and filtering of data.
Summary
In this chapter we had gone through about the .NET Framework 3.0 and the features of the .NET 3.0 such as
Windows Communication Foundation (WCF) Windows Presentation Foundation (WPF) Windows WorkFlow (WF) Windows CardSpace (WCS)
902
Develop ASP Web application s and XML Web services Compile code related to Microsoft Windows Message Queuing (MSMQ) Debug code on remote computers Use source code control to version stored procedures
Not supported
Visual Studio Remote Debugger Visual Studio 6.0 Stored Procedure Versioning Visual SourceSafe
Visual Studio Remote Debugger Visual Studio 6.0 Stored Procedure Versioning Visual SourceSafe
903
Microsoft Microsoft SQL Server SQL Server Windows NT 4.0 supports only the installation of Visual Studio Remote Debugger and Visual Studio Analyzer Client. You cannot install Visual Basic, Visual C++, Visual C#, or Visual J# on Windows NT 4.0. For information on the hardware requirements for other products that are included in some editions, read their associated read me files.
22. 2To find out if your drive uses a FAT16 or FAT32 file system
On the Start menu, and choose My Computer. Right-click the drive you intend to check and select Properties. On the General tab, the File system label indicates what file system the drive uses. Once you have determined whether or not you have a FAT file system, use the table below to determine which procedures you need to complete. File System NTFS file system FAT16 or FAT32 file system Should Do Install IIS Repair .NET Framework Install IIS Manually configure FPSE Repair .NET Framework
904
1. For Windows 2000 users, on the Start menu, choose Settings and then choose Control Panel. For Windows XP and later, on the Start menu, choose Control Panel. 2. In Control Panel, choose Add/Remove Programs and then choose Add/Remove Windows Components. 3. In the Windows Components Wizard, select Internet Information Services (IIS) from the Components list. 4. Click Next to begin installation. 5. After installation is complete, return to Add/Remove Programs 6. Select the Visual Studio .NET product you have installed, such as Visual Studio .NET Enterprise or Visual Basic .NET, and then choose Change. 7. Re-install the Visual Studio .NET product.
905
1. On the Start menu, choose Control Panel, and then select the Performance and Maintenance category. 2. Select Administrative Tools, and then select Computer Management. 3. In the Computer Management dialog box, expand the Services and Applications node, and then expand the Internet Information Services node. 4. Expand the Web sites node. 5. Right-click Default Web Site, choose All Tasks, and then choose Configure Server Extensions.
906
DENOTE: If the Configure Server Extensions menu command is missing, FrontPage 2000 Server Extensions are already installed. 6. 7. 8. 9. Choose Next on the first page of the Server Extensions Configuration Wizard. Choose Yes in the Warning dialog box. Choose No for configuring the mail server settings, then choose Next. Choose Finish.
907
C# Keywords
908
C# Keywords abstract as
base bool break byte case catch Char Checked Class Const
A class modifier that specifies that the class must be derived from to be instantiated. A binary-operator type that casts the left operand to the type specified by the right operand, and that returns null rather than throwing an exception if the cast fails A variable with the same meaning as this, except it accesses a base class implementation of a member A logical data type that can be true or
false
Delegate
A jump statement that exits a loop or switch statement block. A one-byte unsigned integral data type A selection statement that defines a particular choice in a switch statement The part of a try statement that catches exceptions of a specific type defined in the catch clause. A two-byte Unicode character data type A statement or operator that enforces arithmetic bounds checking on an expression or statement block An extendable reference type that combines data and functionality into one unit A modifier for a local variable or field declaration that indicates the value is a constant. A const is evaluated at compile time and can only be a predefined type A jump statement that skips the remaining statements in a statement block and continues to the next iteration in a loop A 16-byte precise decimal datatype A marker in a switch statement specifying the action to take when no case statements match the switch expression A type for defining a method signature so that delegate instances can hold and invoke a method or list of methods that
All Rights Reserved To EaglesGroup
909
Do Double Else Enum Event Explicit Extern False Finally Fixed Float For
match its signature A loop statement to iterate a statement block until an expression at the end of the loop evaluates to false An eight-byte floating-point datatype A conditional statement that defines the action to take when a preceding if expression evaluates to false A value type that defines a group of named numeric constants A member modifier for a delegate field or property that indicates only the += and -= methods of the delegate can be accessed An operator that defines an explicit conversion A method modifier that indicates the method is implemented with unmanaged code. A Boolean literal The part of a try statement that is always executed when control leaves the scope of the try block. A statement to pin down a reference type so that the garbage collector won't move it during pointer arithmetic operations. A four-byte floating-point data type. A loop statement that combines an initialization statement, stopping condition, and iterative statement into one statement. A loop statement that iterates over collections that implement IEnumerable. The name of the accessor that returns the value of a property. A jump statement that jumps to a label within the same method and same scope as the jump point. A conditional statement that executes its statement block if its expression evaluates to true An operator that defines an implicit conversion. The operator between a type and an IEnumerable in a foreach statement.
910
Int interface
A four-byte signed integral datatype A contract that specifies the members a class or struct can implement to receive generic services for that type. An access modifier that indicates a type or type member is accessible only to other types in the same assembly A relational operator that evaluates to true if the left operand's type matches, is derived from, or implements the type specified by the right operand A statement that acquires a lock on a reference-type object to help multiple threads cooperate. An eight-byte signed integral datatype. Maps a set of types to a common name. An operator that calls a constructor on a type, allocating a new object on the heap if the type is a reference type, or initializing the object if the type is a value type. The keyword is overloaded to hide an inherited member. A reference-type literal that indicates no object is referenced. The type all other types derive from. A method modifier that overloads operators. A parameter modifier that specifies the parameter is passed by reference and must be assigned by the method being called A method modifier that indicates that a method of a class overrides a virtual method of a class or interface A parameter modifier that specifies that the last parameter of a method can accept multiple parameters of the same type An access modifier that indicates that only the containing type can access the member An access modifier that indicates that only the containing type or derived types can access the member.
internal
is
911
Public Readonly
Ref
Return Sbyte Sealed Set Short Sizeof Stackalloc Static String Struct Switch This Throw True Try Typeof
An access modifier that indicates that a type or type member is accessible to all other types A field modifier specifying that a field can be assigned only once, in either its declaration or its containing type's constructor A parameter modifier that specifies that the parameter is passed by reference and is assigned before being passed to the method A jump statement that exits a method, specifying a return value when the method is non-void A one-byte signed integral datatype A class modifier that indicates a class cannot be derived from The name of the accessor that sets the value of a property A two-byte signed integral datatype An operator that returns the size, in bytes, of a struct An operator that returns a pointer to a specified number of value types allocated on the stack. A type member modifier that indicates that the member applies to the type rather than an instance of the type A predefined reference type that represents an immutable sequence of Unicode characters A value type that combines data and functionality in one unit A selection statement that allows a selection of choices to be made based on the value of a predefined type A variable that references the current instance of a class or struct A jump statement that throws an exception when an abnormal condition has occurred A Boolean literal A statement that provides a way to handle an exception or a premature exit in a statement block An operator that returns the type of an
912
object as a System.Type object A four-byte unsigned integral data type An eight-byte unsigned integral data type
A statement or operator that prevents arithmetic bounds from checking on an expression A method modifier or statement that permits pointer arithmetic to be performed within a particular block A two-byte unsigned integral data type Specifies that types in a particular namespace can be referred to without requiring their fully qualified type names. The using statement defines a scope. At the end of the scope, the object is disposed The name of the implicit variable set by the set accessor of a property A class-method modifier that indicates that a method can be overridden by a derived class A keyword used in place of a type, for methods that don't have a return value Indicates that a field may be modified by the operating system or another thread A loop statement to iterate a statement block until an expression at the start of each iteration evaluates to false
913
914